RFC 215

NCP, ICP, and Telnet: The Terminal IMP implementation

πŸ“… published August 1971, from ietf

NCP, ICP, and TELNET: The Terminal IMP Implementation πŸ¦‹

Okay bestie, this is RFC 215 πŸ’– Network Working Group, written by A. McKenzie at BBN (NIC #7545) on 30 August 1971. It's filed under Categories: C.2, D.1, D.3, G.1, it updates none of the earlier RFCs, and it obsoletes none ✨ So it's a fresh start, not a replacement.

By early December there will be six Terminal IMPs in the network, and more are coming about one per month after that 🌸 That's why people in the network community will be curious how the protocols got implemented (and where they got bent a little). This note covers the choices the Terminal IMP system programmers made wherever the protocols allowed a choice, and it calls out some spots where the implementation doesn't follow the protocols πŸ’…

Most of the choices here were driven by storage limits, and honestly it's giving tiny-box energy πŸ“¦ The Terminal IMP has no bulk storage for buffering. It only has 8K of 16-bit words for device I/O buffers and program together. It has to drive up to 64 terminals, and those are a mix of terminal types with different code sets and communication protocols (the IBM 2741 terminals, for example) πŸ–₯️ On top of that, the Terminal IMP needs a basic language processor so a terminal user can set parameters for their network connections. It also has to be ready to keep 128 (simplex) network connections going at any time. So every word stored in the NCP tables on a per-connection basis eats a big chunk of the Terminal IMP's memory. Yikes 😭

Remember, the Terminal IMP exists to give its users access to the network, not to serve the rest of the network 🧚 So it doesn't include programs for the "server" side of the ICP. It doesn't even have a "logger" socket. Not me being the main character of the network and not showing up for anyone else πŸ™ˆ

Right now the Terminal IMP program only implements the NCP, the ICP, and the TELNET protocol, because those are what the Terminal IMP sites care about most ✨ Some of the data transfer protocol is expected to be added later. The exact pieces aren't locked in yet, but they'll probably include the infinite bit stream (first) and the "transparent" mode (later). More on data transmission protocol will get documented down the road 🌈

The rest of this note explains, and tries to justify, the deviations from the official protocols and the other design choices that are worth knowing about. It's written in the present tense, but there are a few more known deviations from protocol that will be fixed soon, so keep that in mind πŸ’œ


A) Deviations from Protocols

1) The Terminal IMP does not guarantee a correct response to ECO commands 😬 Say a Host A sends a control message with ECOs in it to the Terminal IMP, and the message shows up at a time when:

  • a) the Terminal IMP has a free buffer, and
  • b) the control link from the Terminal IMP to Host A is not blocked,

then the Terminal IMP will generate a correct ERP for each ECO. In every other case, the ECO commands get discarded. (Every control message the Terminal IMP sends starts with a NOP control command, so if Host A sends a control message made of 60 ECO commands, the Terminal IMP will answer (if at all) with a 121-byte message -- 1 NOP and 60 ERPs. πŸ“)

The reason for doing it this way is that guaranteeing a correct response to ECO in every case would need infinite storage. Picture this: Host A sends control messages, each with an ECO command, to Host B at a rate of one per second, but Host A takes in messages from the network as slowly as possible (one every 39 seconds, say). Then Host B only has three options that don't break the protocol:

  • a) Declare itself dead to the network (in other words, turn off its Ready line), which denies all of its users any use of the network.
  • b) Refuse to accept messages from the network any faster than the slowest possible foreign Host (about one every 39 seconds). If Host B is a Terminal IMP, this is almost certainly slow enough to soon reach a steady state of no users.
  • c) Implement "infinite" storage for buffering messages.

Since none of the "legal" solutions are possible, we decided to do no buffering, which should (we guess) satisfy the protocol well over 99% of the time πŸ’…βœ¨

2) The Terminal IMP does not guarantee to issue CLS commands in response to "unsolicited" RFCs πŸŽ€ There are currently several ways to "solicit" an RFC, as follows:

  • a) A terminal user can tell the Terminal IMP to perform the ICP to the TELNET Logger at some foreign Host. This action "solicits" the RFCs defined by the ICP.
  • b) A terminal user can send an RFC to any particular Host and socket they choose. This "solicits" a matching RFC.
  • c) A terminal user can set their own receive socket "wild." This action "solicits" an STR from anyone to their socket. Similarly, the user can set their send socket "wild" to "solicit" an RTS.

If the Terminal IMP receives a "solicited" RFC, it handles it according to the protocol, no notes πŸ’– If the Terminal IMP receives a control message containing one or more "unsolicited" RFCs, it will either issue CLS commands or ignore the RFCs, following the same criteria described above for answering ECOs (and for the same reasons). Also, if the Terminal IMP does issue a CLS in response to an unsolicited RFC, it will not wait for a matching CLS before treating the sockets involved as free for other use 🫢

3) After issuing a CLS for a connection, the Terminal IMP will not wait forever for a matching CLS 😀 There are two cases:

  • a) The Terminal IMP has sent an RFC, grown tired of waiting for a matching RFC, and therefore issued a CLS.
  • b) The Terminal IMP has sent a CLS for an established connection (matching RFCs exchanged).

In either of these cases, the Terminal IMP will wait for a matching CLS for a "reasonable" time (probably 30 seconds to one minute), and then it will "forget" the connection. Once the connection is forgotten, the Terminal IMP will treat both sockets involved as free for other use 🌸

Because of program size and table size restrictions, the Terminal IMP assigns socket numbers to a terminal as a direct function of that terminal's physical address 🧩 So with this socket assignment scheme, if some foreign Host fails to answer a CLS, a terminal could be permanently "hung." Someone might argue that the Terminal IMP could send a RST to the offending Host, but that would also break the connections of other terminal users who might be doing useful work with that Host. Not a vibe πŸ’€

4) The Terminal IMP ignores all RET commands πŸ™…β€β™€οΈ The Terminal IMP can't buffer very much input from the network to a given terminal because of core size limits. So the Terminal IMP only allocates one message and a very small number of bits (currently 120 bits; eventually some number in the range 8-4000, based on the terminal's speed) on each connection where the Terminal IMP is the receiver. With allocations this small, the Terminal IMP tries to keep the usable bandwidth as high as it can by sending a new allocation, which brings the total allocation up to the maximum amount, each time that:

  • a) one of the two buffers assigned to the terminal is empty, and
  • b) the allocations are below the maxima.

So if a spontaneous RET came in, the reasonable move for the Terminal IMP would be to immediately issue a new ALL. But if a foreign Host had some reason for sending a first spontaneous RET, it would probably send a second RET as soon as it got the ALL. That could easily lead to an infinite (and very rapid) RET-ALL loop between the two machines, chewing through a big chunk of the Terminal IMP's bandwidth. Since the Terminal IMP can't "afford" to talk to a Host like that, it ignores all RETs πŸ›‘

5) The Terminal IMP ignores all GVB commands πŸŒ™ Implementing GVB seems to need an unreasonable number of instructions, and at least for now, no Host appears to use the GVB command. If we did implement GVB, we would always RET all of both allocations, and that doesn't seem very useful ✨

6) The Terminal IMP does not handle a total bit allocation greater than 65,534 (2^16-2) correctly πŸ‘‘ If the bit allocation is ever raised above 65,534, the Terminal IMP will treat the allocation as infinite. This approach lets the Terminal IMP store the bit allocation for each connection in a single word, and it avoids double precision addition and subtraction. Our reasons for this decision are:

  • a) A saving of more than 100 words of memory, which would otherwise be needed for allocation tables and for double precision addition/subtraction routines.
  • b) Our experience, which indicates that very few Hosts (probably one at most) ever raise their total bit allocation above 65,534 bits.
  • c) Our expectation that any Host which ever raises its bit allocation above 65,534 would probably be willing to issue an infinite bit allocation if the protocol provided one. Once the bit allocation is greater than about 16,000, the message allocation (which the Terminal IMP handles correctly) is a more powerful way of controlling network loading on a Host system than bit allocation. We believe that Hosts with loading problems will recognize this 🧚

7) The Terminal IMP ignores the "32-bit number" in the ICP πŸ¦‹ When the Terminal IMP (the "user site") starts the Initial Connection Protocol, the actual procedure is to send the required RTS to the logger socket of the user-specified foreign Host, and at the same time set the terminal user's send and receive sockets to a state where each will accept any RFC from the specified Host. The 32-bit socket number sent over the logger connection gets ignored, and the first RTS and STR addressing the user's sockets will be accepted (and answered with matching RFCs) πŸ’–

The ICP lets the foreign Host send RFCs for the Terminal IMP sockets U+2 and U+3 at any time after it gets the RFC to the (foreign Host's) logger socket πŸ’…βœ¨. The RFCs can show up at the Terminal IMP before the 32-bit number does. With a "normal" foreign Host, the first incoming RFCs for sockets U+2 and U+3 come from the sockets the 32-bit number points to, so ignoring the number is no biggie πŸŽ€. A "pathologic" foreign Host is different 😭. It could send a potentially infinite number of "wrong" RFCs involving U+2 and U+3 before the 32-bit number arrives. The Terminal IMP would be required to store that stream while it waits for the number, and then issue CLS commands for all the "wrong" RFCs. But the Terminal IMP doesn't have infinite storage, and honestly it's doubtful a terminal user even wants to chat with a pathologic foreign Host πŸ™ˆ. So the Terminal IMP just assumes the foreign Host is "normal" and ignores the 32-bit number πŸ’€.

  1. The Terminal IMP ignores incoming ERR commands and does not output ERR commands.
  2. The Terminal IMP assumes incoming messages have the format and contents demanded by the relevant protocols. For example, the byte size of incoming TELNET messages is assumed to be 8 🧚. The major checks the Terminal IMP does make are:
    • a) If an incoming control message has a byte count greater than 120, then it is discarded.
    • b) If a control command opcode greater than 13 is found during the processing of a control message, then the remainder of the control message is discarded.
    • c) If an incoming data message has a byte count indicating that the bit allocation for the connection is exceeded (based on the assumed byte size), then the message is discarded.
  3. If one control message contains several RST commands, only one RRP is transmitted. If several control messages, each containing RST commands, arrive "close together", only one RST is returned. [The actual implementation is to set a bit each time a RST is found (in "foreground") and to reset the bit when a RRP is sent (in "background").] πŸ¦‹
  4. Socket numbers are preassigned based on the hardware "physical address" (in the terminal multiplexing device) of the terminal. The high order 16 bits of the socket number give the device number (in the range 0-63), and the low order bits are normally 2 or 3 depending on the socket's gender (zero is also used during ICP) 🌸. [We would be pleased to see socket number length reduced to 16 bits; in that case the high order 8 bits would be mapped to the device and the low order 8 bits would contain 2 or 3.]
  5. During ICP, with the Terminal IMP as the user site, the Terminal IMP follows the "Listen" option rather than the "Init" option (as described at the top of page 3, NIC #7170). In other words, the Terminal IMP does not issue the RFCs involving sockets U+2 and U+3 except in response to incoming RFCs involving those sockets. In this context, we will mention that the "deadlock" mentioned in NWG-RFC #202 does not exist, since the ICP does not give the server the "Listen" option (see NIC #7170, page 2) πŸ‘‘βœ¨.

[ This RFC was put into machine readable form for entry ] [ into the online RFC archives by Randy Dunlap 5/97 ]

πŸ“¦ where this page comes from