RFC 914

Thinwire protocol for connecting personal computers to the Internet

๐Ÿ“… published September 1984, from ietf

A Thinwire Protocol for connecting personal computers to the INTERNET โœจ

Okay bestie, let's dive into RFC 914 ๐ŸŽ€ It came out in September 1984 and was written by David J. Farber, Gary S. Delp, and Thomas M. Conte, all from the University of Delaware. It's part of the Network Working Group series. The original doesn't list a category, and it doesn't say it obsoletes or updates anything, so I'm not adding that ๐Ÿ’…

Status of This Memo ๐ŸŒธ

This doc is basically a discussion starter ๐Ÿ—ฃ๏ธ It looks at the annoying problems of connecting low speed links in the ARPA-Internet to personal computers, plus some ways to fix them. None of the proposed solutions are meant to be standards for the ARPA-Internet, no cap. The hope is that everyone reaches a general consensus first, and then standards can come later. Distribution of this memo is unlimited ๐Ÿฆ‹

What is the Problem Anyway ? ๐Ÿค”

Okay so once we start hooking workstations and personal computers up to the INTERNET, the cost and speed tradeoffs totally change ๐Ÿ˜ญ That made the team rethink how they balance protocol design against hardware design. With a decent amount of computing power now available in the $3--10K range, it's totally doable to put computers right where they're needed, like in buildings, in our homes, and other places far from the existing high speed connections ๐Ÿ 

The catch is that dedicated 56k baud lines are expensive, hard to get, and take forever to install. High speed LAN's aren't an option for this either ๐Ÿ’€ Those two facts mean that the everyday 1200 / 2400 baud phone modems, running over dialed or leased telephone lines, are going to be a big part of the connection plan in the near future ๐Ÿ“ž This paper looks at the problems and possibilities of using a "thin" (less than 9600 baud) data path. A trio of "THINWIRE" protocols for connecting a personal computer to the INTERNET is presented for discussion โœจ

Modems are super cheap and flexible, which is very attractive ๐Ÿ˜ But their low speed causes some major problems ๐Ÿ™ˆ For example, a minimum TCP/IP Telnet packet (one character) is 41 bytes long. At 1200 baud, sending that packet takes around 0.3 seconds. That's the same as using a 30 baud line for single character transmission. Throughout the paper, the assumption is that transmission speed is limited only by the speed of the communication line. We also assume the line acts as a synchronous link when calculating speed. In reality, interrupt, computational, and framing overhead could make the times 10-50% worse ๐Ÿค“

In lots of cases, local echo and line editing can give acceptable Telnet behaviour. But many applications only work with character at a time transmission ๐Ÿ˜ค On top of that, multiple data streams can be super useful for really taking advantage of the personal computer/Internet link. So, this proposal ๐Ÿ’œ

There are several forms a solution to this problem can take. Here are three of them, followed by descriptions of possible solutions for each form:

  • As a non-solution, you can learn to live with the slow communication. This is honestly a reasonable thing to do for background file transfer and one-time inquiries to time, date, or quote-of-the-day servers ๐Ÿ•ฐ๏ธ
  • Using TCP/IP, you can intercept the link level transmissions and try various kinds of compression algorithms. This gives you a symmetrical structure on either side of the "Thinwire" ๐Ÿชž
  • You could build an "asymmetrical" gateway that takes some of the transport and network communication overhead away from both the serial link and the personal computer. The goal is to make the PC do the local work, and to make the connection to the extended network a benefit to the PC instead of a drain on its resources ๐Ÿงš

The first form is simple and easy to implement, but we already talked about its disadvantages above ๐Ÿ™ƒ The second form, compression at link level, can be exploited in two ways:

  • Thinwire I is a simple, robust compressor. It will reduce the 41 byte minimum TCP/IP Telnet packets to a series of 17 byte update packets. For single character packets over a 1200 baud line, that improves the effective baud rate from 30 baud to 70 baud ๐Ÿ“ˆ
  • Thinwire II uses a much more complex technique and takes advantage of the storage and processing power on either side of the thinwire link ๐Ÿง  It will compress packets from multiple TCP/IP connections from 41 bytes down to 13 bytes. The increased communication rate is 95 (effective) baud for single character packets ๐Ÿ”ฅ

The third form balances the characteristics of the personal computer, the communications line, the gateway, and the Internet protocols. The goal is to make the communications and the workstation itself as useful as possible ๐Ÿ‘‘ Instead of running full transport and internet layers on the PC, the PC and the gateway manage a single reliable stream, multiplexing data on this stream with control requests. Without the interneting and flow control structures travelling over the communications line on a per/packet basis, the data flow can be compressed a ton ๐ŸŒˆ There is some switching overhead, and a reliable link level protocol is needed on the serial line, so the average effective baud rate would be in the 900 baud range โญ

Each of these Thinwire possibilities will be explored in detail ๐Ÿซถ

Thinwire III ๐Ÿงš

okay bestie, so if you don't need link-level transmissions and just want the services, Thinwire III might be the move ๐Ÿ’… The whole thing is built around a star network with a gateway in the middle. That gateway connects a bunch of Personal Computers to the Internet, and honestly it's giving main character energy. ๐Ÿ‘‘

Thinwire III doesn't do connections at the network/link level. It assumes there's a reliable serial link underneath (SLIP or something equivalent ๐Ÿซถ), and that the workstation or PC has better things to do than babysit TCP state tables, timeouts, and all that. The gateway is the one that's powerful enough to run lots of TCP connections and several SLIPs at the same time. So the gateway covers for the limits of the comms line and the PC, and it becomes the bridge to the INTERNET, handling the transport and network stuff and giving you both reliable stream and datagram service. โœจ

Here's how it goes. The gateway starts an interpreter for each SLIP connection coming from a personal computer ๐ŸŒธ When the PC asks, the gateway opens TCP, UDP, and later TP4 connections. It acts as the PC's agent, handling the remote negotiations and the data flow going to and from the PC. You can have multiple connections open at once, and inline logical switches in the reliable data flow say which connection each bit of data belongs to. There are also extra escaped sequences that carry error and informational data between the two Thinwire III communicators. ๐Ÿฆ‹

This protocol is NOT symmetric, and it's giving one-sided friendship ๐Ÿ™ˆ The gateway can open connections out to the INTERNET world as the PC's agent, but it can't open inbound connections to the PC, because the PC is treated as a stub host. The PC can passively open connections on the gateway to act as a server though ๐ŸŽ€ Extended control sequences are defined to handle the multiple connection negotiation that server ability brings along.

Now flow control. ngl, this protocol seems to just ignore it ๐Ÿ’€ But the thinking is that processing on both sides of the link is way speedier than the link itself. So the buffering on the communication line, plus the user process blocking when it has to wait, does most of the flow control work. For the rare times that's not enough, there are control messages that can delay the flow to a port or stop all data flow. ๐Ÿ”ฅ

A tentative specification for Thinwire III is attached as Appendix C. ๐ŸŒˆ


The authors acknowledge the shoulders they're standing on, and they apologize for the toes they stepped on ๐Ÿซถ Ongoing work is being done by Eric Thayer, Guru Parulkar, and John Jaggers. Huge thanks to Peter vonGlahn, Jon Postel, and Helen Delp for their helpful comments on earlier drafts ๐Ÿ’– Responses are super appreciated at these addresses:

  • Dave Farber <Farber@udel-ee>
  • Gary Delp <Delp@udel-ee>
  • Tom Conte <Conte@udel-ee>

Appendix A -- Example of Thinwire I Compression ๐Ÿฆ‹

okay so this is a real example of how Thinwire I would work in a totally common situation ๐Ÿ’… The connection is a TCP/IP Telnet connection. The first packet simulates typing the character "a", and the second packet is what you'd get from typing "d". The compressed version is the third one, and it's on a later page.

[NOTE: The checksums pictured have not been calculated. Binary in MSB to LSB format]

Here are the packets, so you can see the bits lined up ๐Ÿ˜ญ

        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
IP     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header:|Version|  IHL  |Type of Service|          Total Length         |
       |0 1 0 0|0 1 0 1|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0|
P      |   4   |   5   |       0       |               41              |
a      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
c      |       Identification          |Flags|      Fragment Offset    |
k      |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0|
e      |                1              |  0  |            0            |
t      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-      |  Time to live |   Protocol    |       Header Checksum         |
1      |0 1 1 0 0 1 0 1|0 0 0 0 0 1 1 0|0 1 1 1 0 1 1 1 0 0 0 1 0 1 0 0|
       |      101      |       6       |             nnn               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     Source Address                            |
       |1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0|
       |    192.       |       5.      |     39.       |      20       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   Destination Address                         |
       |0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0|
       |     10.       |       2.      |      0.       |      52       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
TCP    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header:|         Source Port           |       Destination Port        |
       |0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1|0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1|
       |             1025              |               27              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                        Sequence Number                        |
       |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 0 0|
       |                              300                              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     Acknowledgement Number                    |
       |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0|
       |                              100                              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |offset | Reserved  |U A P R S F|            Window             |
       |0 1 0 1|0 0 0 0 0 0|0 1 0 0 0 0|0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0|
       |   5   |     0     |     16    |             512               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           Checksum            |         Urgent Pointer        |
       |0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
       |             nnn               |               0               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                            Data                               |
       |0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
       |        "a"                                                    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
IP     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header:|Version|  IHL  |Type of Service|          Total Length         |
       |0 1 0 0|0 1 0 1|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0|
       |   4   |   5   |       0       |               41              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
P      |       Identification*         |Flags|      Fragment Offset    |
a      |0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0|
c      |                2              |  0  |            0            |
k      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
e      |  Time to live*|   Protocol    |       Header Checksum*        |
t      |0 1 1 0 0 1 1 0|0 0 0 0 0 1 1 0|0 1 1 1 0 1 1 1 0 0 0 1 0 1 0 0|
-      |      102      |       6       |             nnn               |
2      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     Source Address                            |
       |1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0|
       |    192.       |       5.      |     39.       |      20       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   Destination Address                         |
       |0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0|
       |     10.       |       2.      |      0.       |      52       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
TCP    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header:|         Source Port           |       Destination Port        |
       |0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1|0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1|
       |             1025              |               27              |
* 's   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
show   |                        Sequence Number*                       |
changed|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 0 1|
fields |                              301                              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     Acknowledgement Number*                   |
       |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1|
       |                              101                              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |offset | Reserved  |U A P R S F|            Window             |
       |0 1 0 1|0 0 0 0 0 0|0 1 0 0 0 0|0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0|
       |   5   |     0     |     16    |             512               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           Checksum*           |         Urgent Pointer        |
       |0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
       |             nnn               |               0               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                            Data*                              |
       |0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
       |        "d"                                                    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Okay so bestie, this is the previous packet all dressed up with its numbers ๐Ÿฆ‹ Now the Thinwire Driver ๐Ÿ•ต๏ธโ€โ™€๏ธ goes and finds the template (aka the previous packet that got sent ๐Ÿ’Œ), compares it to the new packet, and builds a change message โœจ (I added field names to the change record data so you can actually follow along):

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |Descriptor byte|   Data:       |Descriptor byte|  Data:        |
      |offset |length | Identification|offset |length |  Time to live |
      |0 0 1 0|0 0 0 1|0 0 0 0 0 0 1 0|0 0 1 0|0 0 0 1|0 1 1 1 0 1 1 0|
      |   2   |   1   |      2        |   2   |   1   |     102       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |Descriptor byte|   Data:                       |Descriptor byte|
      | offset| length|         Header Checksum       |offset |length |
      |0 0 1 0|0 0 1 0|1 1 1 1 0 0 1 0 1 0 1 1 0 1 0 0|1 1 1 1|0 0 1 0|
      |    2  |   2   |              nn               |  15   |   2   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |   Data:       |Descriptor byte|   Data:       |Descriptor byte|
      |   Seq Number  |offset |length |   Ack Number  |offset |length |
      |0 0 1 0 1 1 0 1|0 0 1 1|0 0 0 1|0 1 1 0 0 1 0 1|0 1 1 1|0 0 1 0|
      |      301      |   3   |   1   |      101      |   7   |   2   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |   Data:                       |Descriptor byte|   Data:       |
      |       -- TCP Checksum --      |offset |length |     data      |
      |0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0|0 0 1 0|0 0 0 1|0 1 1 0 0 1 0 0|
      |             nn                |   2   |   1   |     "d"       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |Descriptor byte|
      |offset |length |
      |0 0 0 0|0 0 0 0|  the 0 0 offset/length record ends the update.
      |   0   |   0   |
      +-+-+-+-+-+-+-+-+

Thinwire I then sends this message over the line, where the previous packet gets updated to form the new packet ๐Ÿ’–

Note: One can see that a series of null descriptor bytes will reset the connection. ๐Ÿšจ So a run of null descriptor bytes = connection reset, periodt ๐Ÿ’€

Appendix B -- Examples of Thinwire II Compression โœจ

This Appendix is giving example time ๐ŸŽ€ It shows how Thinwire II would operate in a super common situation. We're reusing the same original packets from Appendix A, so you'll only see the updates this time.

As the later field definitions depend on the contents of the earlier fields, a field by field analysis of the update packets is going to be super useful ๐Ÿง 

                    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      Thinwire II  |U|L|Template no| Len of change | Type of Packet|
       minimum     |0|0|0 0 0 1 0 1|0 0 0 1 1 0 0 1|0 0 0 0 0 0 0 1|
       header:     |N N|     5     |          41   |     TCP/IP    |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Okay the first bit is the UPDATE bit ๐Ÿ”‘ If it's a 0, this packet describes a brand new template, and the entire new packet gets included right after the header. If there was already a previous template with the same number, it gets cleared and replaced by the new one ๐Ÿงน If the UPDATE bit is a 1, then this packet should be used to update the template with the number given in the template number field.

The second bit is the LONG bit ๐Ÿ“ If it's a 1, that means it's a LONG packet, so the update length field becomes 16 bits instead of 8 bits.

The remaining 6 bits in the first byte tell you which template number this packet is an update to ๐ŸŽฏ

The template number is followed by 1 or 2 bytes (depending on what the LONG bit says), and those bytes give the length of the packet. This is the number of data bytes following the variable length header.

If the UPDATE bit is 0 on this packet, the next byte is a flag telling what type of packet the sender thinks this packet is ๐Ÿท๏ธ The flag gets saved by the receiver so it can interpret the update packets later. Type 0 is for unknown types, and if the type 0 flag is set, there will be no updates to this template number. Type 1 is TCP/IP, and the method of updating for that will be described below. Type 2 is UDP/IP, and the method of update is not described at this time.

At this point we have enough info to encode packet 1 of the example ๐Ÿฅณ Assuming for the moment that this is the first packet for this connection, the UPDATE bit would be set to 0. Since the packet has a length of 41 and can be described in 8 bits, the LONG bit would be set to 0. A template number that isn't in use (or the oldest in-use template number) would be assigned to this packet, and the number 5 is used in the illustration. The Length of Packet would be given as 41, and the Type Flag set to TCP/IP (1). Then the 41 bytes of the packet follow.

The transmission of packet 2 requires the specification of Type 1 (TCP/IP) updating ๐Ÿ’… There are portions of the packets which will always be the same. These are described in the body of the paper, and they're used to match the template, so they don't need to be transmitted for an update. There are also portions of the packet which will always (well, almost always) change. These are the IP Header checksum, the IP Identification number, and the TCP checksum. These get transmitted, in that order, with each template update, right after the packet length byte or bytes. Following the invariant portion of the header are updates to the fields which change some of the time. Which fields are different is indicated with a bitfield describing the changes.

The Bitfield is used to indicate which fields (out of those that may stay the same) have changed. The technique for updating a field varies with the field description. The specifications for TCP/IP are shown in Table B-1 ๐Ÿ“‹

           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Thin-  |U|L|Template no| Len of change | Type of Packet|
wire II|0|0|0 0 0 1 0 1|0 0 0 1 1 0 0 1|0 0 0 0 0 0 0 1|
header:|N N|     5     |          41   |     TCP/IP    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
IP     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header:|Version|  IHL  |Type of Service|          Total Length         |
       |0 1 0 0|0 1 0 1|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0|
P      |   4   |   5   |       0       |               44              |
a      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
c      |       Identification          |Flags|      Fragment Offset    |
k      |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0|
e      |                1              |  0  |            0            |
t      +~+~+~+~+~.~+~+~+~+~+~+~+~+~+~+.+~+~+~+~+~+~+~+~+~+~+~.~+~+~+~+~+
-                .                    .                      .
1                .                    .                      .
       +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
       |           Checksum            |         Urgent Pointer        |
       |0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
       |             nnn               |               0               |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |    Data       |
       |0 1 1 0 0 0 0 1|
       |        "a"    |
       +-+-+-+-+-+-+-+-+

The changed field update information gets added to the update header in the order the bits appear in the field. So if both the IP packet length bit and the Time to Live bit are set, the 2 new bytes of the IP Packet length come first, and then the 1 new byte of the Time to Live field ๐Ÿงƒ

Here's the update for packet 2 ๐ŸŒธ Note that this is an update to template 5, and the length of the update is 8 bits with a value of 1. The new checksums and IP Identification Number are included, and the flags are set to indicate changes to the following fields: Time to Live, and Add 8 bits to Sequence and Acknowledgement Numbers. The new data is one byte following the header.

Thinwire II would send this message over the line, where it gets reassembled into the correct packet ๐Ÿฆ‹

Note: For purposes of synchronization, if three 0 length, template 0, type 0 packets are received, the next non-zero byte should be treated as a start of packet, and the template tables cleared. ๐Ÿงน
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |U|L|Template no| Len of change |   IP  Header  Checksum        |
   |1|0|0 0 0 1 0 1|0 0 0 0 0 0 0 1|0 1 1 1 0 1 1 1 0 0 0 1 0 1 0 0|
   |Y|N|     5     |       1       |           nnn                 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   IP Identification number    |      TCP  Checksum            |
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0|
   |           2                   |           nnn                 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Bitfield     |  Time to Live |add to Seq no. | add to Ack Num|
   |0 0 1 0 1 0 0 0|0 0 0 0 0 0 0 1|0 0 0 0 0 0 0 1|0 0 0 0 0 0 0 1|
   |    T Ad8      |       1       |        1      |      1        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    data       |
   |0 0 0 1 0 1 1 1|
   |      "d"      |
   +-+-+-+-+-+-+-+-+

Packet 2. Thinwire II update ๐ŸŒˆ


Appendix C -- Tentative Specification for Thinwire III ๐ŸŽ€

okay bestie, Thinwire III is giving "one wire, many conversations" ๐Ÿฆ‹. It runs over a single point to point connection, so a lot of the per-datagram routing and sequencing stuff that other transport systems need just gets deleted ๐Ÿ’…. In the steady state, any bytes thinwire III receives go straight to the default higher level protocol connection. There are also escaped control sequences that let you create extra connections, switch the default connection, packetize datagrams, and pass info between the gateway and the personal computer. The gateway and the PC share one full duplex stream and juggle control requests and data streams with embedded logical switches. main character multitasking ๐Ÿ‘‘

The ascii character "z" (binary 01011011) is the escape character ๐Ÿงš. The byte right after the "z" tells you which command it is. Table C-1 shows the general classes the bytes (Request codes) can fall into ๐Ÿ“‹.

If you want to actually send a "z", you send two "z"s ๐Ÿ™ˆ. The first one gets read as the escape, and the second one is a lowercase "z" that goes to the default connection. The letter z was picked as the escape because it shows up rarely in text and control data streams, it should pass easily through any lower level protocols, and it's generally innocuous ๐Ÿ’œ.

Here's the rundown on each Request code ๐ŸŒธ.

Starting with the range 0-31: these Request codes change the default connection ๐Ÿ”€. Once a connection has been established, any characters coming across the line that aren't part of a Request code sequence get sent to one of the connections. At the start, the connection defaults to Zero, but when the "Switch Default Connection" command comes in, characters go to the connection named in the request until a new request shows up. Zero is a special diagnostic connection, so anything received on connection number Zero should be echoed back to the sender on connection number One. Anything received on connection number One should be placed on the diagnostic output of the receiving host. Any other connection number means the data should be sent out the numbered connection. If that numbered connection hasn't been opened, the data can be thrown away, and an Error Control Message gets returned to the sender ๐Ÿ™ƒ.

Escapes followed by numbers 32 through 255 are for new connections, requests for information, and error messages โœจ. The escape is followed by a Request code, a one byte Request Sequence Number (so the Reply to Request can be asynchronously matched up with the Request), and then the arguments for that specific request. The length of the argument field is determined by the Request code. The format of the request looks like this:

"z" <Request Code> <Request Sequence Number> [ <Arguments> ... ]

At this time, the Request codes 32-63 are reserved ๐Ÿ”’.

The Request codes 64-127 are for stream server open requests. Since compression matters here, many of the common servers get single byte codes. See Table C-2 ๐Ÿ—‚๏ธ.

Request code 68 connects you to the default hostname server used by the gateway ๐ŸŒ. It takes 3 bytes for this request, and it looks like this:

"z" < 68 > < Request Sequence Number >

Request code 95 opens any specified TCP Port at the specified address ๐Ÿ”Œ. It takes 9 bytes for this request, and the form is:

"z" < 95 > < Request Sequence Number > < 4 bytes of IP address> <
2 bytes of TCP Port >

Request codes 96-127 are RESERVED for alternate transport protocols ๐Ÿšง.

The Request codes 128-191 are used for framing Datagrams and opening new Datagram connections ๐Ÿ“ฆ. The code 128 is the Start of Datagram code, and the format is:

"z" <128> <Length of Datagram (2 bytes)> <Socket> Data ...

Just like the Stream opens, there are a bunch of assigned ports that have codes of their own. They're listed in Table C-3 ๐ŸŽฏ.

The Request Codes 192-254 are control, status and informational requests ๐Ÿ› ๏ธ. These are still under development, but they're going to include:

  • flow control
  • get host/server/protocol by entry/name/number.
  • additional error messages
  • overall reset
  • open passive connection

The Request Code 252 is the request to close a connection ๐Ÿšช. This code, followed by the connection number, means no more data will be sent out that connection number. A second request with the same connection number means no more data will be accepted on that connection.

The Request Code 253 is the information request for a connection โ„น๏ธ. The protocol, status, and port number of the connection should be returned. The format of this reply has yet to be specified.

The Request code 254 is an error notification ๐Ÿšจ. These are to be acknowledged with their Request Sequence Numbers. Error codes are under development.

The Request code 255 is the Reply to Request ๐Ÿ“ฌ. The Request Sequence Number identifies which request is being replied to. The format is:

"z" <255> <Request Sequence Number (in reply to)> <Length of reply
(1 byte)> Reply...

The Thinwire Drivers on each side will wait at their inbound sockets and relay across the thinwire link character-by-character or packet-by-packet for the stream or datagram connections ๐Ÿฆ‹.

Thinwire III is labeled as a tentative specification ๐Ÿฅบ, because at this time, in order to publish this RFC in a timely fashion, several minor issues are still unresolved. One example is the scheduling of serial line use. Short messages could be given priority over long packets, or priority schemes could be changed during the session, depending on what the user wants in the moment. Additional issues will be resolved in the future ๐Ÿ”ฎ.


Appendix D -- Serial Line Interface Protocol (SLIP) ๐ŸŒˆ

Initial Specifications and Implementation Suggestions

PHILOSOPHY โœจ

the world is a dangerous place for bits ๐Ÿ˜ญ. Data transmission can be a time consuming business when you have to make sure bits don't get lost, destroyed, or forgotten. To cut down on those problems, the Serial Line Interface Protocol (SLIP) has an attitude toward the world that includes both a mistrust of serial lines and a margin of laziness ๐Ÿฆฅ. Examples of this include how SLIP recovers from errors and how SLIP handles the problem of resequencing (see PROTOCOL SPECIFICATIONS and IMPLEMENTATION SUGGESTIONS).

THE MESSAGE FORMAT ๐Ÿ’Œ

Both the Sender Task and the Receiver Task talk using a standard message format, and the Sender and Receiver Task of one machine's SLIP share a buffer ๐Ÿค. Each message begins with a 1 byte Start of Header token (StH, 11111111), followed by a sequence number of four bits (SEQ) and an acknowledgement number of four bits (ACK). After the StH, SEQ and ACK comes a 5 bit length field that says how long the data in the message is. After the length is a three bit field of flags ๐Ÿšฉ. The first bit says that a receive error has occurred, and the ACK is actually a repeat of the Last Acknowledged message (a LACK). The second bit indicates a Synchronize Sequence Numbers message (SSNM), and the third bit indicates a Start of Control Message (SOCM). All three of these flags get explained below. Last but not least, the end of the message has an exclusive-or checksum ๐Ÿงฎ. The message format is shown in figure D-1.

            ________________________________________________

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
|     StH       |  SEQ  |  ACK  |  Length |Flags|...Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
The maximum data length is 32 bytes.                0 1 2 3 4 5 6 7
This limits the vulnerability of receiver       ...-+-+-+-+-+-+-+-+-+-+
timeout errors occurring because of bit error .Data...|   Checksum    |
in the length field.                            ...-+-+-+-+-+-+-+-+-+-+

                    Figure D-1. SLIP Message Format

            ________________________________________________

The Sender, when it's idle but needs to acknowledge something, will send out short messages in the same format as a regular message, except the SOCM flag is set and the data field is omitted ๐Ÿซถ. (This short message is called a SOCM, and it's used instead of a zero length message to avoid the problem of continually ACK'ing ACK's ๐Ÿ™ƒ.) The Sender Task, when it's originating a connection (see STARTING UP AND FINISHING OFF COMMUNICATIONS), will send out another short message, but this time with the SSNM flag set and the data omitted. This message (a SSNM) is used for a TCP-style 3 way startup handshake ๐Ÿคโœจ.

PROTOCOL SPECIFICATIONS and SUGGESTIONS ๐Ÿง 

The SLIP module, when it's called with data to send, prepends its header (SEE ABOVE) to the data, calculates a checksum, and appends the checksum at the end. (This creates a message.) Each message has a sequence number that represents its position in the Sender SLIP's buffers. The sequence number can range from 0 to 15, and it's returned in the ACK field of the other machine's Sender SLIP messages to acknowledge receipt ๐Ÿ“จ.

There are two scenarios for transmission ๐Ÿ‘ฏ. In the first, both SLIP's are transmitting to each other. To send an acknowledgement, the Receiver SLIP uses the ACK field in its next outgoing message. To receive an acknowledgement, the Sender checks the ACK field of its Receiver's incoming messages. In the second scenario, one SLIP may have no data to transmit for a long time ๐Ÿ˜ด. Then, as stated above, to acknowledge a received message, the Receiver has its Sender send out a short message, the SOCM (SEE ABOVE), which specifies the message being acknowledged. The SOCM includes a checksum of its total contents. If there's a checksum error, THE SOCM IS IGNORED ๐Ÿ’€.

When there's a checksum error on a received normal message, the Receiver asks its Sender to send out a SOCM with the LACK flag set, or to set the LACK flag on its next message ๐Ÿšจ. The Sender sends this flag ONCE, then stops incrementing the acknowledgement number (the ACK), while the Receiver keeps checking incoming messages for the sequence number of the message with the checksum error. (Note that it keeps reacting to the acknowledgement field in incoming messages ๐Ÿ‘€.) When it finds the needed message, it goes back to accepting data in new messages and increments the acknowledgement number transmitted accordingly ๐Ÿฅณ.

The sending SLIP must never send a message greater than four past the last message it got an acknowledgement for, so basically a window size of four. ๐ŸชŸ Under normal processing loads, a window size greater than four should not be needed, and this lowkey cuts down the chance that random errors create a fake acknowledgement or sequence number that looks valid ๐Ÿ™ˆ If the Sender has four unacknowledged messages outstanding, it retransmits the old messages, starting from the oldest unacknowledged one. If it gets an acknowledgement with the LACK flag set, it transmits the message following the LACK number and keeps transmitting from that one on. So a LACK is literally a message asking the Sender to please the Receiver ๐Ÿฅบ๐Ÿ’– If the Sender times out on any message not logically greater than four past the last acknowledged message, it should retransmit the message that timed out and then continue to transmit messages following the timed out message โฐ

The following describes a partial implementation of SLIP. โœจ System dependent subjects like buffer management, timer handling and calling conventions are discussed.

The SLIP implementation is split into four modules and two sets of input/output interfaces. ๐Ÿงฉ The four modules are the Sender Task, the Receiver Task, the buffer Manager, and SLIPTIME (the timer). The two interfaces are to the higher protocol and to the lower protocol, which is the UARTian, an interrupt driven device driver for the serial lines ๐Ÿ”Œ

OPERATIONS OF THE SENDER TASK ๐Ÿ’Œ

The Sender Task takes a relatively noncomplex approach to transmitting, and I respect that energy ๐Ÿ’… It sends message zero, sets a timer on it (using the SLIPTIME Task), and then keeps sending and setting timers for messages one, two, and three. When the Receiver Task tells the Sender Task that a message has been acknowledged, the Sender Task clears the timer for that message and marks it acknowledged โœ…

When the Sender Task has finished sending a message, it checks a few conditions to decide what to do next. First it checks whether a LACK has been received. If it has, it clears all the timers and begins retransmitting messages (updating the acknowledgement field and checksum) starting from the one after the LACK'ed message. ๐Ÿ” If there is no LACK waiting for the Sender Task, it checks whether any messages have timed out. If a message has timed out, the Sender Task again clears the timers and begins retransmitting from the message number that timed out. If neither of these conditions is true, the Sender Task checks whether, because it has looped back to retransmit, it has any previously formulated messages to send. If so, it sends the first of these messages. ๐Ÿ“ฆ

If it does not have previously formulated messages, it checks whether it is more than three past the last acknowledged message. If so, it restarts from the message after the last acknowledged message. If none of these are true, it checks whether there is more data waiting to be transmitted. If there is more data available, it forms the largest packet it can and begins to transmit it ๐Ÿš€ If there is no more data to transmit, it checks whether it needs to acknowledge a message received from the other side. If so, it sends a SOCM. If none of the above conditions create work for the Sender Task, the task suspends itself ๐Ÿ˜ด

Note that the Sender Task uses the Receiver Task to find out about acknowledgements, and the Receiver Task uses the Sender Task to send acknowledgements to the other SLIP on the other side (via the ACK field in the Sender Task's message). The two tasks on one machine communicate through a small buffer. ๐Ÿค Because acknowledgements need to be passed back to the Sender Task quickly, the Receiver Task can wake up the Sender Task (unblock it) โšก

OPERATIONS OF THE RECEIVER TASK ๐Ÿ“ฅ

The Receiver Task checks the checksums of the messages coming into it. When it gets a checksum error, it tells the Sender Task to mark the next acknowledgement as a LACK. It then throws away all messages coming into it that don't match the message it wants, and keeps acknowledging with the last ACK until it gets the message it wants ๐Ÿ™ƒ A checksum error could be the result of a crashed packet, and the StH character can occur within the packet. So when a checksum error does occur, the recovery includes scanning forward from the last StH character for the next StH character, then attempting to verify a packet beginning from it ๐Ÿ” A valid message includes a valid checksum, and sequence and acknowledgement numbers within the active window of numbers. This eliminates the need for resequencing messages, because the Receiver Task throws away anything that would make information in its buffers out of sequence. No cap, that's iconic design ๐Ÿ‘‘

OPERATIONS OF SLIPTIME โฑ๏ธ

The timer task will maintain and update a table of timers for each request. Its functions should be called with the timer length and the sequence number to associate with the timer. Its functions can also be called with a request to delete a timer. An interrupt-driven mechanism is used to update the running timers and to wake up the Sender when an alarm goes off ๐Ÿ””

THE INPUT AND OUTPUT INTERFACES ๐ŸŽ€

To force SLIP to do something, the higher protocol should create a buffer and then call SLIP, passing it a pointer to the buffer. SLIP will then read the buffer and begin sending it. The call to SLIP returns the number of bytes written. A negative number indicates to the caller that SLIP could not do the request. Exact error numbers will be assigned in the future ๐Ÿ”ข To ask SLIP to receive something, one would call SLIP, and SLIP would immediately return the number of bytes received, or a negative number for an error (nothing ready to receive, for example) ๐Ÿ“ญ

SLIP, when it wants to talk to the underworld of the serial interface, does much the same thing, only through a buffer written to by the UARTian (for received data) and read from by the UARTian (for sent data) ๐Ÿซฃ

OPERATIONS OF THE BUFFER/WINDOW MANAGER ๐Ÿ—‚๏ธ

The Manager tends a continuous, circular buffer for the Sender Task in which data to be sent (from the downcalling protocol) is stored. This buffer is called the INPUT-DATA BUFFER (IDBuff). The Manager also manages a SENDER TASK'S OUTPUT-DATA BUFFER (SODBuff), which is its output buffer to the UARTian ๐Ÿ’

The IDBuff has some parameters attached to it. These include START OF MEMORY (SOM), the start of memory reserved for the IDBuff; END OF MEMORY (EOM), the end of memory reserved; START OF DATA (SOD), the beginning of the used portion of the IDBuff; and END OF DATA (EOD), the end of data in the IDBuff. The SOM and EOM are constants, whereas the SOD and EOD are variables ๐Ÿงฎ

The SODBuff is made up of four buffers for four outbound messages (less the checksum). The buffers can be freed up to be overwritten when the message they contain is acknowledged by the SLIP on the other side of the line. When a message is in the SODBuff, it has a sequence number associated with it (which is the message's sequence number). The Sender Task can reference the data in the SODBuff and reference acknowledgements via this sequence number ๐Ÿ”—

When the application has data to be transmitted, the application places it in the IDBuff using functions from the Manager, and the EOD is incremented. If the data the application wants to send won't fit in the buffer, no data is written, and the application can either sleep, or keep trying to write until the data will fit ๐Ÿ˜ฌ The Sender Task calls a Manager function to fill a message slot in the SODBuff. The Sender Task then sends its message from the SODBuff ๐Ÿ“ค

The Manager also maintains a buffer set for the Receiver Task. The buffers are similar to those of the Sender Task. There is a CHECKSUMMED OUTPUT-DATA BUFFER (CODBuff), which is the final output from SLIP that the higher level protocol may read. The CODBuff is also controlled by the four parameters START OF MEMORY, END OF MEMORY, START OF DATA, and END OF DATA (SOM, EOM, SOD, and EOD) ๐Ÿง

There is also an inbound circular buffer, the analog of the SODBuff, called the RECEIVER TASK'S INPUT-DATA BUFFER (RIDBuff) ๐Ÿ’ซ

When the UARTian gets data, it places the data in the RIDBuff. After this, the Receiver Task checksums the data. If the checksum is good and the Receiver Task opts to acknowledge the message, it moves the data to the CODBuff, increments EOD, and frees up space in the RIDBuff. The higher level application can then take data off the CODBuff, incrementing SOD as it does so ๐Ÿ“

STARTING UP AND FINISHING OFF COMMUNICATIONS ๐Ÿคณ

The problem is that the SLIPs on either side need to know (and keep knowing) the sequence number of the other SLIP. The easiest way to solve most of these problems is to have the SLIP check the Request to Send and Clear to Send lines to see if the other SLIP is active. On startup, or if it has reason to believe the other side has died, the SLIP assumes that all connections are closed, no data from any connection has been sent, and both its SEQ and the SEQ of the other SLIP are zero ๐Ÿงธ

To start up a connection, the instigating SLIP sends an SSNM with its starting sequence number in it. The receiving SLIP acknowledges this SSNM and replies with its own starting sequence number (combined into one message). Then the sending SLIP acknowledges the receiving SLIP's starting sequence number, and the transmission commences. This is the three way handshake taken from TCP ๐Ÿค After which, data transmission can begin ๐Ÿš€๐Ÿ’œ

๐Ÿ“ฆ where this page comes from