RFC 714

Host-Host Protocol for an ARPANET-Type Network

๐Ÿ“… published April 1976, from ietf

๐Ÿ“œ RFC 714: A Host/Host Protocol for an ARPANET-Type Network ๐ŸŽ€

Okay bestie, let me set the scene ๐Ÿ’…. This is RFC 714, written by A. McKenzie of BBN-NCC, dated April 1976, with NIC number 35144 ๐ŸŒธ. The header doesn't give a category or status, and it doesn't say it obsoletes or updates anything, so we're just going off the facts that are actually here โœจ.

Then comes the preface ๐Ÿงš. Recently the authors were planning a network that would use ARPANET IMPs without any modification, but would let you re-specify the Host/Host Protocol (and the higher level protocols too) ๐Ÿ’œ. The rest of this doc is a slightly edited version of their recommendation for the Host/Host Protocol, because they figured the ARPANET Community might find it interesting ๐Ÿฆ‹.


I. Introduction โœจ

The Host/Host Protocol for the ARPANET was the first one ever designed for use over a packet-switched network ๐Ÿ‘‘. The current version has been around since early 1972, and it has transported billions of bits over tens or hundreds of thousands of connections ๐Ÿ”ฅ. So yeah, it's clearly adequate for the job, but adequate isn't the same as ideal ๐Ÿ™ˆ. The ARPANET Host/Host Protocol has been criticized on a few grounds (among others):

  1. It's simplex ๐Ÿ’€. Each established connection is a simplex entity, so two connections (one in each direction) have to be set up before you can carry out an exchange of messages. That gives great generality, but at a maybe unacceptable cost in complexity.
  2. It's not very robust ๐Ÿ˜ญ. It can't keep operating correctly in the face of several types of message loss. The ARPANET itself rarely loses messages, but messages are occasionally lost, both by the network and by the Hosts.
  3. Flow control is clunky for transactions ๐Ÿซถ. Because connections are simplex, the flow control mechanisms in the ARPANET protocol don't make efficient use of how much data processing is transactional. Instead of sending flow control info (in the form of permits, or requests for more information) on the reverse traffic, a separate channel gets set up just to convey it. So for transactional systems, up to twice as many messages get exchanged (half for flow control and half for data) as would be needed for data alone.
  4. Reaching service facilities is a whole ordeal ๐Ÿ™„. The prohibition against using a connection termination point more than once makes establishing communication with service facilities extremely cumbersome.

The International Federation for Information Processing (IFIP) Working Group 6.1 (Packet-switched Network Internetworking) recently approved a proposal for an internetwork end-to-end protocol ๐ŸŒˆ. The IFIP Protocol is based on experience from the ARPANET, the (French) Cyclade Network, and the (British) NPL Network, plus the plans of other networks ๐ŸŽ€. So you'd expect it to have all of the strengths and few (or none) of the weaknesses of the protocols in use on, or planned for, those networks.

In fact, the IFIP Protocol avoids the ARPANET protocol's deficiencies mentioned above ๐Ÿฆ‹. Connections are treated as full-duplex entities, which means flow control info can ride the reverse channel in transaction-oriented systems where there's reverse channel traffic happening naturally โœจ. The IFIP Protocol is also to some extent self synchronizing. Specifically, there's no type of message loss it can't recover from in a graceful way ๐Ÿ’–.

The IFIP Protocol makes a minimal number of assumptions about the network it operates over ๐Ÿงฉ. It's designed to permit fragmentation as a message crosses from one network to another, without network reassembly. It anticipates duplication or non-delivery of messages or message fragments, and it provides ways to recover from those conditions ๐Ÿ’œ. Finally, it permits delivery of messages at their destination Host in a completely different order from the order the source Host input them ๐ŸŒ€. Unfortunately, all of that comes at a relatively high overhead cost in transferred bits ๐Ÿ˜ฌ. The complete source and destination process addresses are carried in every message, 24-bits of fragment identification are carried with each fragment, and 16-bits of acknowledgement information are also carried in every message.

When you're looking at channel capacities of hundreds of kilobits (or more), a message overhead of a few hundred bits is a modest price to pay for great flexibility and generality ๐Ÿ’…. But for a stand-alone network of the type under consideration, especially given the anticipated use of many circuits of 10kbs capacity, the IFIP Protocol offers way more generality than is needed, and it still pays a pretty severe overhead price for it ๐Ÿ’€.

The virtual circuit protocols currently being debated within the International Telegraph and Telephone Consultative Committee (CCITT) are going in the opposite direction ๐Ÿงš. Virtual circuit protocols try to make a packet switching network indistinguishable (from a customer's point of view) from a switched circuit network, except possibly for error or delay characteristics ๐Ÿ‘‘. So they tend to put responsibility for end-to-end communications control within the network instead of within the Hosts ๐Ÿซถ. For example, when a receiving Host limits the rate at which it accepts data from the network, the network in turn limits the rate of input from the Host transmitting that data stream โœจ. Host protocols designed for virtual circuit networks can be pretty simple, if somewhat inflexible ๐ŸŒธ. The Host might give the network a "link number" or "index" and ask it to set up a virtual circuit to some other Host to be associated with that number, then report back if and when the circuit is established ๐Ÿ’œ. However, adding a virtual circuit capability to the ARPANET IMP software would need significant development, and the required changes would seem to be more expensive and carry more uncertainty than they're worth ๐Ÿ™ˆ.

So in light of all that, our approach to this proposed protocol was to start with the ARPANET Host/Host Protocol and modify it using some of the concepts of the IFIP Protocol, in order to remedy its major deficiencies ๐ŸŽ€. The rest of this document specifies the protocol we designed for exactly that purpose ๐Ÿฆ‹โœจ.

II. Communication Concepts ๐ŸŽ€

okay so the IMP subnetwork has a bunch of physical rules for how Hosts can talk, and they're all written up in BBN Report No. 1822 ๐ŸŒธ. the bits that matter for designing the Host/Host Protocol are leaders, messages, padding, message ID's, and message types. this section assumes you already know all of that, bestie ๐Ÿ’…

The IMP subnetwork only takes notice of Hosts ๐Ÿงš. But a single Host can be running several users, several terminals, or several independent processes, and they all want to use the network at the same time. So the Host/Host Protocol has to handle process-to-process communication, which means it needs a richer addressing structure than the IMP subnetwork gives it โœจ

Processes inside a Host talk to the rest of the network through a network control program (NCP) living in that Host, and the NCP is the one that actually speaks the Host/Host protocol ๐Ÿฆ‹. The NCP's main jobs are to establish connections, break connections, and control data flow over them. A connection couples two processes so that the output from one is the input to the other, and vice versa. The NCP can be part of the Host's operating system or its own user process, but it must have the capability of communicating with all of the processes or routines that are trying to use the network ๐Ÿ‘‘.

To do its job, the NCP of one Host has to talk to the NCPs of other Hosts ๐Ÿ’œ. A particular communication path between each pair of Hosts is designated as the control connection. Messages sent over the control connection are called control messages, and an NCP must always interpret them as a sequence of one or more control commands. For example, one kind of control command starts a connection, and another kind tells you a connection has been terminated.*

*Note: in BBN Report No. 1822, messages of non-zero type are called control messages, and they're used to control the flow of information between a Host and its IMP. In this document, "control message" means a message of type zero sent over the control connection. The IMPs take no special notice of these messages.

The IMP subnetwork limits a message to roughly 1000 8-bit bytes ๐Ÿ“, and the receiving Host might limit it even further for flow control reasons (more on that later) ๐ŸŒˆ.

So the transmitting process, or its NCP, has to take responsibility for chopping long interprocess messages into pieces that fit the Host/Host and Host/IMP protocols ๐Ÿ”ฅ. Because of this, a sending Host can't guarantee that receiving processes will attach any meaning to message boundaries. Boundaries will still happen naturally though, and they should be used in a reasonable way wherever possible. In other words, a sending process or its NCP should not fragment messages arbitrarily ๐Ÿ™ˆ. For example, this protocol says that each control message must contain a whole number of control commands, and no single control command gets split into two pieces that travel through the network in separate messages ๐Ÿ’….

A big concern for the Host/Host Protocol is how to reference processes in other Hosts ๐Ÿฆ‹. To make that work, there's a standard name space, with a separate portion of it allocated to each Host, so each Host has to map its internal process identifiers into its own portion of that name space. The elements of the name space are called sockets ๐ŸŒธ. A socket forms one end of a connection, and a connection is fully specified by a pair of sockets, one in each Host. A socket is identified by a Host number and a 16-bit socket number, and the same 16-bit socket number in different Hosts refers to different sockets. Sending a full pair of 16-bit socket numbers in every message would be wasteful, so connection establishment lets each Host define a mapping, valid for the lifetime of that connection, from the 32 bits that specify the socket pair down to an 8-bit number โœจ.

There are no constraints on how socket numbers get assigned ๐Ÿงš. But since a pair of socket numbers defines a unique connection, a Host has to make sure that for each new connection, at least one of the socket numbers is unique. For example, a Host that supports lots of terminals might use a terminal's physical interface number as part of the socket number for any connection set up on that terminal's behalf. That guarantees uniqueness at the terminal end, so there's no conflict if several terminals try to access a common resource (which has its own unique socket number) ๐Ÿ’–.

So the Host/Host protocol lets a single socket take part in several connections at once ๐Ÿ‘‘. It's lowkey like the telephone system, where a company, as well as an individual, can be identified with a phone number. From the outside, a company's phone number is shareable, since several conversations can happen at the same time and the caller doesn't have to worry about the conversations already going on. An individual's phone number isn't shareable, since they can only handle one conversation at a time, and the same is generally true of a connection to a terminal that might be using the network ๐Ÿ“ž.

One last big idea is the "windowing" concept, which is used for flow control ๐ŸŒˆ. It's adapted from the IFIP protocol with some modifications that suit an ARPANET-type network ๐Ÿ”ฅ. When a connection is established, a sequence number is initialized to some specified starting point, and the receiver allocates a certain number of credits to the sender. Each credit entitles the sender to transmit one message. In other words, the receiver agrees to provide buffering for as many messages as the number of credits granted. If you picture sequence numbers advancing from left to right, the initial sequence number defines the left edge of a window into the entire sequence number space, and the credit, when added to the initial sequence number, defines the right edge of the window ๐Ÿฆ‹. The transmitting process is allowed to send as many messages as would fill the window, but no more ๐Ÿ™ˆ.

When a receiver gets a message whose sequence number is at the left window edge (or several consecutive messages running rightward from the left window edge), it returns an acknowledgement for the rightmost one of those messages, along with a new credit, and it advances its own window ๐Ÿ’…. Its new left edge sits right after the last acknowledged message, and its new right edge is at the location you get by adding the new credit to the new left window edge. On the flip side, when a sender receives an acknowledgement, it advances its own left window edge to the location in the sequence number space that the acknowledgement specifies, and its own right window edge to the location you get by adding the new credit allocation to the left window edge โœจ. Fields are reserved in each data message to carry an acknowledgement and a credit for traffic flowing the other way, so in interactive or transactional exchanges, no control messages need to be sent at all ๐Ÿซถ.

What if a sender doesn't get acknowledgements for messages it already sent within some timeout period? Then it transmits those messages again, using the same sequence number it assigned the first time ๐Ÿ˜ญ. That's a straightforward way to recover from lost messages. If it's the acknowledgement that gets lost instead, the retransmitted message carries an identical sequence number, which lets the receiver throw it away as a duplicate ๐ŸŒธ. But the receiver should notice that when the retransmission happened, the sender hadn't yet received an acknowledgement. So the receiver should re-acknowledge this (and any messages received after it) by sending an acknowledgement that carries the current left window edge ๐Ÿ“. That way, whether it's lost data messages or lost acknowledgements, the protocol stays synchronized ๐Ÿ’œ.

The main difference between this protocol and the IFIP Protocol is the size of the sequence number field ๐ŸŽ€. The IFIP Protocol is built for interconnecting many networks with huge variations in delay, and where messages might not arrive at the destination in the same order the source sent them. So IFIP uses a 16-bit sequence number field, which, even at megabit-per-second rates, can't be completely cycled through in less than several hours โฐ. The proposed ARPANET-type network is different though: delays are typically short, messages are rarely lost, and they're always delivered in the same order they were sent, if they're delivered at all ๐Ÿ‘‘. So this Host/Host Protocol uses only a 4-bit sequence number field, which cycles through every 16 messages ๐Ÿ”ฅ. That imposes a constraint: a window may never be larger than eight messages ๐Ÿ™…. Since the sequence number lives in a 4-bit field, it's also possible to use only four bits each for the credit and acknowledgement fields. That means this protocol uses only 12 bits in each message header, instead of the 40 bits used under the IFIP Protocol ๐Ÿ’…โœจ.

III. NCP Functions ๐Ÿงš

The NCP's functions are to establish connections, terminate connections, control flow, transmit interrupts, and respond to test inquiries ๐Ÿฆ‹. This section explains these functions, and control commands get introduced as they're needed. In Section IV, the formats of all control commands are presented together ๐Ÿ“–.

Connection Establishment ๐Ÿ’–

The command used to establish a connection is the RFC (request for connection) ๐ŸŒˆ.

          8*       16           16           8        16       8
      ----------------------------------------------------------------
      !  RFC  ! my-socket ! your-socket !  Index  !  size  ! credit  !
      ----------------------------------------------------------------
* The number shown above each control command field is the length of that field in bits.

The RFC command is the ultimate "wanna connect?" ๐Ÿ’Œ and also the "yes, I accept" ๐Ÿซถ, because the same command does both jobs. That means either of two cooperating processes can start a connection. And if both of them send an RFC at the exact same moment, each one reads the other's RFC as a yes to its own, so the connection just happens with zero drama ๐Ÿ’…โœจ

The my-socket and your-socket fields tell each Host which sockets sit at the two ends of the connection ๐ŸŽ€. The index field is a number that shows up in every data transmission sent from the "my-socket" end to the "your-socket" end ๐Ÿฆ‹. The size field is the biggest number of 8-bit bytes the "your-socket" end is allowed to send to the "my-socket" end in one message ๐ŸŒธ. The credit field sets the starting size of the window in the "your-socket" to "my-socket" direction, and it has to be in the range 0-7 ๐Ÿงš. Two RFCs match when one Host's my-socket equals the other's your-socket, and vice versa. Once a matching pair has been swapped, the connection is established ๐Ÿ’–

Connections are identified by their sockets, so one pair of socket numbers can never point to two different connections at once ๐Ÿ™ˆ. The same logic goes for index: it says which connection a data message belongs to, so an index value can't be reused while its connection is still active or still being set up ๐Ÿ”ฅ. Let's say Host A sends an RFC to Host B with my-socket = X, your-socket = Y, and index = Z. Until that connection is closed (even if it never got established) or reinitialized, Host A is NOT allowed to send Host B a different RFC with my-socket and your-socket set to X and Y, or with index set to Z. The X and Y pair is treated as a unit. So Host A can still send an RFC with my-socket = X as long as your-socket is some value other than Y โœจ

There's no fixed lifetime for an RFC ๐Ÿ•ฐ๏ธ. A Host can hold onto incoming RFCs and wait forever before answering, or it can reject them right away if it hasn't already sent a matching RFC. Of course, the Host that sent the RFC might not want to wait forever, so it can give up on the request ๐Ÿ™ƒ

Whether a Host queues incoming RFCs or not is a big deal, so don't ignore it ๐Ÿšจ. Every queued RFC takes up a little memory on the queuing Host ๐Ÿง . If an RFC gets queued until a local process grabs the socket and accepts or rejects it, but no local process ever shows up, that RFC just sits in the queue "forever" ๐Ÿ’€. On the flip side, if nothing gets queued at all, the cooperating processes might only manage to connect by accident ๐Ÿ˜ญ

The most sensible fix is for each NCP to give its own Host's processes two ways to start connections ๐Ÿ‘‘. Option one: a process asks for an RFC to be sent to a specific remote socket, and the NCP tells the process whether the remote Host accepted or rejected it ๐Ÿ“ฎ. Option two: a process tells its NCP to "listen" for an RFC aimed at a specific local socket, coming from some remote socket (the process can also name a particular remote socket and/or Host it wants to talk to). When one arrives, the NCP accepts it by sending back a matching RFC ๐Ÿฆ‹. Listening does involve queuing, but it's internal queuing, which the local Host can manage sensibly ๐ŸŒˆ

Connection Termination

The command for ending a connection is CLS (close) ๐Ÿ‘‹.

          8         16          16
      -----------------------------------
      !  CLS  ! my-socket ! your-socket !
      -----------------------------------

The my-socket and your-socket fields of a CLS command name the sockets at the ends of the connection being closed ๐ŸŽ€. Both sides MUST send and receive a CLS command before the termination is complete. Only then are the restrictions on reusing the socket pair and the index value lifted ๐Ÿ”“

Closing doesn't need the connection to be fully set up first (meaning both RFCs were swapped) โœจ. For example, if a Host doesn't want a connection request, it sends back a CLS instead of a matching RFC ๐Ÿ™…โ€โ™€๏ธ. Then it waits for the initiating Host to confirm the refusal by sending a CLS back ๐Ÿ’Œ. Same deal if a Host wants to cancel its own pending request: it sends a CLS, and the foreign Host is OBLIGED to acknowledge with its own CLS ๐Ÿซถ. Even though the connection was never established, CLS commands MUST be exchanged before the socket pair and index are fully free again ๐Ÿ”ฅ. Under normal conditions, a Host SHOULD NOT send a CLS for a connection where it still has unacknowledged data waiting ๐Ÿ™…โ€โ™€๏ธ. The other Host might have just sent data, so the CLS sender could still get more data coming its way ๐Ÿ“ฆ

A Host SHOULD acknowledge an incoming CLS quickly so the foreign Host can clean out its tables ๐Ÿงน. Specifically, when there's no unacknowledged data outstanding, a Host MUST acknowledge an incoming close within 60 seconds โฑ๏ธ. After that 60-second window, the Host that sent the CLS can treat the socket pair and index as "unused" and delete those values from any tables tracking active connections ๐Ÿ—‘๏ธ. Of course, if the foreign Host is broken in a way that makes it ignore the CLS for more than 60 seconds, later attempts to set up connections or send data could give confusing results ๐Ÿ˜ต. To avoid that, a Host SHOULD generally "reinitialize" its connection parameters before trying to set up a new connection with any Host that didn't respond to a CLS ๐Ÿ”„. Ways to reinitialize the connection parameter tables are described below ๐Ÿ‘‡

Acknowledgement

As mentioned in the previous section, flow control runs on a windowing scheme built on sequence numbers ๐ŸชŸ. Credits and acknowledgements can ride along on data traveling the reverse way, so most acknowledgements happen over the data connection instead of the control connection ๐Ÿš—. Still, there are times when it's useful to send acknowledgements over the control connection, like when nothing is going back in the reverse direction ๐Ÿ’ฌ. It can also be efficient to send a negative acknowledgement for data that's known not to have arrived, instead of waiting for the timeout and retransmission to resend it ๐Ÿƒโ€โ™€๏ธ. [Negative acknowledgement is not REQUIRED, since timeout and retransmission is always enough to guarantee eventual delivery of all data, but it MAY be used to improve efficiency.] Over an ARPANET-type network, negative acknowledgements are super rare, so it would be wasteful to reserve space for them in the header of every data message ๐Ÿ™ˆ. The cleanest approach is to handle negative acknowledgements with control messages ๐ŸŽ€

There are two acknowledgement commands ๐ŸŒธ.

          8       8       4       4
      ---------------------------------
      !  ACK  ! index !  seq  !  crd  !
      ---------------------------------

The ACK (acknowledgement) command carries three data fields ๐Ÿ’–. The index value is the index the sender uses to identify the connection. The seq field holds the sequence number of the highest-numbered sequential data message that was received correctly over the connection ๐Ÿ“ฌ. [The very first data message on a newly established connection gets sequence number one. Until that message is received correctly, any acknowledgement commands sent for this connection (for example, to change the credit value) MUST have the seq field set to zero. This applies whether the "acknowledgement" comes in an ACK command or is contained in data messages sent to the foreign Host over the connection.] The crd field holds a number in the range 0-7 that gives the size of the receive window ๐ŸชŸ. Add that number to seq and you get the sequence number of the highest-numbered message the foreign Host is allowed to send. So a credit of zero means the transmitting Host can't accept any messages over the connection right now ๐Ÿ™…โ€โ™€๏ธ, and a credit of 7 means it can accept up to 7 messages ๐Ÿ™Œ. Since the sequence number lives in a 4-bit field, adding seq and the credit value MUST be done modulo 16, so sequence number zero comes right after sequence number 15 ๐Ÿ”

The ACK command is meant for data connections where data only flows one way, like sending a file to a line printer ๐Ÿ–จ๏ธ. Control messages aren't synchronized with data messages, either in the network or, more importantly, in the transmitting NCP ๐Ÿ˜ตโ€๐Ÿ’ซ, so ACK commands SHOULD NOT be sent for a connection where data is flowing in the same direction ๐Ÿšซ. So if an ACK command gets generated, the NCP sending it MUST make sure that the control message containing it goes out before any new data messages for the same connection ๐Ÿ

          8        8       8
      --------------------------
      !  NACK  ! index !  seq  !
      --------------------------

The NACK is the sender's little "hey, this one didn't land" ๐Ÿ’Œ, and it is totally optional, so the protocol works fine without it โœจ. It carries two data fields. The first is the index number that the NACK's sender assigned to this connection, same as with the positive acknowledgement we just covered ๐ŸŽ€. The second field holds only the 4-bit sequence number of the data message being negatively acknowledged, right justified in an 8-bit field ๐ŸŒธ.

The NACK is meant for when the window width is greater than one, the message at the left window edge didn't arrive correctly, and messages further to the right did arrive correctly ๐Ÿฆ‹. A timeout will eventually retransmit the missing message, and once that happens the left window edge can jump forward several messages ๐Ÿ’…. The NACK can speed things up, though, because it could trigger the immediate retransmission of the missing message and cut down on the delay ๐Ÿ”ฅ. If more than one message is missing, it may be worth sending several NACKs for one index in a single control message. The protocol allows this, but it is extremely unlikely to happen ๐Ÿ™ˆ.

Re-initialization

Okay so sometimes things go sideways ๐Ÿ˜ญ. Control messages get lost, systems crash, NCP errors happen, and communication between two NCPs gets disrupted ๐Ÿ’€. One possible result is that neither NCP can be sure that what it has stored about connections with the other Host still matches what the other NCP has stored ๐Ÿซ . When that happens, an NCP may want to reinitialize its tables and ask the other Host to do the same ๐Ÿงน. This re-initialization can be requested for a particular index and/or socket pair, or globally for all connections that might have been established with the other Host ๐ŸŒ. The protocol gives us three control commands for this, and we'll go through them below ๐Ÿซถ.

        8        16           16          8
    -------------------------------------------
    !  RCP  ! my-socket ! your-socket ! index !
    -------------------------------------------

The RCP (reinitialize connection parameters) command has three data fields ๐ŸŽ€. The my-socket and your-socket fields hold a pair of socket numbers that define a connection, and the index field holds a value that would identify data messages over a connection ๐Ÿฆ‹. When an NCP receives this command, it should purge its tables of any reference to a connection identified by that socket pair, or any reference to a connection for which received data would be identified by the specified index value ๐Ÿงš. Only connections using these values with the Host that sent the RCP get purged, though ๐Ÿ”’. Basically, the Host sending the RCP is saying: "I am about to send you an RFC using this socket pair and this index to identify a data connection, which I hope we can agree to establish. I do not believe that any use of this socket pair or this index conflicts with any previous use, but if you believe it does, please record the fact (for later examination) as an error and then delete from your tables the conflicting information so that we may proceed to establish the connection." ๐Ÿ’–

In case things are more globally broken or state information is lost, the protocol has a pair of control commands, RST (reset) and RRP (reset reply) ๐ŸŒˆ.

        8
    ---------
    !  RST  !
    ---------

        8
    ---------
    !  RRP  !
    ---------

When the Host receiving an RST gets it, that Host should treat it as a signal to purge its tables of any entries that came from communication with the Host that sent the RST ๐Ÿงน. The Host sending the RST should likewise purge its tables of any entries that came from communication with the Host the RST was sent to ๐Ÿ’œ. The Host receiving the RST should acknowledge it by returning an RRP ๐Ÿซถ. Once the first Host has sent an RST to the second Host, the first Host should not communicate with the second Host (except for responding to RST) until the second Host returns an RRP ๐Ÿ™…โ€โ™€๏ธ. If both NCPs decide to send RSTs at about the same time, each Host will receive an RST, and each must answer with an RRP even though its own RST hasn't been answered yet ๐Ÿ‘ฏโ€โ™€๏ธ.

A Host should not send an RRP when no RST has been received ๐Ÿšซ. Also, a Host should send only one RST (and no other commands) in a single control message, and it should not send another RST to the same Host until either 60 seconds have passed or a command that is not an RST or RRP has been received from that Host โณ. Under these conditions, a single RRP counts as an answer to all RSTs sent to that Host, and any other RRPs arriving from that Host should be discarded ๐Ÿ—‘๏ธ.

Interrupts

Sometimes a communication system has to go around its flow control when serious errors or other important conditions show up ๐Ÿšจ. Think about a user on a time sharing terminal who starts a program that has an erroneous infinite loop in it ๐Ÿ”. That user may need to "attract the attention" of the operating system so it will cancel the program, even though the OS normally only "listens" to the terminal when the running program asks for input ๐Ÿ˜ค. Likewise, in a computer communication network, flow control can block data from moving from one process to another, and under certain extraordinary conditions it may be necessary to pass a signal from one process to another โšก. The channel between the NCPs of two Hosts isn't subject to the flow control mechanisms that apply to the data connections, so it's possible to send this kind of "out-of-band" signal over the control connection ๐Ÿ›ธ. The INT (interrupt) command exists for exactly this purpose ๐Ÿ‘‘.

        8       8       8
    -------------------------
    !  INT  ! index !  seq  !
    -------------------------

The INT command has two data fields ๐ŸŽ€. The index field identifies the data connection the "interrupt" is about ๐Ÿงต. The sequence number ("seq"), which is four bits right-justified in an eight-bit field, gives the sequence number of the first data message that should "come after" the interrupt ๐Ÿ”ข. In other words, the INT command tells the receiving NCP about an exception condition that has to be synchronized with the data stream, and the sequence number provides that synchronization ๐ŸŽฏ. Any data messages with sequence numbers to the left of the specified sequence number were generated before the exception condition arose ๐Ÿ•ฐ๏ธ.

An NCP that receives an INT command should advance the right window edge of the specified data connection so the window contains at least the sequence number given in the interrupt command ๐ŸชŸ. (It may be necessary to acknowledge data messages that weren't received correctly or weren't buffered in order, so the window can reach that point. The justification is that the INT was only sent because flow control was blocking the transmission of important information ๐Ÿซฃ.) Of course, the interrupt or exception signal itself is up to the interpretation of the Host that receives it, but it should have a meaning equivalent to: "notify the process in execution, or that process' superior, that something exceptional has happened and that the data now buffered is an important message." ๐Ÿ“ฃ

Test Inquiry

Sometimes it's useful for one Host to check whether another Host is still carrying on network conversations ๐Ÿ”. The control command for this is ECO (echo) ๐Ÿชž.

        8       8
    ------------------
    !  ECO  !  data  !
    ------------------

The data field of the ECO command can hold any bit configuration the sending Host chooses ๐ŸŽจ. When an NCP receives an ECO command, it should respond by returning the data to the sender in an ERP (echo reply) command ๐Ÿ“.

        8       8
    ------------------
    !  ERP  !  data  !
    ------------------

A Host should respond to an incoming ECO command with an ERP command within a reasonable time, which here means sixty seconds or less โฐ. A Host should not send an ERP when no ECO has been received ๐Ÿ™…โ€โ™€๏ธ.


IV. DECLARATIVE SPECIFICATIONS โœจ

Message Format

All Host-to-Host messages that conform to this protocol shall be constructed as follows ๐Ÿ“‹:

Bits 1-96: Leader - This field is as specified in BBN Report No. 1822, with the following additional specifications ๐Ÿงพ.

Bits 38-40: Maximum Message Size - This field should be zero for all control messages 0๏ธโƒฃ. For messages sent over data connections, the value of this field should be calculated from the size received in the RFC that established the connection ๐Ÿ“.

Bits 65-76: Message-id - This field is subdivided into eight bits giving the index of the connection that the message is part of, and four bits giving the sequence number of the message ๐Ÿงฉ. The index is in bits 65-72, and the sequence number is in bits 73-76 ๐Ÿ”ข.

Bits 97-100: Acknowledgement - This field contains the four-bit sequence number of the highest-numbered data message to the left of the window for this connection ๐ŸชŸ. That is, it's the sequence number identifying the highest-numbered of the consecutively numbered data messages (none missing) that have been correctly received over this connection ๐Ÿ’ฏ. If no data messages have been received since the connection was established, this field must contain the value zero 0๏ธโƒฃ. This field is not used (so it may have any value) in control messages ๐Ÿคทโ€โ™€๏ธ.

Bits 101-104: Credit - This field contains a number in the range 0-7 ๐ŸŽŸ๏ธ. Adding this number (modulo 16) to the sequence number in the acknowledgement field (bits 97-100) gives the highest sequence number the foreign Host is permitted to send over this data connection ๐Ÿšฆ. So a value of zero here means no new data messages should be sent, and a value of seven means the foreign Host may send up to seven messages beyond the message whose sequence number is in the acknowledgement bits ๐Ÿš€. Since flow control doesn't apply to messages sent over the control connection, this field may have any value in control messages ๐Ÿซถ.

Bits 105 - ... : Text and padding - A sequence of 8-bit bytes of text, followed by padding, as specified in BBN Report No. 1822 ๐Ÿ“.

Index Assignment

Index values must be assigned (in bits 65-72) as follows ๐Ÿ—‚๏ธ:

 Number     Assignment

      0     Identifies a control connection

      1     Reserved for revisions to this protocol

  2-191     Identify data connections

192-255     Reserved for expansion or for other protocols

Sequence Number Assignment

Sequence Numbers โœจ

Okay so every data message carries a sequence number in bits 73-76 ๐ŸŽ€ The receiver uses it to spot when a message has gone missing, to slot a resent message (which is probably out of order, bestie) into the right spot in the stream, or to recognise a resend as a duplicate ๐Ÿ™ˆ It also tells the sender which messages got acknowledged, and flow control uses it too ๐Ÿ’… The IMP subnetwork already has its own elaborate machinery for these exact goals, so the sequence-number error recovery probably won't get used much. Its efficiency isn't the main priority, which is very chill of it ๐Ÿงš

Each direction of a connection gets its own sequence numbers, totally independent of the other direction ๐Ÿ’œ For a given direction, the very first data message sent after the connection is established MUST have sequence number one ๐Ÿ‘‘ After that, numbers go up in order, modulo 16, so the message after number 15 wraps back around to zero ๐Ÿ”„

Control messages don't get sequence numbers at all ๐Ÿฆ‹ The protocol is built so they can arrive out of sequence without causing any trouble, and flow control can't be applied to the control link anyway, so it's a no-brainer โœจ

Control Messages

Control messages look just like other Host-to-Host messages, minus the exceptions we already covered ๐ŸŒธ But they MUST NOT contain more than 120 8-bit bytes of text ๐Ÿ™…โ€โ™€๏ธ They also MUST contain a whole number of control commands. A single control command MUST NOT get split across different control messages, so no chopping commands in half, periodt ๐Ÿ’€

Message Transmission and Retransmission

Control messages MAY be sent whenever they're needed ๐Ÿ’– Data messages are stricter. They MAY only be sent when flow control allows it, which means the sequence number has to sit inside the "window" for that direction of the connection ๐ŸชŸ

Here's the window math, and it's giving precise ๐Ÿค“ The "left window edge" (LWE) is the highest sequence number (modulo 16) that's been acknowledged, or zero if nothing has been acknowledged yet. The "right window edge" (RWE) is the left window edge plus the most recently received credit, again modulo 16. [Heads up: LWE=RWE if the most recently received credit is zero โœจ] A message with sequence number SEQ MAY only be sent if, before the (possible) reduction modulo 16 of SEQ and/or RWE, this holds:

   LWE less-than SEQ less-than-or-equal RWE

Messages SHOULD be retransmitted whenever any of these happen ๐Ÿ”

  • The IMP subnetwork sent back an "Incomplete transmission" (type 9) or "Error in Data" (type 8) response to the message. You can tell it's the right message because bits 41-76 of the response match those bits of the transmitted message. This applies to control messages too, not just data ๐Ÿซถ
  • The message's sequence number is LWE + 1, and it's been more than 30 seconds since the message was last sent โฐ
  • The foreign Host's NACK command for this connection names this message's sequence number specifically ๐Ÿ™‹โ€โ™€๏ธ

Since messages might need resending, they SHOULD NOT be thrown away by the sending NCP until they've been acknowledged ๐Ÿ—‘๏ธ๐Ÿšซ A message counts as acknowledged when its sequence number, or the sequence number of any message to its right in the same direction of the connection, comes back in the acknowledgement field of a data message sent the other way. It also counts if it comes back in an ACK command for this connection from the foreign Host ๐Ÿ’…

Control Commands

Control commands are built out of 8-bit bytes ๐Ÿ“ Every command starts with a one-byte opcode. Opcodes are handed out as the sequential values 0, 1, 2, ... so the receiver can just look them up in a table ๐Ÿ” The reasoning behind the design and expected use of these commands is covered in Section III, so go check that if you're curious ๐Ÿ“–

NOP - No Operation

              8
          ---------
          !  NOP  !
          ---------

NOP can be sent at any time, and the receiver SHOULD discard it ๐Ÿซง It's handy for padding out control messages to the right shape ๐Ÿง

RST - Reset

              8
          ---------
          !  RST  !
          ---------

RST is how one Host tells another to purge all info about any earlier connections between the two Hosts from the NCP tables of the Host that receives the RST ๐Ÿงน Aside from answering RSTs, the Host that sent the RST SHOULD NOT talk to the other Host again until it gets an RRP back ๐Ÿ™…โ€โ™€๏ธ Also, when a Host is about to start talking to another Host it has no open connections with (like sending an RFC command), it's good practice to send an RST first and then wait for an RRP ๐ŸŒท

RRP - Reset Reply

              8
          ---------
          !  RRP  !
          ---------

RRP MUST be sent in reply to an RST command ๐Ÿ’Œ

RFC - Request for Connection

         8       16           16          8      16      8
      ---------------------------------------------------------
      ! RFC ! my-socket ! your-socket ! index ! size ! credit !
      ---------------------------------------------------------

RFC is how you set up a connection ๐ŸŽ€ The "my-socket" field is the socket on the Host sending the RFC, and the "your-socket" field is the socket on the Host it's being sent to ๐Ÿ”Œ The "index" field is the index value that will show up in bits 65-72 of every data message going from "my-socket" to "your-socket" ๐Ÿท๏ธ The "size" field is the largest number of 8-bit bytes allowed in any single message from "your-socket" to "my-socket" ๐Ÿ“ And the "credit" field sets the size of the starting sequence number window (somewhere in 0-7) for the "your-socket" to "my-socket" direction ๐ŸชŸ

CLS - Close

              8        16           16
          -----------------------------------
          !  CLS  ! my-socket ! your-socket !
          -----------------------------------

CLS ends a connection ๐Ÿ‘‹ The connection doesn't have to be fully set up before you send CLS, so you can bail anytime ๐Ÿฆ‹

RCP - Re-Initialize Connection Parameters

              8        16           16          8
          -------------------------------------------
          !  RCP  ! my-socket ! your-socket ! index !
          -------------------------------------------

RCP is how one Host says to the other: wipe all info about any possibly existing connection between "my-socket" and "your-socket" AND all info about any possibly existing connection identified by "index" between these Hosts ๐Ÿงผ Those tables SHOULD be purged on the receiving Host โœจ The "my-socket", "your-socket", and "index" fields work exactly like they do in the RFC command ๐Ÿชž

ACK - Acknowledgement

              8       8       4       4
          ---------------------------------
          !  ACK  ! index !  seq  !  crd  !
          ---------------------------------

ACK can be used to acknowledge received data, or to hand out credit, without sending a data message ๐Ÿ’ซ The index field points at the data connection that uses that same index value (in the direction from the ACK's sender to its receiver) ๐Ÿ”— The next eight bits, the "seq" and "crd" fields, mean the same thing as bits 97-104 of the data message that the index value identifies ๐Ÿค

NACK -- Negative Acknowledgement

              8        8       8
          --------------------------
          !  NACK  ! index !  seq  !
          --------------------------

NACK tells the receiver of the NACK that it should immediately resend the data message named by the other fields ๐Ÿšจ The index field works exactly like it does in the ACK command ๐Ÿ” The "seq" field gives the 4-bit sequence number (right-justified) that should be resent right away ๐ŸŽฏ Heads up, though: the message being resent doesn't have an index value equal to "index". It travels the other direction of the data connection, which the Host sending the NACK identifies using "index" ๐Ÿ”„ No Host is ever REQUIRED to send or act on a NACK command ๐Ÿ™…โ€โ™€๏ธ Still, using NACK may occasionally cut down on retransmission delay โšก

INT - Interrupt

              8       8       8
          -------------------------
          !  INT  ! index !  seq  !
          -------------------------

INT goes over the control link to deliver an "out-of-band" signal for the data connection named by the index field. Being out-of-band, it isn't subject to flow control, which is a whole mood ๐ŸŒˆ The index value is the one that would appear in bits 65-72 of a data message sent from the INT's sender to its receiver ๐Ÿท๏ธ To sync this signal with the data flowing over the connection, the "seq" field carries a 4-bit sequence number (right-justified) ๐ŸŽฏ That number marks the first data message that "follows" the out-of-band signal ๐Ÿซถ

ECO - Echo Request

              8       8
          ------------------
          !  ECO  !  data  !
          ------------------

ECO is only for testing ๐Ÿงช The data field MAY be any bit pattern that's convenient for the Host sending the ECO ๐Ÿซง

ERP - Echo Reply

              8       8
          ------------------
          !  ERP  !  data  !
          ------------------

ERP MUST be sent in reply to an ECO command ๐Ÿ’Œ Its data field MUST be identical to the data field in the incoming ECO command ๐Ÿชž

Opcode Assignment

Opcodes are 8-bit unsigned binary numbers ๐Ÿ”ข Here are the values assigned to opcodes ๐Ÿ’–

    NOP  =  0

    INT  =  1

    RFC  =  2

    CLS  =  3

    ACK  =  4
    NACK =  5

    RCP  =  6

    RST  =  7

    RRP  =  8

    ECO  =  9

    ERP  = 10

     [ This RFC was put into machine readable form for entry ]
     [ into the online RFC archives by Alex McKenzie with    ]
     [ support from BBN Corp. and its successors.     7/2000 ]
๐Ÿ“ฆ where this page comes from