RFC 714
Host-Host Protocol for an ARPANET-Type Network
๐ 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):
- 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.
- 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.
- 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.
- 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
- ietf: rfc714 1976-04
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms