RFC 1795

Data Link Switching: Switch-to-Switch Protocol AIW DLSw RIG: DLSw Closed Pages, DLSw Standard Version 1

๐Ÿ“… published April 1995, from ietf

okay so meet RFC 1795 ๐Ÿฆ‹ It's a Network Working Group doc from April 1995, and the two people behind it are L. Wells (Chair) from the Internetwork Technology Institute and A. Bartky (Editor) from Sync Research, Inc. It's filed as Informational ๐Ÿ’… and it obsoletes RFC 1434. The subtitle is AIW DLSw RIG: DLSw Closed Pages, DLSw Standard Version 1.0 ๐ŸŒˆ


Status of This Memo ๐ŸŒธ

this memo is here to inform the Internet community, so it's not a standard or anything ๐Ÿ™ˆ it does not specify an Internet standard of any kind. distribution is unlimited, so share it with your whole crew ๐Ÿซถ

Abstract ๐Ÿ”ฅ

this RFC is all about using Data Link Switching over TCP/IP ๐Ÿงš the whole point is to get reactions from the Internet community about the proposals inside. ngl the issues might not be directly relevant to the Internet's research problems, but a bunch of researchers and Implementers could still find them super interesting ๐Ÿ’œ

this RFC was made as a joint project of the Advanced Peer-to-Peer Networking (APPN) Implementers Workshop (AIW) Data Link Switching (DLSw) Related Interest Group (RIG) ๐Ÿ‘‘ the APPN Implementers Workshop is sponsored by IBM and is made up of reps from member companies building current and future IBM Networking interoperable products. the DLSw RIG was formed in that forum for a few big reasons: to produce one version of the Switch to Switch Protocol (SSP) that every vendor could implement, to fix the documentation problems in the existing RFC 1434, and to enhance and evolve the protocol with new functions and features โœจ

this document is based on RFC 1434 but has significant changes, so it obsoletes that document ๐ŸŽ€

any questions or comments about this RFC should go to this Internet address: aiw-dlsw@networking.raleigh.ibm.com ๐Ÿ’–

NOTE 1: this is a widely subscribed mailing list, so messages sent there go to all members of the DLSw mailing list ๐Ÿ˜ญ for specific questions about subscribing to the AIW and any of its working groups, email appn@vnet.ibm.com

info about all the AIW working groups and what they're producing can be grabbed with anonymous ftp. you want the file aiwinfo.psbin or aiwinfo.txt from the Internet host networking.raleigh.ibm.com, in the directory aiw ๐Ÿ“

NOTE 2: these mailing lists and addresses are subject to change ๐Ÿ’…

1. Introduction ๐Ÿฆ‹

okay so Data Link Switching (DLSw) is a forwarding mechanism for the IBM SNA (Systems Network Architecture) and IBM NetBIOS (Network Basic Input Output Services) protocols ๐Ÿ’– this doc is the spec for the Switch-to-Switch Protocol (SSP) that Data Link Switches use between each other. it's not full routing, bestie. it does switching at the SNA Data Link layer (that's layer 2 in the SNA architecture) and then encapsulates in TCP/IP so it can travel over the Internet ๐ŸŒธ this RFC covers the frame formats and the protocols for multiplexing data between Data Link Switches. the first version of SSP uses TCP as the reliable transport between Data Link Switches. other transports like OSI TP4 could show up later ๐Ÿ”ฎ

a Data Link Switch (also abbreviated DLSw in this document) can support SNA systems (Physical Unit (PU) 2, PU 2.1 and PU 4) and, optionally, NetBIOS systems. those are attached to IEEE 802.2 compliant Local Area Networks ๐Ÿซง it can also support SNA systems (PU 2, primary or secondary, and PU 2.1) attached to IBM Synchronous Data Link Control (SDLC) links ๐Ÿš‚ for the SDLC ones, the Data Link Switch gives them a LAN appearance, since each SDLC PU is presented to the SSP protocol as a unique MAC/SAP address pair ๐Ÿ’œ for the Token-Ring LAN attached systems, the Data Link Switch shows up as a source-routing bridge ๐Ÿ’… Token-Ring Remote systems that are reached through the Data Link Switch look like they're attached to an adjacent ring. that ring is a virtual ring that exists inside each Data Link Switch โœจ

1.1. Backwards Compatibility with RFC 1434 ๐ŸŽ€

this document has significant changes from RFC 1434 ๐Ÿ™ˆ it does not say how to interoperate with RFC 1434 or with "enhanced" implementations (like the ones that added enter and exit busy flow control) ๐Ÿ˜ญ if you need interop with pre-AIW DLSw RIG standards, the implementer has to look at RFC 1434 and/or the vendor documentation of whichever vendor's implementation they're talking to ๐Ÿซถ

2. Overview ๐ŸŒˆ

okay so Data Link Switching was built to support SNA and NetBIOS in multi-protocol routers ๐Ÿงš SNA and NetBIOS are basically connection oriented protocols, so the Data Link Control procedure they use on the LAN is IEEE 802.2 Logical Link Control (LLC) Type 2 ๐Ÿ’– Data Link Switching also handles SNA protocols over WAN (Wide Area Network) links through the SDLC protocol ๐Ÿš‚

IEEE 802.2 LLC Type 2 was designed assuming the network transit delay would be predictable, because it's a local LAN ๐Ÿ  so its elements of procedure use a fixed timer to detect lost frames. when remote bridging runs over wide area lines (especially slower ones), the network delay gets bigger and can swing a lot depending on congestion ๐ŸŒŠ once the delay goes past the time-out value, LLC Type 2 tries to retransmit. if the frame wasn't actually lost and just got delayed, the LLC Type 2 procedures can get confused ๐Ÿ˜ต and then the link might eventually get taken down if the delay goes past the T1 timer times the N2 retry count ๐Ÿ’€

because LLC Type 2 services are in play, Data Link Switching tackles these bridging problems:

         DLC Time-outs
         DLC Acknowledgments over the WAN
         Flow and Congestion Control
         Broadcast Control of Search Packets
         Source-Route Bridging Hop Count Limits

NetBIOS also uses a lot of datagram services that run on connectionless LLC Type 1 service ๐Ÿ“ for NetBIOS, Data Link Switching handles the last two problems in that list โœจ

the main difference between Data Link Switching and bridging is that for connection-oriented data, DLSw terminates the Data Link Control, while bridging does not ๐Ÿฆ‹ this diagram shows that difference with two end systems running LLC Type 2 services:

Bridging
--------

                 Bridge           Bridge
+------+         +----+           +----+         +------+
| End  | +-----+ |    +-----/     |    | +-----+ | End  |
|System+-+ LAN +-+    |    /------+    +-+ LAN +-+System|
|      | +-----+ |    |  TCP/IP   |    | +-----+ |      |
+------+         +----+           +----+         +------+
   Info----------------------------------------------->
       <-----------------------------------------------RR


Data Link Switching
-------------------

+------+         +----+           +----+         +------+
| End  | +-----+ |    +-----/     |    | +-----+ | End  |
|System+-+ LAN +-+DLSw|    /------+DLSw+-+ LAN +-+System|
|      | +-----+ |    |  TCP/IP   |    | +-----+ |      |
+------+         +----+           +----+         +------+
 Info--------------->   -------------> Info
   <---------------RR                 ------------>
                                      <------------RR

in traditional bridging, the Data Link Control is end-to-end ๐ŸŒธ Data Link Switching terminates the LLC Type 2 connection at the switch. so the LLC Type 2 connections don't cross the wide area network ๐Ÿ™Œ DLSw multiplexes LLC connections onto a TCP connection to another DLSw. so the LLC connections at each end are totally independent of each other ๐Ÿ’… it's the Data Link Switch's job to deliver frames it got from an LLC connection to the other end. TCP is used between the Data Link Switches to guarantee delivery of frames ๐Ÿซถ

because of this design, LLC time-outs are limited to the local LAN (they don't traverse the wide area) ๐Ÿ  the LLC Type 2 acknowledgments (RR's) also don't cross the WAN, which cuts down traffic on the wide area links ๐Ÿ’– for SDLC links, polling and poll response happen locally, not over the WAN ๐Ÿš‚ broadcast of search frames is controlled by the Data Link Switches once they've found where a target system is ๐Ÿ” and finally, switches can now apply back pressure to the end systems for flow and congestion control ๐Ÿ‘‘

only one copy of a Link Protocol Data Unit (LPDU) gets sent between Data Link Switches in SSP messages (XIDFRAME and INFOFRAME) ๐Ÿ˜ค retries of the LPDU get absorbed by the Data Link Switch that receives it ๐Ÿงš the Data Link Switch that sends the LPDU from an SSP message to a local DLC does the retries, in a way that fits the local DLC. this can involve running a reply timer and keeping a poll retry count ๐Ÿ•ฐ๏ธ the length of the timer and the number of retries is an implementation choice based on user configuration parameters and the DLC type โญ

Data Link Switching uses LAN addressing to set up connections between SNA systems ๐Ÿ’œ SDLC attached devices are defined with MAC and SAP addresses so they can talk to LAN attached devices ๐Ÿซง for NetBIOS systems, Data Link Switching uses the NetBIOS name to forward datagrams and set up connections for NetBIOS sessions ๐ŸŽ€ for LLC type 2 connection establishment, SNA systems send TEST (or in some cases, XID) frames to the null (0x00) SAP ๐Ÿ“ NetBIOS systems have an address resolution procedure, based on the Name Query and Name Recognized frames, that's used to set up an end-to-end circuit ๐ŸŒˆ

since Data Link Switching may be implemented in multi-protocol routers, both bridging and switching can be enabled at the same time ๐Ÿฆ‹ SNA frames can be identified by their link SAP. typical SAP values for SNA are 0x04, 0x08, and 0x0C ๐Ÿ’– NetBIOS always uses a link SAP value of 0xF0 โœจ

3. Transport Connection โœจ

okay so Data Link Switches can be used in pairs or all by themselves ๐Ÿซถ

A single DLSw internally switches one data link to another without using TCP (DLC(1) to DLC(2) in the figure below) ๐Ÿ’… This RFC doesn't go into details on how to implement this feature, and it's not a requirement to support this RFC ๐Ÿ™ˆ

A paired DLSw multiplexes data links over a reliable transport using a Switch-to-Switch Protocol (SSP) ๐Ÿฆ‹

   +-------------------------------------------+Switch-to-Switch
   |              DLC Interfaces               | Protocol (SSP)
   |+-----------+   DLC Request  +-----------+ |
   ||   Data    |<---------------|           | |Send SSP Frame
   ||   Link    | DLC Indication |           | |-------------->
   || Control 1 |--------------->|           | |
   |+-----------+                | Data Link | |
   |+-----------+   DLC Request  |  Switch   | |
   ||   Data    |<-------------- |           | |Rec. SSP Frame
   ||   Link    | DLC Indication |           | |<-------------
   || Control 2 | -------------->|           | |
   |+-----------+                +-----------+ |
   |            Multi-Protocol Router          |
   +-------------------------------------------+

Before Data Link Switching can happen between two routers, they have to set up two TCP connections between them ๐ŸŽ€ Each Data Link Switch keeps a list of DLSw capable routers and their status (active/inactive) ๐Ÿ“‹ Once the TCP connection is up, SSP messages get swapped so the two Data Link Switches can figure out what each other can do โœจ After that exchange wraps up, the DLSw uses SSP control messages to set up end-to-end circuits over the transport connection ๐Ÿ”ฅ Inside that transport connection, DLSw SSP messages keep getting exchanged. The message formats and types for these SSP messages are documented in the following sections ๐Ÿ’œ

The default parameters for the TCP connections between Data Link Switches are:

Socket Family     AF_INET        (Internet protocols)
Socket Type       SOCK_STREAM    (stream socket)
Read Port Number  2065
Write Port Number 2067

Two or more Data Link Switches can be attached to the same LAN, which is made of a bunch of token-ring segments linked together by source-routing bridges ๐ŸŒˆ In this case, no TCP connection is defined between bridges attached to the same LAN. This lets the systems pick one of the possible Data Link Switches, kind of like how they pick a bridge path through a source-routed bridged network ๐Ÿงš The virtual ring segment in each Data Link Switch attached to a common LAN must be configured with the same ring number. This keeps LAN frames sent by one Data Link Switch from getting propagated through the other Data Link Switches ๐Ÿ’€

3.1. SSP Frame Formats ๐Ÿ“ฆโœจ

okay so bestie, these diagrams show the two header formats that Data Link Switches swap with each other: Control and Information. ๐Ÿ’– Control headers are used for every message except Information Frames (INFOFRAME) and Independent Flow Control Messages (IFCM), which go out in Information header format. INFOFRAME, KEEPALIVE and IFCM headers are 16 bytes long, and Control headers are 72 bytes long. ๐ŸŽ€ The first sixteen bytes look exactly the same in every header, so it's giving consistency. ๐Ÿซถ

Control Message (72 bytes):

 CONTROL MESSAGES (72 Bytes)
 (zero based offsets below shown in decimal (xx) )
+-----------------------------+-----------------------------+
| (00) Version Number         | (01) Header Length (= 72)   |
+-----------------------------+-----------------------------+
| (02) Message Length                                       |
+-----------------------------+-----------------------------+
| (04) Remote Data Link Correlator                          |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (08) Remote DLC Port ID                                   |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (12) Reserved Field                                       |
+-----------------------------+-----------------------------+
| (14) Message Type           | (15) Flow Control Byte      |
+-----------------------------+-----------------------------+
| (16) Protocol ID            | (17) Header Number          |
+-----------------------------+-----------------------------+
| (18) Reserved                                             |
+-----------------------------+-----------------------------+
| (20) Largest Frame Size     | (21) SSP Flags              |
+-----------------------------+-----------------------------+
| (22) Circuit Priority       | (23) Message Type (see note)|
+-----------------------------+-----------------------------+
| (24) Target MAC Address  (non-canonical format)           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -|
|                                                           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (30) Origin MAC Address  (non-canonical format)           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -|
|                                                           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|            .                              .               |
+-----------------------------+-----------------------------+
| (36) Origin Link SAP        | (37) Target Link SAP        |
+-----------------------------+-----------------------------+
| (38) Frame Direction        | (39) Reserved               |
+-----------------------------+-----------------------------+
| (40) Reserved                                             |
+-----------------------------+-----------------------------+
| (42) DLC Header Length                                    |
+-----------------------------+-----------------------------+
| (44) Origin DLC Port ID                                   |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (48) Origin Data Link Correlator                          |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (52) Origin Transport ID                                  |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (56) Target DLC Port ID                                   |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (60) Target Data Link Correlator                          |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (64) Target Transport ID                                  |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (68) Reserved Field                                       |
+-----------------------------+-----------------------------+
| (70) Reserved Field                                       |
+-----------------------------+-----------------------------+
         (Even Byte)                     (Odd Byte)

Information Message (16 bytes):

 INFORMATION MESSAGE (16 Bytes)
+-----------------------------+-----------------------------+
| (00) Version Number         | (01) Header Length (= 16)   |
+-----------------------------+-----------------------------+
| (02) Message Length                                       |
+-----------------------------+-----------------------------+
| (04) Remote Data Link Correlator                          |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (08) Remote DLC Port ID                                   |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| (12) Reserved Field                                       |
+-----------------------------+-----------------------------+
| (14) Message Type           | (15) Flow Control Byte      |
+-----------------------------+-----------------------------+
         (Even Byte)                    (Odd Byte)

Both headers share the same first sixteen bytes, so let's break down the fields that matter most. ๐Ÿงš

The Version Number field (offset 0) is set to 0x31 (ASCII '1'), which is decimal 49. That's how you know it's DLSw version 1. ๐Ÿ’…

The Header Length field (offset 1) is 0x48 for control messages, which is 72 bytes. For information and Independent Flow Control messages it's 0x10, which is 16 bytes. ๐Ÿ“

The Message Length field (offset 2) tells you how many bytes are in the data field after the header. ๐ŸŒธ

The Flow Control Byte field (offset 15) is explained in section 8. ๐Ÿฆ‹

The Header Number field (offset 17) is 0x01, which means one. ๐Ÿ’œ

The Circuit Priority field (offset 22) is explained in section 4. โœจ

The Frame Direction field (offset 38) is 0x01 for frames going from the origin DLSw to the target DLSw, and 0x02 for frames going from the target DLSw back to the origin DLSw. ๐Ÿ”ฅ

Note: the Remote Data Link Correlator and Remote DLC Port ID get set to the Target Data Link Correlator and Target DLC Port ID when Frame Direction is 0x01. When Frame Direction is 0x02, they get set to the Origin Data Link Correlator and Origin DLC Port ID instead. ๐Ÿ‘‘

The Protocol ID field is set to 0x42, which is decimal 66. ๐ŸŒˆ

The DLC Header Length is zero for SNA. For NetBIOS datagrams it's 0x23, which is 35 bytes. That 35 bytes covers the Access Control (AC) field, the Frame Control (FC) field, the Destination MAC Address (DA), the Source MAC Address (SA), the Routing Information (RI) field (padded to 18 bytes), the Destination link SAP (DSAP), the Source link SAP (SSAP), and the LLC control field (UI). ๐ŸŽ€

NOTE: the Message Type field values are defined in section 3.5. This value shows up in two different spots in the control header (offset 14 and offset 23 decimal). Only the first one gets used when you parse a received SSP message. New implementations should ignore the second one on reception. It's only still there for backwards compatibility with RFC 1434 implementations, and it might get used in future versions if needed. ๐Ÿ™ˆ

The SSP Flags field holds extra info about the SSP message. Bit 7 is the most significant bit and bit 0 is the least significant bit of the octet. ๐Ÿซถ

Bit(s)
76543210    Name    Meaning
---------   -----   -------
x.......    SSPex   1 = explorer message (CANUREACH and ICANREACH)

Reserved fields are set to zero when they're sent and should be ignored when they're received. That's the whole vibe on reserved fields, periodt. ๐Ÿ’…โœจ

3.2. Address Parameters โœจ

Okay so a data link is basically the logical pairing between the two end stations using Data Link Switching ๐ŸŽ€. It gets identified by a Data Link ID (14 bytes) made of the attachment addresses for each end system. Each attachment address is the MAC address (6 bytes) plus the LLC address (1 byte) ๐Ÿซถ. Depending on the situation, an attachment address is either "Target" (the Destination MAC/SAP addresses of an explorer frame sent in the first frame used to set up a circuit) or "Origin" (the Source MAC/SAP addresses). And all MAC addresses are written in non-canonical (Token-Ring) format, periodt ๐Ÿ’….

 DATA LINK ID  (14 Bytes @ Control message offset 24 decimal)
+-----------------------------+-----------------------------+
| Target MAC Address                                        |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| Origin MAC Address                                        |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
|                                                           |
+-----------------------------+-----------------------------+
| Origin Link SAP             | Target Link SAP             |
+-----------------------------+-----------------------------+

Next up, end-to-end circuits ๐Ÿฆ‹. Each one is identified by a pair of Circuit IDs. A Circuit ID is a 64 bit number that identifies the DLC circuit within a single DLSw. It's made of a DLC Port ID (4 bytes) and a Data Link Correlator (4 bytes). The Circuit ID MUST be unique in a single DLSw, and it's assigned locally (no cap, that's the whole vibe). The pair of Circuit IDs along with the Data Link IDs uniquely identifies a single end-to-end circuit ๐Ÿ‘‘. Each DLSw MUST keep a table of these Circuit ID pairs, one for the local end of the circuit and the other for the remote end. To keep track of which Data Link Switch started the circuit, this document uses the terms "Origin" DLSw and "Target" DLSw ๐Ÿ’œ.

    CIRCUIT ID   (8 Bytes)
   +-----------------------------+-----------------------------+
   | DLC Port ID                                               |
   +- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
   |                                                           |
   +-----------------------------+-----------------------------+
   | Data Link Correlator                                      |
   +- - - - - - - - - - - - - - -+- - - - - - - - - - - - - - -+
   |                                                           |
   +-----------------------------+-----------------------------+

The Origin Transport ID and the Target Transport ID fields in the message header are how you find the individual TCP/IP port on a Data Link Switch ๐ŸŒธ. Those values only have local significance, BUT each Data Link Switch is REQUIRED to reflect the values in these two fields, along with the matching DLC Port ID and Data Link Correlator values, whenever it returns a message to the other Data Link Switch. Not optional, bestie ๐Ÿ™ˆ.

Here's how the addressing parameters show up when an end-to-end connection gets set up ๐Ÿงš. CANUREACH, ICANREACH and REACH_ACK all carry the Data Link ID, which is the MAC and Link SAP addresses of the two end stations. CANUREACH and ICANREACH get qualified by the SSPex flag into CANUREACH_ex and ICANREACH_ex (explorer messages) or CANUREACH_cs and ICANREACH_cs (circuit start). CANUREACH_ex is used to find a remote MAC and Link SAP address without setting up an SSP circuit. When the target DLSw gets a CANUREACH_cs, it starts a data link for each port, which gets it a Data Link Correlator. If the target station can be reached, an ICANREACH_cs goes back to the origin DLSw with the Target Circuit ID parameter in it. Once the origin DLSw gets that, it starts a data link and sends the Origin Circuit ID back to the target DLSw inside REACH_ACK. (Note: for a full list of message types, see section 3.5.)

   +------------+                                +------------+
   |Disconnected|                                |Disconnected|
   +------------+   CANUREACH_cs (Data Link ID)  +------------+
       ------------------------------------------------->
         ICANREACH_cs (Data Link ID, Target Circuit ID)
       <------------------------------------------------
     REACH_ACK (Data Link ID, Origin Cir ID, Target Cir ID)
       ------------------------------------------------->
   +------------+                                +------------+
   |Circuit Est.|                                |Circuit Est.|
   +------------+                                +------------+
     XIDFRAME (Data Link ID, Origin Cir ID, Target Cir ID)
       <------------------------------------------------>
      CONTACT (Data Link ID, Origin Cir ID, Target Cir ID)
       ------------------------------------------------->
     CONTACTED (Data Link ID, Origin Cir ID, Target Cir ID)
       <-------------------------------------------------
   +------------+                                +------------+
   | Connected  |                                | Connected  |
   +------------+                                +------------+
        INFOFRAME (Remote Circuit ID = Target Circuit ID)
       ------------------------------------------------->
        INFOFRAME (Remote Circuit ID = Origin Circuit ID)
       <-------------------------------------------------

While XIDFRAME, CONTACT and CONTACTED are being exchanged, the pair of Circuit ID parameters goes along in the message format together with the DATA LINK ID parameter ๐ŸŽ€. Once the connection is up, INFOFRAME messages get exchanged with a shorter header. That header only carries the Circuit ID for the remote DLSw. The Remote Data Link Correlator and the Remote DLC Port ID are set equal to the Data Link Correlator and DLC Port ID belonging to the origin or target Data Link Switch, depending on which direction the packet is going โœจ.


3.3. Correlators ๐Ÿซง

The local use and contents of the Data Link Correlator, Port ID and Transport ID fields in SSP messages are an implementation choice, totally up to you ๐Ÿ’–. These fields only have local significance. Values received from a partner DLSw MUST NOT be interpreted by the DLSw that receives them, and they SHOULD be echoed "as is" to a partner DLSw in later messages. Every implementation MUST follow the rules in this section (3.3) for assigning and fixing these correlator fields for each transport connection or circuit ๐Ÿ”ฅ.

The Transport ID fields get learned from the first SSP message exchanged with a DLSw partner (the Capabilities exchange). This field SHOULD NOT be varied by a DLSw after the capabilities exchange, and it MUST be reflected to the partner DLSw in every SSP control message ๐Ÿฆ‹.

The Target Data Link Correlator, Target Port ID and Target Transport ID MUST remain the same once the Target DLSw has sent the ICANREACH_cs for a given circuit. The Origin DLSw MUST store the values specified in the ICANREACH_cs and use them on all subsequent SSP messages for this circuit ๐Ÿ‘‘.

The Origin DLSw MUST allow these fields to vary until the ICANREACH_cs is received. Each SSP message issued for a circuit MUST reflect the values specified by the Target DLSw in the last SSP message for this circuit that the Origin DLSw received. Binary zero SHOULD be used if no such message has been received yet for a given circuit (apart from the Target Transport ID, which will have been learnt as described above) ๐ŸŒˆ.

The Origin Data Link Correlator, Origin Port ID and Origin Transport ID MUST remain the same once the Origin DLSw has issued the REACH_ACK for a given circuit. The Target DLSw MUST store the values specified in the REACH_ACK and use them on all subsequent SSP messages for this circuit ๐Ÿงš.

The Target DLSw MUST allow these fields to vary until the REACH_ACK is received. Each SSP message issued for a circuit MUST reflect the values specified by the Origin DLSw in the last SSP message for this circuit that the Target DLSw received. Binary zero SHOULD be used if no such message has been received yet for a given circuit (apart from the Origin Transport ID, which will have been learnt as described above) ๐Ÿ’œ.

For correlator exchange, explorer messages form a separate circuit ๐Ÿ“. Both DLSw partners MUST reflect the last received correlator values as described above. However, correlators learned on explorer messages need not be carried over to a later circuit setup attempt. Specifically, the Origin DLSw MAY elect to use the same values for the Origin Data Link Correlator and Origin Port ID when it issues a CANUREACH_cs after receiving an ICANREACH_ex or NETBIOS_NR_ex. But the Target DLSw MUST NOT assume that the CANUREACH_cs will specify any of the Target Data Link Correlator or Target Port ID values that were exchanged on the explorer messages ๐Ÿ™ˆ.

Received SSP messages that require a valid Remote Circuit ID but can't be associated with an existing circuit SHOULD be rejected with a HALT_DL_NOACK message. This is done to prevent a situation where one DLSw partner has a circuit defined while the other partner does not. The exception would be a HALT_DL_NOACK message with an invalid Remote Circuit ID. The HALT_DL_NOACK message is typically used in error situations where a response is not appropriate ๐Ÿ’€.

The SSP messages that require a valid Remote Circuit ID are all messages except these: CANUREACH_ex, CANUREACH_cs, ICANREACH_ex, ICANREACH_cs, NETBIOS_NQ_cs, NETBIOS_NR_cs, DATAFRAME, NETBIOS_ANQ, NETBIOS_ANR, KEEPALIVE and CAP_EXCHANGE ๐ŸŽ€.

3.4. Largest Frame Size Field โœจ

okay so the Largest Frame Size (LF Size) field lives in the SSP Control Header ๐ŸŽ€ and its whole job is carrying the LF Size bits across the DLSw connection. the goal is that both end-stations agree on a frame size for the circuit that doesn't make the Origin and Target DLSw partners re-segment frames. no re-segmenting drama ๐Ÿ’…

this field only shows up on CANUREACH_ex, CANUREACH_cs, ICANREACH_ex, ICANREACH_cs, NETBIOS_NQ_ex and NETBIOS_NR_ex messages. on every other frame, the contents SHOULD be ignored ๐Ÿ™ˆ

every DLSw forwarding an SSP frame to its DLSw partner MUST make sure the contents reflect the minimum capability of the route to its local end-station, or any limit the DLSw itself imposes. main character energy for the smallest link wins ๐Ÿ‘‘

here's the bit layout (bit 7 is the most significant, bit 0 is the least significant) ๐Ÿฆ‹

  7   6   5   4   3   2   1   0
+-------------------------------+
| c | r | b | b | b | e | e | e |
+-------------------------------+

  c   .   .   .   .   .   .   .  LF Size Control flag
                                 (significant on messages
                                 from Origin to Target
                                 DLSw only)

                                 0=fail circuit if route
                                   obtained requires a
                                   smaller LF size
                                 1=don't fail the circuit
                                   but return the LF size
                                   obtained even if it is
                                   smaller

  .   r   .   .   .   .   .   .  Reserved
  .   .   b   .   .   .   .   .  Largest Frame Bit Base
  .   .   .   b   .   .   .   .  Largest Frame Bit Base
  .   .   .   .   b   .   .   .  Largest Frame Bit Base
  .   .   .   .   .   e   .   .  Largest Frame Bit Extended
  .   .   .   .   .   .   e   .  Largest Frame Bit Extended
  .   .   .   .   .   .   .   e  Largest Frame Bit Extended

          <----- LF Bits ----->

for the encoding of the Largest Frame base and extended bit values, check the IEEE 802.1D Standard, Annex C ๐Ÿ“š

now the Origin DLSw "Size Control" flag is the spicy one ๐ŸŒถ๏ธ it tells a Target DLSw that answers *_cs messages from cached info that it MAY safely return a smaller LF Size on the ICANREACH_cs frame, if it had to pick a different route to start the circuit. if this bit is 1, the Origin DLSw takes responsibility for making sure the end-stations negotiate a suitable frame size for the circuit. if this bit is 0, the Target DLSw MUST NOT reply to the CANUREACH_cs if it can't get a route to the Target end station that supports an LF Size at least as large as the one specified in the CANUREACH_cs frame. no compromises, bestie ๐Ÿ’€


3.5. Message Types ๐Ÿ’Œ

this table lists the protocol data units that get exchanged between Data Link Switches. anything not listed is reserved for potential use in follow-on releases ๐Ÿงš

Command          Description                       Type   flags/notes
-------          --------                         ------  -----------
CANUREACH_ex     Can U Reach Station-explorer      0x03   SSPex
CANUREACH_cs     Can U Reach Station-circuit start 0x03
ICANREACH_ex     I Can Reach Station-explorer      0x04   SSPex
ICANREACH_cs     I Can Reach Station-circuit start 0x04
REACH_ACK        Reach Acknowledgment              0x05
DGRMFRAME        Datagram Frame                    0x06   (note 1)
XIDFRAME         XID Frame                         0x07
CONTACT          Contact Remote Station            0x08
CONTACTED        Remote Station Contacted          0x09
RESTART_DL       Restart Data Link                 0x10
DL_RESTARTED     Data Link Restarted               0x11
ENTER_BUSY       Enter Busy                        0x0C   (note 2)
EXIT_BUSY        Exit Busy                         0x0D   (note 2)
INFOFRAME        Information (I) Frame             0x0A
HALT_DL          Halt Data Link                    0x0E
DL_HALTED        Data Link Halted                  0x0F
NETBIOS_NQ_ex    NETBIOS Name Query-explorer       0x12   SSPex
NETBIOS_NQ_cs    NETBIOS Name Query-circuit setup  0x12   (note 3)
NETBIOS_NR_ex    NETBIOS Name Recognized-explorer  0x13   SSPex
NETBIOS_NR_cs    NETBIOS Name Recog-circuit setup  0x13   (note 3)
DATAFRAME        Data Frame                        0x14   (note 1)
HALT_DL_NOACK    Halt Data Link with no Ack        0x19
NETBIOS_ANQ      NETBIOS Add Name Query            0x1A
NETBIOS_ANR      NETBIOS Add Name Response         0x1B
KEEPALIVE        Transport Keepalive Message       0x1D   (note 4)
CAP_EXCHANGE     Capabilities Exchange             0x20
IFCM             Independent Flow Control Message  0x21
TEST_CIRCUIT_REQ Test Circuit Request              0x7A
TEST_CIRCUIT_RSP Test Circuit Response             0x7B

Note 1: both DGRMFRAME and DATAFRAME carry information that the DLC entity received inside UI frames ๐Ÿ“ฆ DGRMFRAME is addressed by a pair of Circuit IDs, while DATAFRAME is addressed by a Data Link ID, which is made of a pair of MAC addresses and a pair of link SAP addresses. the Data Link ID is used before the end-to-end circuit exists (when Circuit IDs aren't set up yet) or during a circuit restart, when Data Links get reset.

Note 2: these messages aren't used for the DLSw Standard, but older DLSw implementations MAY use them ๐Ÿ•ฐ๏ธ they're listed just for information. they were added after RFC 1434 was published and got deleted in this standard, since adaptive pacing does the job now.

Note 3: a Standard DLSw doesn't normally send these ๐Ÿ™… it uses the NB_*_ex messages instead, as shown in section 5.4. but if a Standard DLSw wants to interoperate with older DLSw implementations, these messages line up with the NETBIOS_NQ and NETBIOS_NR messages from RFC1434, used both to find the resource and to set up a circuit. this document doesn't try to fully spec how these get used.

Note 4: a KEEPALIVE message MAY be sent by a DLSw to a partner DLSw to check that the TCP connection (or some future SSP carrying protocol) is still alive ๐Ÿ’“ if a DLSw receives one, it gets discarded and ignored. using this message is OPTIONAL.

for NetBIOS control messages, the whole DLC header rides along as part of the message unit ๐ŸŽ€ that includes the MAC header, with the routing information field padded to 18 bytes, plus the LLC header. the affected message types are NETBIOS_NQ, NETBIOS_NR, NETBIOS_ANQ, NETBIOS_ANR, and DATAFRAME when NetBIOS systems are using it. the remote Data Link Switch doesn't use the routing information in the DLC header when it gets any of those five messages ๐Ÿ™ƒ

any SSP message types that aren't defined above are supposed to be ignored if a DLSw receives them, meaning no error action happens ๐Ÿซถ a Data Link Switch SHOULD quietly drop any SSP message whose Message Type it doesn't recognize or support. getting one of those MUST NOT... sorry, SHOULD NOT cause the transport connection to the sender to get terminated ๐Ÿ˜ญ


4. Circuit Priority ๐Ÿ‘‘

at circuit start time, each circuit end point gives its circuit partner some priority info ๐Ÿ’… the initiator of the circuit picks which priority sticks for the whole life of the circuit. if the Data Link Switch doesn't implement Priority, then "Unsupported" priority gets used.

4.1. Frame format ๐Ÿฆ‹

circuit priority is only valid in the CANUREACH_cs, ICANREACH_cs, and REACH_ACK frames. the relevant header field is below. the Circuit Priority value is a byte at offset 22 in an SSP Control Message.

here's the Circuit Priority byte format:

  7   6   5   4   3   2   1   0
+-------------------+-----------+
|   reserved        |    CP     |
+-------------------+-----------+

and here's what the CP bits mean ๐ŸŒˆ

CP: Circuit Priority bits
        000 - Unsupported       (note 1)
        001 - Low Priority
        010 - Medium Priority
        011 - High Priority
        100 - Highest Priority
        101 to 111 are reserved for future use

Note 1: "Unsupported" means the Data Link Switch that started the circuit doesn't implement priority. what happens with Unsupported priority is vendor specific ๐Ÿคทโ€โ™€๏ธ

4.2. Circuit Startup ๐Ÿš€

whoever sends a CANUREACH_cs is in charge of setting the CP bits to match the priority they want for the circuit they're requesting ๐Ÿ’– how they pick that value is implementation dependent. the sender of an ICANREACH_cs does the same thing, also with an implementation dependent way of choosing ๐Ÿง  the receiver of the ICANREACH_cs picks from the priorities in the CANUREACH_cs and ICANREACH_cs frames, then sets the CP field in the REACH_ACK that comes next to whatever value the circuit will use. that priority sticks for the life of the circuit โœจ a CANUREACH_cs or ICANREACH_cs with CP set to Unsupported (CP=000) means the sender doesn't support the circuit priority function ๐Ÿ™ˆ

here's how the flow plays out:

   DLSw A               DLSw B

CANUREACH_cs (CP=011) ----->           Circuit initiator requests
                                       high Priority.

     <--------- ICANREACH_cs (CP=010)  Circuit target requests
                                       medium priority.

REACH_ACK (CP=010) -------->           Circuit initiator sets
                                       the priority for this
                                       circuit to medium. The
                                       circuit initiator could
                                       choose either high or
                                       medium in this example.

5. DLSw State Machine โœจ

okay so this is the part where we talk about the state machine ๐Ÿซถ Every circuit going through the Data Link Switch gets its own state tracking, and every connection keeps its own state info too. A connection always starts out in DISCONNECTED (the blank slate ๐Ÿงš). The steady states are either CIRCUIT_ESTABLISHED or CONNECTED. In CIRCUIT_ESTABLISHED, an end-to-end circuit is up, so the end systems can talk Type 1 LLC ๐Ÿ’œ. CONNECTED means there's an end-to-end connection for Type 2 LLC services between the end systems, and that's the one that gets the full glam ๐Ÿ‘‘

For SNA, LLC type 2 connection setup happens through IEEE 802.2 Test or XID frames. SNA devices send these to the null SAP so they can figure out source route info for bridging ๐ŸŒธ Normally SNA devices use SAP 0x04, 0x08, or 0x0C (most SNA LLC2 devices with a single PU per MAC address default to 0x04). Usually the SAP is what decides whether those Test frames get sent to the DLSw code in the router. If bridging and DLSw are both turned on, this lets the product make sure SNA frames don't get bridged and switched, which would be chaos ๐Ÿ˜ญ Also, although SNA typically uses a DSAP and SSAP of 0x04, it's allowed to use other SAPs if they're configured, and it supports unequal SAPs too. That means multiple PUs can share connections between two MAC addresses, with each PU to PU session using one LLC2 connection. Very efficient, very iconic ๐Ÿฆ‹

For NetBIOS, LLC type 2 connection setup happens through the Name Query and Name Recognized frames. Those frames do double duty for address resolution and source route determination ๐Ÿง  NetBIOS devices use SAP 0xF0.


The Switch-to-Switch Protocol is formally defined through the state machines in this chapter ๐Ÿ’… The table below lists the thirteen possible states for the main circuit FSM. Each end-to-end circuit that the Data Link Switch maintains gets its own separate state machine instance, so they're all doing their own thing ๐ŸŽ€

State Name            Description
----------            -----------
CIRCUIT_ESTABLISHED   The end-to-end circuit has been
                      established.  At this time LLC Type 1
                      services are available from end-to-end.

CIRCUIT_PENDING       The target DLSw is awaiting a REACH_ACK
                      response to an ICANREACH_cs message.

CIRCUIT_RESTART       The DLSw that originated the reset is
                      awaiting the restart of the data link
                      and the DL_RESTARTED response to a
                      RESTART_DL message.

CIRCUIT_START         The origin DLSw is awaiting a
                      ICANREACH_cs in response to a
                      CANUREACH_cs message.

CONNECTED             The end-to-end connection has
                      been established thereby allowing
                      LLC Type 2 services from end-to-end
                      in addition to LLC Type 1 services.

CONNECT_PENDING       The origin DLSw is awaiting the
                      CONTACTED response to a CONTACT
                      message.

CONTACT_PENDING       The target DLSw is awaiting the
                      DLC_CONTACTED confirmation to a
                      DLC_CONTACT signal (i.e., DLC
                      is waiting for a UA response to
                      an SABME command).

DISCONNECTED          The initial state with no circuit
                      or connection established, the
                      DLSw is awaiting either a
                      CANUREACH_cs, or an ICANREACH_cs.

DISCONNECT_PENDING    The DLSw that originated the
                      disconnect is awaiting the DL_HALTED
                      response to a HALT_DL message.

HALT_PENDING          The remote DLSw is awaiting the
                      DLC_DL_HALTED indication following
                      the DLC_HALT_DL request (i.e., DLC
                      is waiting for a UA response to a
                      DISC command), due to receiving a
                      HALT_DL message.

HALT_PENDING_NOACK    The remote DLSw is awaiting the
                      DLC_DL_HALTED indication following
                      the DLC_HALT_DL request (i.e., DLC
                      is waiting for a UA response to a
                      DISC command), due to receiving a
                      HALT_DL_NOACK message.

RESTART_PENDING       The remote DLSw is awaiting the
                      DLC_DL_HALTED indication following
                      the DLC_HALT_DL request (i.e., DLC
                      is waiting for a UA response to a
                      DISC command), and the restart of
                      the data link.

RESOLVE_PENDING       The target DLSw is awaiting
                      the DLC_DL_STARTED indication
                      following the DLC_START_DL request
                      (i.e., DLC is waiting for a Test
                      response as a result of sending a
                      Test command).

DISCONNECTED is the starting state for a new circuit ๐Ÿš€ One end station kicks things off with an XID or SABME command (i.e., DLC_XID or DLC_CONTACTED). When that comes in, the Data Link Switches swap a set of CANUREACH_cs, ICANREACH_cs and REACH_ACK messages. It's a three-legged exchange, and once it wraps up, both Data Link Switches land in CIRCUIT_ESTABLISHED โœจ Three pending states show up during this dance. CIRCUIT_START gets entered by the origin Data Link Switch after it sends the CANUREACH_cs message. RESOLVE_PENDING gets entered by the target Data Link Switch while it waits for a Test response to a Test Command. And last but not least, CIRCUIT_PENDING is entered by the target DLSw while it waits for the REACH_ACK reply to an ICANREACH_cs message.

In CIRCUIT_ESTABLISHED, LLC Type 1 frames can be exchanged, like the XID exchanges between SNA stations that happen before a connection gets set up ๐Ÿ’– Datagram traffic (i.e., UI frames) can also flow between the end stations. These exchanges use the XIDFRAME and DGRMFRAME messages sent between the Data Link Switches.

Now, in CIRCUIT_ESTABLISHED, if a SABME command shows up (i.e., DLC_CONTACTED), the origin DLSw issues a CONTACT message, sends an RNR supervisory frame (i.e., DLC_ENTER_BUSY) to the origin station, and enters CONNECT_PENDING to wait for a CONTACTED message. The target DLSw, once it gets the CONTACT message, issues a SABME command (i.e., DLC_CONTACT) and enters the Contact Pending state. When the UA response arrives (i.e., DLC_CONTACTED), the target DLSw sends a CONTACTED message and enters CONNECTED. Then, when the origin DLSw receives that, it enters CONNECTED too and sends an RR supervisory frame (i.e., DLC_EXIT_BUSY). Plot twist, everyone's connected ๐ŸŽ‰

CONNECTED is the steady state for normal data flow once a connection has been set up ๐ŸŒˆ Information frames (i.e., INFOFRAME messages) just go back and forth between the endpoints of the connection. This is the path that should be optimized for performance โญ

The connection ends when a DISC frame is received or when DLC detects some other error condition (i.e., DLC_ERROR) ๐Ÿ’€ When that indication arrives, the DLSw halts the local data link, sends a HALT_DL message to the remote DLSw, and enters the DISCONNECT_PENDING State. When the other DLSw receives the HALT_DL frame, it halts the local DLC for that data link, returns a DL_HALTED message, and enters DISCONNECTED. Getting that DL_HALTED message makes the other DLSw enter DISCONNECTED as well, so both sides are out ๐Ÿซถ

CIRCUIT_RESTART gets entered if one of the Data Link Switches receives a SABME command (i.e., DLC_RESET) after data transfer while it's in CONNECTED ๐Ÿ”ฅ That causes a DM command to be sent back to the origin station, and a RESTART_DL message goes to the remote Data Link Switch. That halts the remote data link and then restarts it. The remote DLSw then sends a DL_RESTARTED message back to the first DLSw. When the first DLSw gets DL_RESTARTED, it issues a new CONTACT message, as long as the local DLC has been contacted (i.e., the origin station has resent the SABME command). That gets answered eventually with a CONTACTED message, and after that exchange, both Data Link Switches go back to CONNECTED ๐Ÿฆ‹ If the local DLC hasn't been contacted, getting a DL_RESTARTED command makes the Data Link Switch enter CIRCUIT_ESTABLISHED and wait for a SABME command (i.e., DLC_CONTACTED signal) instead.

HALT_PENDING, HALT_PENDING_NOACK and RESTART_PENDING are for when the Data Link Switch is waiting on responses from the local station on the adjacent LAN (e.g., a UA response to a DISC command) ๐Ÿ™ˆ In RESTART_PENDING, the Data Link Switch also tries to restart the data link before it sends a DL_RESTARTED message. In some implementations, starting a data link involves a Test command/response exchange on the adjacent LAN (i.e., DLC_START_DL). For other implementations, that extra exchange might not be needed at all ๐Ÿงš

5.2. State Transition Tables โœจ

Okay bestie, this is where the state machine gets fully detailed ๐Ÿงš The tables spell out every event, action, and next state. A lot of the transitions depend on local signals passing between the DLSw and one of the DLC entities, so first we need the signal list ๐Ÿ’…

DLC Events:

Event Name      Description
----------      -----------
DLC_CONTACTED   Contact Indication:  DLC has received an SABME
                command or DLC has received a UA response as a
                result of sending an SABME command.

DLC_DGRM        Datagram Indication:  DLC has received a UI frame.

DLC_ERROR       Error condition indicated by DLC:  Such a
                condition occurs when a DISC command is received
                or when DLC experiences an unrecoverable error.

DLC_INFO        Information Indication:  DLC has received an
                Information (I) frame.

DLC_DL_HALTED   Data Link Halted Indication:  DLC has
                received a UA response to a DISC command.

DLC_DL_STARTED  Data Link Started Indication:  DLC has
                received a Test response from the null SAP.

DLC_RESET       Reset Indication:  DLC has received an SABME
                command during the time a connection is
                currently active and has responded with DM.

DLC_RESOLVE_C   Resolve Command Indication:  DLC has received
                a Test command addressed to the null SAP, or an
                XID command addressed to the null SAP.

DLC_RESOLVED    Resolve request:  DLC has received a TEST response
                frame (or equivalent for non-LAN DLCs) but has not
                reserved the resources required for a circuit yet.

DLC_XID         XID Indication:  DLC has received an XID command
                or response to a non-null SAP.

Other Events:

Event Name      Description
----------      -----------
XPORT_FAILURE   Failure of the transport connection used by the
                circuit.

CS_TIMER_EXP    The CIRCUIT_START timer (started when the circuit
                went into CIRCUIT_START state) has expired.

DLC Actions:

Action Name     Description
-----------     -----------
DLC_CONTACT     Contact Station Request:  DLC will send a SABME
                command or a UA response to an outstanding SABME
                command.

DLC_DGRM        Datagram Request:  DLC will send a UI frame.

DLC_ENTER_BUSY  Enter Link Station Busy:  DLC will send an
                RNR supervisory frame.

DLC_EXIT_BUSY   Exit Link Station Busy:  DLC will send an RR
                supervisory frame.

DLC_HALT_DL     Halt Data Link Request:  DLC will send a DISC
                command.

DLC_INFO        Information Request:  DLC will send an I frame.

DLC_RESOLVE     Resolve request:  DLC should issue a TEST (or
                appropriate equivalent for non-LAN DLCs) but need
                not reserve the resources required for a circuit yet.

DLC_RESOLVE_R   Resolve Response Request:  DLC will send a
                Test response or XID response from the null SAP.

DLC_START_DL    Start Data Link Request:  DLC will send a Test
                command to the null SAP.

DLC_XID         XID Request:  DLC will send an XID command or an
                XID response.

Other Actions:

Action Name     Description
----------      -----------
START_CS_TIMER  Start the CIRCUIT_START timer.
DLC_RESOLVE_R and DLC_START_DL actions require the DLC to reserve the resources necessary for a link station, since they are only used when a circuit is about to be started. The DLC_RESOLVE action is used for topology explorer traffic and does not require such resources to be reserved, though a DLC implementation may choose not to distinguish this from the DLC_START_DL action. See section 5.4 for details of the actions and events for explorer frames.

The Data Link Switch is described by a state transition table, as laid out in the following sections. Each state is described below in terms of the events, actions, and next state for each transition. If a particular event is not listed for a given state, no action and no state transition should occur for that event. Any significant comments about the transitions within a given state come right after the table for that state ๐ŸŒธ

A separate state machine instance is maintained by the Data Link Switch for each end-to-end circuit. How many circuits each Data Link Switch can support is a local implementation option ๐Ÿฆ‹

The CANUREACH_ex, ICANREACH_ex, NETBIOS_NQ_ex, and NETBIOS_NR_ex are SSP messages that aren't tied to a particular circuit, so they're handled separately. Their processing is covered in section 5.4 ๐Ÿซถ

5.2.1. DISCONNECTED State

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive CANUREACH_cs | DLC_START_DL        | RESOLVE_PENDING      |
+----------------------+---------------------+----------------------+
| Receive DATAFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_XID              | If source route     | If CANUREACH_cs was  |
|                      | bridged frame with  | sent:                |
|                      | broadcast indicated:|   CIRCUIT_START      |
|                      |   Send CANUREACH_ex |                      |
|                      | else:               |                      |
|                      |   Send CANUREACH_cs |                      |
|                      |   START_CS_TIMER    |                      |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | If NETBIOS          |                      |
|                      | NAME_QUERY:         |                      |
|                      |  Send NETBIOS_NQ_ex |                      |
|                      | else:               |                      |
|                      |  Send DATAFRAME     |                      |
+----------------------+---------------------+----------------------+
| DLC_CONTACTED        | Send CANUREACH_cs   | CIRCUIT_START        |
+----------------------+---------------------+----------------------+

It's assumed that each Data Link Switch will build a set of topology tables that give the identity of each Data Link Switch that can reach a specific MAC address or a specific NetBIOS name. These tables can be built using the explorer frames, as per the Explorer FSM in section 5.4, so the amount of search traffic can be kept to a minimum ๐Ÿ”

When a TEST command, broadcast XID, or NetBIOS NAME_QUERY comes in, the Data Link Switch checks the topology table for the target MAC/SAP or NetBIOS name. If there's no matching entry in the table, the Data Link Switch uses the explorer FSMs in section 5.4 to locate the target MAC/SAP or NetBIOS name ๐Ÿงญ

When the first non-broadcast XID or SABME flows, the Data Link Switch issues a CANUREACH_cs to attempt to start a circuit. The CANUREACH_cs message is sent only to those Data Link Switches that are known to be able to reach the given MAC address. The mechanism by which a topology table entry is judged out-of-date and deleted from the table is implementation specific ๐Ÿ’€

The DISCONNECTED state is exited upon the sending of a CANUREACH_cs by the origin DLSw, or the receipt of a CANUREACH_cs message by a prospective target Data Link Switch. In the latter case, the Data Link Switch will issue a Test command to the target station (i.e., the DLC_START_DL signal is presented to the DLC) ๐ŸŽ€

5.2.2. RESOLVE_PENDING State

+-------------------+-----------------------+-----------------------+
|        Event      |      Action(s)        |      Next State       |
+-------------------+-----------------------+-----------------------+
| Receive DATAFRAME | DLC_DGRM              |                       |
+-------------------+-----------------------+-----------------------+
| DLC_DL_STARTED    | If LF value of        | If LF value of        |
|                   | DLC_DL_STARTED        | DLC_DL_STARTED        |
|                   | is greater than or    | is greater than or    |
|                   | equal to LF Size of   | equal to LF Size of   |
|                   | CANUREACH_cs or LF    | CANUREACH_cs or LF    |
|                   | Size Control bit set: | Size Control bit set: |
|                   |   Send ICANREACH_cs   |   CIRCUIT_PENDING     |
|                   | else:                 | else:                 |
|                   |   Send DLC_HALT_DL    |   HALT_PENDING_NOACK  |
+-------------------+-----------------------+-----------------------+
| DLC_ERROR         |                       | DISCONNECTED          |
+-------------------+-----------------------+-----------------------+
| DLC_DGRM          | Send DATAFRAME        |                       |
+-------------------+-----------------------+-----------------------+

The RESOLVE_PENDING state is entered upon receipt of a CANUREACH_cs message by the target DLSw. A data link is started, which causes a Test command to be sent by the DLC ๐ŸŒˆ

Several CANUREACH_cs messages can be received while in the RESOLVE_PENDING state. The Data Link Switch may update its topology information based on the origin MAC address information in each CANUREACH_cs message ๐Ÿ’œ

When a DLC_DL_STARTED signal is received in the RESOLVE_PENDING state, the Data Link Switch may update its topology table based on the remote MAC address information. The ICANREACH_cs message must be returned to the first partner DLSw from which a CANUREACH_cs was received for this circuit, or an implementation may optionally reply to all partners from which the CANUREACH_cs was received ๐Ÿ‘‘

The RESOLVE_PENDING state is exited once the data link has been started (i.e., a DLC_DL_STARTED signal is received as a result of a Test response received by the DLC). The target Data Link Switch then enters the CIRCUIT_PENDING state ๐Ÿฆ‹

5.2.3. CIRCUIT_START State โœจ

okay bestie, this is the state where the origin Data Link Switch is basically waiting for its partner to show up ๐Ÿฅบ๐ŸŽ€ Here's the whole table, exactly as it's written:

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive CANUREACH_cs | If origin MAC addr  | If DLC_START_DL      |
   | for circuit in       | in CANUREACH_cs is  | issued:              |
   | opposite direction   | greater than origin |   RESOLVE_PENDING    |
   |                      | MAC addr of circuit:|                      |
   |                      |   DLC_START_DL      |                      |
   |                      | else:               |                      |
   |                      |   no action taken   |                      |
   +----------------------+---------------------+----------------------+
   | Receive ICANREACH_cs | If LF Size Control  | If LF Size Control   |
   |                      | bit set and LF Size | bit set and LF Size  |
   |                      | is not negotiable:  | is not negotiable:   |
   |                      |   Send HALT_DL_NOACK|   DISCONNECTED       |
   |                      | else:               | else if Connected:   |
   |                      |   Send REACH_ACK,   |   CONNECT_PENDING    |
   |                      |   Send appropriate  | else:                |
   |                      |   SSP message based |   CIRCUIT_ESTABLISHED|
   |                      |   on the event      |                      |
   |                      |   that generated    |                      |
   |                      |   CANUREACH_cs      |                      |
   |                      |   (see Note)        |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DATAFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            |                     | DISCONNECTED         |
   +----------------------+---------------------+----------------------+
   | CS_TIMER_EXP         |                     | DISCONNECTED         |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        |                     | DISCONNECTED         |
   +----------------------+---------------------+----------------------+

The origin Data Link Switch jumps into CIRCUIT_START when it gets a DLC_XID or DLC_CONTACTED signal from the DLC ๐Ÿ’…

It leaves this state as soon as an ICANREACH_cs message shows up. Then it sends a REACH_ACK back to the target Data Link Switch. If we got here because of DLC_XID, it also sends an XIDFRAME carrying the XID to the target Data Link Switch. If we got here because of DLC_CONTACTED, it sends a CONTACT message to the target Data Link Switch instead โœจ

5.2.4. CIRCUIT_PENDING State ๐Ÿฆ‹

this one is the target's waiting room ๐Ÿงš Here's the table, untouched:

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive CONTACT      | DLC_CONTACT         | CONTACT_PENDING      |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL      | DLC_HALT_DL         | HALT_PENDING         |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+
   | Receive REACH_ACK    | If Connected:       | If Connected:        |
   |                      |  Send CONTACT       |  CONNECT_PENDING,    |
   |                      |                     | else:                |
   |                      |                     |  CIRCUIT_ESTABLISHED |
   +----------------------+---------------------+----------------------+
   | Receive XIDFRAME     | DLC_XID             |                      |
   +----------------------+---------------------+----------------------+
   | Receive DGRMFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive DATAFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | DLC_CONTACTED        | If UA is sent in    |                      |
   |                      | response to SABME:  |                      |
   |                      |   DLC_ENTER_BUSY    |                      |
   |                      | else:               |                      |
   |                      |   no action taken   |                      |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            |                     | DISCONNECTED         |
   +----------------------+---------------------+----------------------+
   | DLC_XID              | Drop or hold until  |                      |
   |                      | REACH_ACK received  |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DATAFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+

The target Data Link Switch lands here right after it sends an ICANREACH_cs message. It's just waiting for a REACH_ACK from the origin Data Link Switch ๐Ÿฅน

Now, if the target station sends a SABME command while we're in CIRCUIT_PENDING (aka the DLC gave us a DLC_CONTACTED signal), then when the REACH_ACK finally arrives, the target Data Link Switch moves into CONNECT_PENDING and sends a CONTACT message to the origin Data Link Switch. Plot twist, but make it iconic ๐Ÿ‘‘

If no SABME shows up, the REACH_ACK just gets the Data Link Switch into CIRCUIT_ESTABLISHED. Clean and simple ๐ŸŒธ

5.2.5. CONNECT_PENDING State ๐Ÿ‘‘

this is the state with the most drama, so buckle up ๐Ÿ˜ญ Here's the table:

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive CONTACTED    | If UA was sent in   | CONNECTED            |
   |                      | response to SABME:  |                      |
   |                      |   DLC_EXIT_BUSY     |                      |
   |                      | else:               |                      |
   |                      |   DLC_CONTACT       |                      |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL      | DLC_HALT_DL         | HALT_PENDING         |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+
   | Receive DGRMFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive DATAFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive ICANREACH_cs | Send HALT_DL_NOACK  |                      |
   +----------------------+---------------------+----------------------+
   | DLC_RESET            | Send RESTART_DL     | CIRCUIT_RESTART      |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DGRMFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+

CONNECT_PENDING gets entered when the DLC hands us a DLC_CONTACTED signal, which means a SABME command came in. From there, a CONTACT message gets issued. We only leave this state once a CONTACTED message shows up ๐Ÿ’– If a DLC_RESET signal comes in, the local data link gets restarted and a RESTART_DL message is sent to the remote DLSw. Ugh, so dramatic, I love it ๐Ÿ™ˆ

Here's the spicy bit โšก If an ICANREACH_cs arrives after we've already moved into CONNECT_PENDING, that means more than one CANUREACH_cs got sent when the circuit was being set up, and the target station was found by more than one Data Link Switch partner. So we send a HALT_DL_NOACK to halt the circuit that each of those extra partners started when it sent its ICANREACH_cs. Not the vibe for those duplicates ๐Ÿ™…โ€โ™€๏ธ

Note: Some implementations will also send a Test command in order to restart the data link to the station that sent the SABME command (i.e., a DLC_START_DL will be issued).

5.2.6. CIRCUIT_ESTABLISHED State โœจ

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive CONTACT      | DLC_CONTACT         | CONTACT_PENDING      |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL      | DLC_HALT_DL         | HALT_PENDING         |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+
   | Receive XIDFRAME     | DLC_XID             |                      |
   +----------------------+---------------------+----------------------+
   | Receive DGRMFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive DATAFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive ICANREACH_cs | Send HALT_DL_NOACK  |                      |
   +----------------------+---------------------+----------------------+
   | DLC_CONTACTED        | Send CONTACT        | CONNECT_PENDING      |
   |                      | If UA is sent in    |                      |
   |                      | response to SABME:  |                      |
   |                      |   DLC_ENTER_BUSY    |                      |
   |                      | else:               |                      |
   |                      |   no action taken   |                      |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DGRMFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | DLC_XID              | Send XIDFRAME       |                      |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+

Okay so the CIRCUIT_ESTABLISHED state is where the origin Data Link Switch lands coming from CIRCUIT_START, and the target Data Link Switch lands here coming from CIRCUIT_PENDING ๐Ÿ’…. You leave when a connection gets started (aka DLC receives a SABME command) or when a CONTACT shows up. From there you go to CONTACT_PENDING or CONNECT_PENDING ๐Ÿฆ‹.

An ICANREACH_cs that arrives after you've already hit CIRCUIT_ESTABLISHED means more than one CANUREACH_cs went out at circuit establishment time, and the target station got found by more than one Data Link Switch partner ๐Ÿ˜ญ. So a HALT_DL_NOACK gets sent to halt the circuit started by the Data Link Switch partner that originated each one of those ICANREACH_cs messages. Main character energy, but make it a cleanup crew ๐Ÿงน.

5.2.7. CONTACT_PENDING State ๐ŸŽ€

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL      | DLC_HALT_DL         | HALT_PENDING         |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+
   | Receive RESTART_DL   | DLC_HALT_DL         | RESTART_PENDING      |
   +----------------------+---------------------+----------------------+
   | Receive DGRMFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive DATAFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | DLC_CONTACTED        | Send CONTACTED      | CONNECTED            |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DGRMFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+

The CONTACT_PENDING state gets entered when a CONTACT message arrives, which makes the Data Link Switch fire a DLC_CONTACT signal at the DLC (i.e., the DLC sends a SABME command) ๐Ÿ“ก. You hang out here until a DLC_CONTACTED signal comes back from the DLC (i.e., a UA response is received) and then you're out ๐Ÿฆ‹.

If a RESTART_DL message comes in, that means the remote Data Link Switch got a DLC_RESET signal. So the local Data Link Switch sends a DISC command frame on the adjacent LAN (i.e., DLC_HALT_DL signal) and enters the RESTART_PENDING state ๐Ÿ”„.

An ICANREACH_cs received after the transition to CONTACT_PENDING is the same plot twist as before: more than one CANUREACH_cs was sent at circuit establishment time, and the target station was found by more than one Data Link Switch partner. A HALT_DL_NOACK is sent to halt the data link started by the Data Link Switch partner that originated this ICANREACH_cs ๐Ÿ™…โ€โ™€๏ธ.

5.2.8. CONNECTED State ๐Ÿ’œ

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL      | DLC_HALT_DL         | HALT_PENDING         |
   +----------------------+---------------------+----------------------+
   | Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+
   | Receive RESTART_DL   | DLC_HALT_DL         | RESTART_PENDING      |
   +----------------------+---------------------+----------------------+
   | Receive DGRMFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive INFOFRAME    | DLC_INFO            |                      |
   +----------------------+---------------------+----------------------+
   | Receive DATAFRAME    | DLC_DGRM            |                      |
   +----------------------+---------------------+----------------------+
   | Receive XIDFRAME     | If non-activation   |                      |
   |                      | XID3:               |                      |
   |                      |   DLC_XID           |                      |
   +----------------------+---------------------+----------------------+
   | Receive ICANREACH_cs | Send HALT_DL_NOACK  |                      |
   +----------------------+---------------------+----------------------+
   | Receive ENTER_BUSY   | DLC_ENTER_BUSY      |                      |
   +----------------------+---------------------+----------------------+
   | Receive EXIT_BUSY    | DLC_EXIT_BUSY       |                      |
   +----------------------+---------------------+----------------------+
   | Rec TEST_CIRCUIT_REQ | Snd TEST_CIRCUIT_RSP|                      |
   +----------------------+---------------------+----------------------+
   | DLC_RESET            | Send RESTART_DL     | CIRCUIT_RESTART      |
   +----------------------+---------------------+----------------------+
   | DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM             | Send DGRMFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | DLC_INFO             | Send INFOFRAME      |                      |
   +----------------------+---------------------+----------------------+
   | DLC_XID              | If non-activation   |                      |
   |                      | XID3:               |                      |
   |                      |   Send XIDFRAME     |                      |
   +----------------------+---------------------+----------------------+
   | XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
   +----------------------+---------------------+----------------------+

The CONNECTED state is entered from CONNECT_PENDING when a CONTACTED message arrives, or from CONTACT_PENDING when a DLC_CONTACTED signal shows up ๐ŸŽ‰.

You usually leave CONNECTED in one of two ways. Either a DLC_ERROR signal comes in from the DLC (e.g., a DISC command received by the local DLC), or a HALT_DL message comes in from the other Data Link Switch (e.g., a DISC command received by the remote DLC) ๐Ÿ’”.

A SABME command (i.e., a DLC_RESET signal) received by either Data Link Switch also makes both of them leave CONNECTED and try to restart the circuit ๐Ÿ”. After getting a SABME, the local Data Link Switch sends a RESTART_DL message to the other one and enters the CIRCUIT_RESTART state. When that RESTART_DL message lands, the remote Data Link Switch sends a DISC command (i.e., DLC_HALT_DL signal) and enters the RESTART_PENDING state ๐Ÿซถ.

An ICANREACH_cs received after the transition to CONNECTED is the same story as before. More than one CANUREACH_cs was sent at circuit establishment time, and the target station was found by more than one Data Link Switch partner. A HALT_DL_NOACK is sent to halt the circuit started by the Data Link Switch partner that originated each such ICANREACH_cs ๐Ÿšซ.

Note: Some implementations will also send a Test command in order to restart the data link to the station that sent the SABME command (i.e., a DLC_START_DL will be issued). ๐Ÿงš

5.2.9. CIRCUIT_RESTART State โœจ

okay bestie, this one is the "we're starting over" state ๐Ÿ”„๐Ÿ’–

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive DL_RESTARTED | If Connected:       | If Connected:        |
|                      |  Send CONTACT       |  CONNECT_PENDING,    |
|                      |                     | else:                |
|                      |                     |  CIRCUIT_ESTABLISHED |
+----------------------+---------------------+----------------------+
| Receive HALT_DL_NOACK| DLC_HALT_DL         | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+
| Receive DGRMFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | Send DGRMFRAME      |                      |
+----------------------+---------------------+----------------------+
| XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+

So the CIRCUIT_RESTART state kicks in when the local DLC sends a DLC_RESET signal ๐Ÿซถ. That happens because a SABME command showed up while a connection was already active ๐Ÿ‘€. The Data Link Switch answers that SABME with a DM response, then tries to restart the whole end-to-end circuit ๐Ÿฆ‹.

There are two ways out of this state ๐Ÿšช, and which one you get depends on timing โฐ. What matters is whether the local DLC hits the contacted state (aka a DLC_CONTACTED signal shows up) before or after the DL_RESTARTED message arrives. That DLC_CONTACTED signal happens because the origin station resends the SABME command that originally kicked the Data Link Switch into CIRCUIT_RESTART ๐Ÿ”. So the two cases are:

  1. DL_RESTARTED message received before the DLC_CONTACTED signal. In this case, the CIRCUIT_ESTABLISHED state is entered. โœจ
  2. DL_RESTARTED message received after the DLC_CONTACTED signal. In this case, the CONNECT_PENDING state is entered. ๐Ÿ’œ

5.2.10. DISCONNECT_PENDING State ๐ŸŒง๏ธ

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive DL_HALTED    |                     | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| Receive HALT_DL      | Send DL_HALTED      |                      |
+----------------------+---------------------+----------------------+
| Receive HALT_DL_NOACK|                     | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| Receive DATAFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | Send DATAFRAME      |                      |
+----------------------+---------------------+----------------------+
| XPORT_FAILURE        |                     | DISCONNECTED         |
+----------------------+---------------------+----------------------+

DISCONNECT_PENDING is the state you land in when the local DLC sends a DLC_ERROR signal ๐Ÿšจ. The moment that signal arrives, the Data Link Switch sends a HALT_DL message ๐Ÿ“ค. Once a DL_HALTED message comes back ๐Ÿ“ฉ, the state is exited and the Data Link Switch moves over to DISCONNECTED ๐Ÿ’….


5.2.11. RESTART_PENDING State ๐Ÿ”ง

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive HALT_DL_NOACK|                     | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+
| Receive DGRMFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_DL_HALTED        | Send DL_RESTARTED   | CIRCUIT_ESTABLISHED  |
+----------------------+---------------------+----------------------+
| DLC_ERROR            | Send HALT_DL        | DISCONNECT_PENDING   |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | Send DGRMFRAME      |                      |
+----------------------+---------------------+----------------------+
| XPORT_FAILURE        | DLC_HALT_DL         | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+

RESTART_PENDING gets entered when a RESTART_DL message shows up from the remote DLSw ๐Ÿ“จ. That only happens if the local Data Link Switch is sitting in either CONTACT_PENDING or CONNECTED. Once it's in here, the local DLSw issues a DISC command to the DLC ๐Ÿ™ˆ. When the UA response comes back (that's the DLC_DL_HALTED), the data link gets restarted โ™ป๏ธ, a DL_RESTARTED message gets sent back to the remote DLSw ๐Ÿ’Œ, and the CIRCUIT_ESTABLISHED state is entered ๐ŸŽ€.

Note: Some implementations will send a Test command in order to restart the data link to the target station (i.e., a DLC_START_DL will be issued) prior to sending the DL_RESTARTED message. ๐Ÿงช


5.2.12. HALT_PENDING State ๐Ÿ›‘

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive HALT_DL_NOACK|                     | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+
| Receive DATAFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_DL_HALTED        | Send DL_HALTED      | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| DLC_ERROR            | Send DL_HALTED      | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | Send DATAFRAME      |                      |
+----------------------+---------------------+----------------------+
| XPORT_FAILURE        |                     | HALT_PENDING_NOACK   |
+----------------------+---------------------+----------------------+

HALT_PENDING is entered when a HALT_DL message is received ๐ŸงŠ. That makes the local DLC issue a DISC command ๐Ÿ“ด. When the UA response (DLC_DL_HALTED) comes back, a DL_HALTED message goes back to the remote DLSw ๐Ÿ’œ, and then the DISCONNECTED state is entered ๐ŸŒธ.


5.2.13. HALT_PENDING_NOACK State ๐Ÿฅ€

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive DATAFRAME    | DLC_DGRM            |                      |
+----------------------+---------------------+----------------------+
| DLC_DL_HALTED        |                     | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| DLC_ERROR            |                     | DISCONNECTED         |
+----------------------+---------------------+----------------------+
| DLC_DGRM             | Send DATAFRAME      |                      |
+----------------------+---------------------+----------------------+

HALT_PENDING_NOACK gets entered when a HALT_DL_NOACK message is received ๐Ÿ™…โ€โ™€๏ธ. That causes the local DLC to issue a DISC command. When the UA response (DLC_DL_HALTED) finally comes in, the DISCONNECTED state is entered ๐ŸŒ™โœจ.

5.3 NetBIOS Datagrams โœจ

okay so NetBIOS uses a bunch of UI frames for directory services and sending datagrams ๐Ÿ“ฎ Most of these go to a group MAC address (GA) with the routing information field set to spanning tree explorer (STE), which is also called Single Route Broadcast ๐ŸŒธ The NB_Add_Name_Response and NB_Name_Recognized frames go to one specific MAC address with the routing information field set to an all routes explorer frame (ARE), aka All Routes Broadcast ๐Ÿฆ‹ And the NB_Status_Response frame goes to a specific MAC address too, but its routing information field says specifically routed frame (SRF) ๐Ÿ’… Here's how it all gets handled:

+---------------------------+------------------+--------------------+
|          Event            |     Action(s)    |      Comment       |
+---------------------------+------------------+--------------------+
| DLC_DGRM for NETBIOS      | Send NETBIOS_ANQ | Transmitted to all |
|  group address:           |                  |   remote DLSw      |
|   NB_Add_Name_Query       |                  |                    |
+---------------------------+------------------+--------------------+
| DLC_DGRM for a specific   | Send NETBIOS_ANR | Transmitted to     |
|  address:                 |                  |   specific DLSw    |
|   NB_Add_Name_Response    |                  |                    |
+---------------------------+------------------+--------------------+
| DLC_DGRM for a specific   | Send DATAFRAME   | Transmitted to all |
|  address:                 |                  |   remote DLSw      |
|   NB_Status_Response      |                  |                    |
+---------------------------+------------------+--------------------+
| DLC_DGRM for NETBIOS      | Send DATAFRAME   | Transmitted to all |
|  group address:           |                  |   remote DLSw      |
|   NB_Name_in_Conflict     |                  |                    |
|   NB_Add_Group_Name_Query |                  |                    |
|   NB_Datagram,            |                  |                    |
|   NB_Datagram_Broadcast   |                  |                    |
|   NB_Status_Query         |                  |                    |
|   NB_Terminate_Trace      |                  |                    |
+---------------------------+------------------+--------------------+
โš ๏ธ Heads up bestie: the actions above do not apply in these states: CIRCUIT_ESTABLISHED, CONTACT_PENDING, CONNECT_PENDING, CONNECTED, and CIRCUIT_PENDING. ๐Ÿ™ˆ

The other two NetBIOS UI frames, NB_Name_Query and NB_Name_Recognized, are handled as part of the DLSw state machine in the previous section, specifically the DISCONNECTED and RESOLVE_PENDING states ๐Ÿงš And NetBIOS datagrams (NB_Datagram) sent to a specific MAC address are also run through the DLSw state machine ๐Ÿ’œ

Note: some implementations also send Test frames during the NB_Name_Query and NB_Name_Recognized exchange ๐ŸŒˆ This exchange happens when a data link is starting up and it's how the routing information gets figured out. Most other NetBIOS implementations use the NB_Name_Query/NB_Name_Recognized exchange to work out routes at the same time they resolve NetBIOS names, and these differences are not reflected in the SSP protocols ๐Ÿซถ

Here's how the NetBIOS-specific SSP messages get handled:

+---------------+-------------------------+-------------------------+
|     Event     |        Action(s)        |         Comment         |
+---------------+-------------------------+-------------------------+
| NETBIOS_ANQ   | DLC_DGRM:               | Routed STE              |
|               |    NB_Add_Name_Query    | (NETBIOS Group Address) |
+---------------+-------------------------+-------------------------+
| NETBIOS_ANR   | DLC_DGRM:               | Routed ARE              |
|               |    NB_Add_Name_Response | (Specific MAC Address)  |
+---------------+-------------------------+-------------------------+
| NETBIOS_NQ_ex | DLC_DGRM:               | Routed STE              |
|               |    NB_Name_Query        | (NETBIOS Group Address) |
+---------------+-------------------------+-------------------------+
| NETBIOS_NQ_cs | DLC_DGRM:               | Routed STE              |
|               |    NB_Name_Query        | (NETBIOS Group Address) |
+---------------+-------------------------+-------------------------+
| NETBIOS_NR_ex | DLC_DGRM:               | Routed ARE              |
|               |    NB_Name_Recognized   | (Specific MAC Address)  |
+---------------+-------------------------+-------------------------+
| NETBIOS_NR_cs | DLC_DGRM:               | Routed ARE              |
|               |    NB_Name_Recognized   | (Specific MAC Address)  |
+---------------+-------------------------+-------------------------+
| DATAFRAME     | DLC_DGRM                | If NB_Status_Response:  |
|               |                         |  Routed ARE             |
|               |                         |  (Specific MAC Address) |
|               |                         | Else:                   |
|               |                         |  Routed STE             |
|               |                         |  (NETBIOS Group Address)|
+---------------+-------------------------+-------------------------+

These actions apply in all DLSw states ๐ŸŽ€ NetBIOS datagrams that ride inside DGRMFRAME messages are governed by the DLSw state machine. DGRMFRAME is used instead of DATAFRAME once the end-to-end circuit is up, and at that point the message gets addressed using the pair of Circuit IDs in the message header, not the MAC address info in the token ring header ๐Ÿ“


5.4 Explorer Traffic ๐Ÿ”ฅ

The CANUREACH_ex, ICANREACH_ex, NETBIOS_NQ_ex, and NETBIOS_NR_ex SSP messages are the explorers ๐Ÿงญ They map out the topology of the DLSw cloud and the networks attached to it. Explorer frames are how a DLSw finds out which DLSw partners can reach a given MAC or NetBIOS name. This info can optionally be cached so there's less explorer traffic floating around the DLSw cloud โœจ

If a DLSw knows from cached info that a certain MAC address or NetBIOS name is reachable through a certain partner DLSw, it should send all its circuit setup attempts to that partner ๐Ÿ’– If the setup fails, or there's no data for it in the MAC or name cache, the DLSw may fall back to trying every DLSw partner, since the cached data might be outdated by now ๐Ÿฆ‹ How it decides when to fall back is implementation defined.

DLSw implementations can also keep a local MAC cache, so they can reply to CANUREACH_ex requests without doing a TEST frame exchange (or something equivalent) until CANUREACH_cs shows up ๐ŸŒธ Again, when that local cache is out of date is implementation defined ๐Ÿ‘‘

Using either cache is totally optional in DLSw. An implementation can always send explorer frames, or use either or both caches. Its choice ๐Ÿ’…

The next sections describe the FSMs for explorer frames. The DLC events and actions are a subset of what's in section 5.2 for the main circuit FSM ๐Ÿงš


5.4.1 CANUREACH/ICANREACH Explorer FSM ๐Ÿฆ„

This FSM handles explorer frames that get routed by MAC address. There's one instance of it for each Data Link ID (that's the Target and Origin MAC/SAP pair) with explorer traffic flowing ๐ŸŒˆ The states are:

State Name            Description
----------            -----------
RESET                 The initial state.

SENT_EX               Local DLSw has issued an explorer message

RECEIVED_EX           Local DLSw has received an explorer message

5.4.1.1 RESET State ๐Ÿซง

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive CANUREACH_ex | If replying from    | If DLC_RESOLVE sent, |
|                      | cache, send         |   RECEIVED_EX        |
|                      | ICANREACH_ex        |                      |
|                      | else if allowed to  |                      |
|                      | test availability,  |                      |
|                      | issue DLC_RESOLVE.  |                      |
|                      | Optionally update   |                      |
|                      | cache.              |                      |
+----------------------+---------------------+----------------------+
| Receive ICANREACH_ex | Optionally update   | RESET                |
|                      | cache               |                      |
+----------------------+---------------------+----------------------+
| DLC_RESOLVE_C        | Send CANUREACH_ex   | SENT_EX              |
+----------------------+---------------------+----------------------+

RESET is the starting state for the CANUREACH/ICANREACH explorer FSM ๐ŸŒธ You leave it when a DLC_RESOLVE_C request comes in from the DLC, or when a CANUREACH_ex arrives from a remote DLSw.

A DLSw implementation can optionally reply to CANUREACH_ex messages using cached topology info ๐Ÿ’œ If it does, the DLC_RESOLVE exchange (the TEST) isn't needed. If there's no cache, or nothing matches, and the DLC allows TEST, the DLSw issues DLC_RESOLVE to find the target MAC and moves to RECEIVED_EX. If there's no cache entry and the DLC doesn't allow TEST, a received CANUREACH_ex is simply ignored ๐Ÿ™ˆ

5.4.1.2 SENT_EX State ๐Ÿ“ฎ

+----------------------+---------------------+----------------------+
|        Event         |      Action(s)      |      Next State      |
+----------------------+---------------------+----------------------+
| Receive ICANREACH_ex | DLC_RESOLVE_R       | RESET                |
|                      | Optionally update   |                      |
|                      | cache               |                      |
+----------------------+---------------------+----------------------+
| DLC_RESOLVE_C        |                     | SENT_EX              |
+----------------------+---------------------+----------------------+

SENT_EX is entered once the DLSw has sent a CANUREACH_ex message to locate a MAC address ๐Ÿฆ‹ You leave this state when a remote DLSw sends back a matching ICANREACH_ex, or after an implementation defined timeout. DLC_RESOLVE events that show up in this state line up with TEST retries from the origin DLC station, so they get absorbed โœจ

An implementation can pick how it handles explorer frame crossover. It can use totally separate FSM instances and just let both ends send TEST frames, or it can detect a reverse CANUREACH_ex frame right here and send an ICANREACH_ex message plus the DLC_RESOLVE_R action instead ๐Ÿ’…

5.4.1.3 RECEIVED_EX State ๐Ÿฆ‹

okay so this is the RECEIVED_EX state, and it's giving "I got a question and I'm figuring out the answer" ๐Ÿ”โœจ

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive CANUREACH_ex | Optionally update   | RECEIVED_EX          |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | Receive ICANREACH_ex |                     | RECEIVED_EX          |
   +----------------------+---------------------+----------------------+
   | DLC_RESOLVED         | Send ICANREACH_ex   | RESET                |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+

RECEIVED_EX gets entered when the DLSw has gotten a CANUREACH_ex from a remote DLSw and has sent out a DLC_RESOLVE to find the MAC address ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ’…. It gets exited once the DLC_RESOLVED response shows up, or after an implementation defined timeout, whichever comes first โฐ.

So if the target MAC is found, the DLSw has to reply to the first CANUREACH_ex that got it into this state, no skipping that one ๐Ÿซถ. If more CANUREACH_ex messages roll in from other remote DLSw partners while it's in this state, the DLSw can reply to those too if it wants to, but it's not required to do that, so no pressure ๐Ÿ’œ.

An implementation gets to pick how it handles explorer frame crossover ๐Ÿฆ‹. It can either use totally separate FSM instances and just let both ends send TEST frames, or it can catch that reverse DLC_RESOLVE_C event right here and send an ICANREACH_ex message plus do a DLC_RESOLVE_R action instead โœจ. Both are valid, bestie, it's a choice ๐ŸŒˆ.


5.4.2 NETBIOS_NQ/NR Explorer FSM ๐ŸŽ€

This FSM is for handling explorer frames that get routed by NetBIOS names ๐Ÿงš. There's one instance of it for every unique combo of Source Name, Destination Name, Data 2 field and Response Correlator, so it's super specific, iykyk ๐Ÿ’–.

   State Name            Description
   ----------            -----------
   RESET                 The initial state.

   SENT_EX               Local DLSw has issued an explorer
                         message

   RECEIVED_EX           Local DLSw has received an explorer
                         message

   SENT_REC_EX           An explorer frame has been both sent
                         and received for the same (potential)
                         NetBIOS circuit.

5.4.2.1 RESET State ๐ŸŒธ

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NQ_ex| DLC_DGRM(NAME_QUERY)| RECEIVED_EX          |
   |                      | Optionally update   |                      |
   |                      | cache.              |                      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NR_ex| Optionally update   | RESET                |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_QUERY)| Send NETBIOS_NQ_ex  | SENT_EX              |
   +----------------------+---------------------+----------------------+

RESET is the starting state for the NETBIOS_NQ/NR explorer FSM ๐Ÿ“. It gets exited when the DLC gets either a NETBIOS_NQ_ex or a DLC_DGRM carrying a NetBIOS NAME_QUERY frame ๐Ÿ‘€. If a NETBIOS_NQ_ex comes in, the NAME_QUERY gets passed along to the DLC and the FSM moves over to RECEIVED_EX. If a NetBIOS NAME_QUERY frame comes in, the NETBIOS_NQ_ex gets sent out to the appropriate DLSw partners (see below), and the FSM moves to SENT_EX ๐Ÿš€.

Here's the tea โ˜•: SNA traffic can skip the CANUREACH_ex/ICANREACH_ex exchange if the MAC location is already cached, but NETBIOS_NQ_ex/NETBIOS_NR_ex frames have to be issued every single time during NetBIOS session setup ๐Ÿ˜ญ. That's because the NetBIOS session numbers need to get swapped correctly between the DLC end stations ๐Ÿ’…. If the location of a NetBIOS name is already known from cached data, the NETBIOS_NQ_ex only needs to go to the cached DLSw partners โœจ. Otherwise the NETBIOS_NQ_ex should go out to every partner that supports NetBIOS ๐ŸŒˆ.

5.4.2.2 SENT_EX State ๐Ÿงš

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NQ_ex| DLC_DGRM(NAME_QUERY)| SENT_REC_EX          |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NR_ex| DLC_DGRM(NAME_RECOG)| RESET                |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_QUERY)| Send NETBIOS_NQ_ex  | SENT_EX              |
   | (different local     | Optionally update   |                      |
   |  session number than | cache               |                      |
   |  existing searches)  |                     |                      |
   +----------------------+---------------------+----------------------+

SENT_EX kicks in when the local DLSw sends a NETBIOS_NQ_ex out to its remote DLSw partners ๐Ÿ“ค. It gets exited when a NETBIOS_NR_ex comes back from a remote DLSw, or if a matching NETBIOS_NQ_ex comes in from a remote DLSw (that's the NETBIOS_NQ_ex crossover case, bestie ๐Ÿ™ˆ). If the local NetBIOS end station sends a NAME_QUERY with a different session number from any earlier NAME_QUERY for this search, that NAME_QUERY gets passed to the DLSw partners so the session numbers keep getting handled correctly ๐Ÿ’–.

5.4.2.3 RECEIVED_EX State ๐Ÿ’œ

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NQ_ex| DLC_DGRM(NAME_QUERY)| RECEIVED_EX          |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NR_ex|                     | RECEIVED_EX          |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_QUERY)| Send NETBIOS_NQ_ex  | SENT_REC_EX          |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_RECOG)| Send NETBIOS_NR_ex  | RESET                |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+

RECEIVED_EX is entered when the local DLSw gets a NETBIOS_NQ_ex message from a remote DLSw ๐Ÿ“ฅ. It gets exited when a NAME_RECOGNIZED NetBIOS frame arrives from the DLC, which wraps up the query โœ…, or when a matching NAME_QUERY comes in from the DLC (aka NAME_QUERY crossover, lowkey a plot twist ๐ŸŽญ).

5.4.2.4 SENT_REC_EX State ๐ŸŒท

   +----------------------+---------------------+----------------------+
   |        Event         |      Action(s)      |      Next State      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NQ_ex| DLC_DGRM(NAME_QUERY)| SENT_REC_EX          |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | Receive NETBIOS_NR_ex| DLC_DGRM(NAME_RECOG)| RECEIVED_EX          |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_QUERY)| Send NETBIOS_NQ_ex  | SENT_REC_EX          |
   | (different local     | Optionally update   |                      |
   |  session number than | cache               |                      |
   |  existing searches)  |                     |                      |
   +----------------------+---------------------+----------------------+
   | DLC_DGRM (NAME_RECOG)| Send NETBIOS_NR_ex  | SENT_EX              |
   |                      | Optionally update   |                      |
   |                      | cache               |                      |
   +----------------------+---------------------+----------------------+

This state is required if an implementation wants to handle NQ/NR crossover cases from one FSM instance by spotting 'opposite' NAME_QUERY attempts between the same two NetBIOS names ๐Ÿ”. If separate FSM instances are used instead, this state isn't required and the transitions into it from other states can be removed ๐Ÿงฉ.

SENT_RCV_EX gets exited once the NAME_QUERY search is resolved in either direction ๐Ÿ. If the local NetBIOS end station sends a NAME_QUERY with a different session number from any NAME_QUERY it already sent for this search, that NAME_QUERY gets passed to the DLSw partners so the session number exchange stays correct ๐Ÿ’….

5.4.2.5 NetBIOS Session Numbers ๐Ÿฆ‹

NetBIOS NAME_QUERY and NAME_RECOGNIZED frames are how the end stations swap NetBIOS session numbers ๐Ÿ”ข. For NetBIOS to work right over DLSw, every SSP NETBIOS_NQ_ex frame a DLSw receives has to make NetBIOS NAME_QUERY frames flow on the LAN with the new session number from that NETBIOS_NQ_ex โœจ. These frames can't get answered from a cache of local NetBIOS names the way MAC addresses and CANUREACH_ex messages can ๐Ÿ™…โ€โ™€๏ธ.

Also, NAME_QUERY messages usually get retried a bunch of times on the LAN ๐Ÿ”. Making and absorbing those frames is outside the scope of the FSM above, so that's a different story ๐Ÿ’œ.


6. Protocol Flow Diagrams ๐ŸŽ€

The Switch-to-Switch Protocol is what sets up and takes down circuits between a pair of Data Link Switches ๐Ÿ”Œ. Once a circuit is up, the end stations on the local networks can use LLC Type 1 (connectionless UI frames) protocols end-to-end ๐ŸŒˆ. The end systems can also set up an end-to-end connection to support LLC Type 2 (connection oriented I frames) protocols, where Type 2 I frames go end-to-end and supervisory frames get handled locally ๐Ÿซถ.

The term Data Link is used in this document to mean both a "logical data link" when Type 1 LLC services are in play, and a "data link connection" when Type 2 LLC services are in play โœจ. Either way, the Data Link is identified by the Data Link ID defined in section 3.2 ๐Ÿชช.

NOTE: THIS SECTION CONTAINS EXAMPLES ONLY. IT CANNOT AND DOES NOT SHOW ALL POSSIBLE VARIATIONS AND OPTIONS ON PROTOCOL FLOWS FOR SNA/SDLC, SSP, AND LLC PROTOCOLS. ๐Ÿ™ˆ

6.1 Connect Protocols ๐Ÿ’–

The two basic startup flows, from a pure FSM point of view, are shown below ๐Ÿงš. The first one is a startup that involves XIDs, and the second one doesn't use XIDs at all ๐Ÿ“.

Flow #1 - DLSw Startup With XIDs โœจ

Okay bestie, this is Flow #1, where DLSw starts up with XIDs ๐Ÿฆ‹ Both stations start out disconnected, then a bunch of resolve and XID messages get passed around until they're both connected. It's giving full choreography ๐Ÿ’…

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                    disconnected

              DLC_RESOLVE_C   CANUREACH_ex
              ----------->    ----------->
              DLC_RESOLVE_R     ICANREACH_ex
               <-----------     <-----------

              DLC_XID         CANUREACH_cs    DLC_START_DL
              ----------->    ----------->    ----------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED
                                <-----------    <-----------
          circuit_established                 circuit_pending
                              REACH_ACK
                              ----------->   circuit_established

                              XIDFRAME        DLC_XID
                              ----------->    ----------->

                     DLC_XID        XIDFRAME         DLC_XID
                <-----------    <-----------    <-----------
              DLC_XID         XIDFRAME        DLC_XID
              ----------->    ----------->    ----------->

                 DLC_XIDs       XIDFRAMEs        DLC_XIDs
              <------------>  <------------>  <------------>

              DLC_CONTACTED   CONTACT         DLC_CONTACT
              ----------->    ----------->    ----------->
              connect_pending                 contact_pending

                 DLC_CONTACT       CONTACTED    DLC_CONTACTED
                <-----------    <-----------    <-----------
                 connected                       connected

                DLC_INFOs        IFRAMEs        DLC_INFOs
              <------------>  <------------>  <------------>

Now let's map the LAN events onto the DLC events and actions for Flow #1. Here's what that looks like ๐ŸŽ€

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                    disconnected

TEST_cmd      DLC_RESOLVE_C    CANUREACH_ex               TEST_cmd
----------->  ----------->     ----------->               ---------->
   TEST_rsp   DLC_RESOLVE_R     ICANREACH_ex                 TEST_rsp
 <---------    <-----------   <-----------             <-----------
null XID      DLC_XID          CANUREACH_cs    DLC_START_DL
----------->  ----------->     ----------->    ----------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED
                                <-----------    <-------------
           circuit_established                circuit_pending
                              REACH_ACK
                              ----------->  circuit_established

                              XIDFRAME         DLC_XID       null XID
                              ----------->     --------->    -------->
        XID        DLC_XID        XIDFRAME         DLC_XID          XID
  <--------   <-----------    <-----------    <-----------    <--------
    XIDs         DLC_XIDs      XIDFRAMEs        DLC_XIDs         XIDs
<---------->  <---------->  <------------>  <------------>  <--------->
SABME         DLC_CONTACTED   CONTACT         DLC_CONTACT     SABME
----------->  ----------->    ----------->    ----------->    -------->
              connect_pending                 contact_pending

          UA     DLC_CONTACT     CONTACTED    DLC_CONTACTED          UA
  <---------   <-----------   <-----------    <-----------    <--------
                  connected                        connected

  IFRAMEs       DLC_INFOs        IFRAMEs        DLC_INFOs       IFRAMEs
<---------->  <----------->  <------------>  <------------>  <-------->

Some implementations like to answer the SABME right away, and they can use the same events to do it ๐ŸŒธ

SABME         DLC_CONTACTED   CONTACT         DLC_CONTACT     SABME
----------->  ----------->    ----------->    ----------->    -------->
          UA  connect_pending                 contact_pending
  <---------
RR
----------->
         RNR
  <---------

          RR    DLC_CONTACT       CONTACTED    DLC_CONTACTED          UA
  <---------   <-----------    <-----------    <-----------    <--------
                 connected                        connected

   IFRAMEs      DLC_INFOs        IFRAMEs        DLC_INFOs      IFRAMEs
<---------->  <------------>  <------------>  <------------>  <-------->

Flow #2 - DLSw Startup Without XIDs (circuit setup) ๐Ÿงš

Flow #2 skips the XIDs and goes straight to setting up the circuit ๐Ÿ’œ

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                    disconnected

              DLC_CONTACTED   CANUREACH_cs    DLC_START_DL
              ----------->    ----------->    ----------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED
                                <-----------    <-----------
          circuit_established                 circuit_pending
                              REACH_ACK
                              ----------->   circuit_established

                              CONTACT         DLC_CONTACT
                              ----------->    ----------->
              connect_pending                 contact_pending

                 DLC_CONTACT       CONTACTED    DLC_CONTACTED
                <-----------    <-----------    <-----------
                 connected                       connected

                DLC_INFOs        IFRAMEs        DLC_INFOs
              <------------>  <------------>  <------------>

Next up is the LAN-event mapping for Flow #2, where we also add a NETBIOS_NQ and a NETBIOS_NR_ex ๐Ÿ“

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                     disconnected

NAME_QUERY    DLC_DGRM        NETBIOS_NQ_ex   DLC_DGRM       NAME_QUERY
----------->  ----------->    ----------->    ----------->   --------->

   NAME_RECOG    DLC_DGRM      NETBIOS_NR_ex     DLC_DGRM    NAME_RECOG
 <-----------  <------------   <-----------    <-----------  <---------

SABME         DLC_CONTACTED   CANUREACH_cs    DLC_START_DL
----------->  ----------->    ----------->    ----------->
               circuit_start                 resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED
                                <-----------    <-----------
            circuit_established                circuit_pending
                              REACH_ACK
                              ----------->   circuit_established

                              CONTACT         DLC_CONTACT     SABME
                              ----------->    ----------->    --------->
             connect_pending                 contact_pending

          UA   DLC_CONTACT       CONTACTED    DLC_CONTACTED           UA
  <---------  <-----------    <-----------    <-----------    <---------
                connected                       connected

   IFRAMEs       DLC_INFOs       IFRAMEs        DLC_INFOs       IFRAMEs
<------------> <------------> <------------>  <------------>  <-------->

Okay, the big idea here is "DLSw is a big 802.2 LAN" ๐ŸŒˆ Under that paradigm, every other DLC type (SDLC for now, QLLC, channel, or whatever shows up later) gets handled by a "DLC transformation layer." That layer translates the specific protocol's events into the matching DLSw DLC events, and it translates DLSw DLC actions back into the matching protocol actions ๐Ÿ”ฅ The XIDs that go out in the SSP XIDFRAME should stay 802.2-ish (so the ABM bit is set), and the DLC transformation layer is the one that adjusts the XID to fit its particular DLC type ๐Ÿ’–

Here's an example of a leased SDLC PU 2.0 device acting as the origin station ๐ŸŽ€ It should use Flow #2, because we can't tell whether the other side is a LAN, a switched line, or a leased line ๐Ÿคทโ€โ™€๏ธ

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                     disconnected

implementer's  DLC_RESOLVE_C   CANUREACH_ex
choice (power  ----------->    ----------->
up, configuration
change,        DLC_RESOLVE_R   ICANREACH_ex
never,          <-----------    <-----------
connect timer,etc.)

PU 2.0 is
configured
in DLSw to    DLC_XID(null)   CANUREACH_cs    DLC_START_DL
call in       ----------->    ----------->    ----------->
              circuit_start                   resolve_pending

                                ICANREACH_cs   DLC_DL_STARTED
                                <-----------   <-----------
           circuit_established                circuit_pending
                                REACH_ACK
                                ----------->   circuit_established

                              XIDFRAME        DLC_XID
                              ----------->    ----------->

                    DLC_XID        XIDFRAME         DLC_XID
respond with   <-----------    <-----------    <-----------
XID configured
for station or
forward XID to
station and
send response  DLC_XID        XIDFRAME        DLC_XID
               ----------->   ----------->    ----------->

        SNRM    DLC_CONTACT       CONTACT      DLC_CONTACTED
  <---------   <-----------    <-----------    <------------
              contact_pending                    connect_pending

UA            DLC_CONTACTED    CONTACTED       DLC_CONTACT
---------->    ----------->    ----------->    ----------->
                connected                       connected

   IFRAMEs       DLC_INFOs        IFRAMEs        DLC_INFOs

okay bestie, picking up right where we left off ๐Ÿ’…

<----------->  <------------>  <------------>  <------------>

Here's a switched SDLC PU 2.0 device playing the origin station ๐Ÿฆ‹ The little boxes are the same cast as always: the origin station, the origin DLSw partner, the IP network in the middle, then the target DLSw partner and the target station. The message flow is what matters, so scroll down and vibe with it ๐Ÿงš

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                     disconnected

implementer's  DLC_RESOLVE_C   CANUREACH_ex
choice (power  ----------->    ----------->
up, configuration
change,        DLC_RESOLVE_R   ICANREACH_ex
never,          <-----------    <-----------
connect timer,etc.)

XID(null)     DLC_XID(null)   CANUREACH_cs    DLC_START_DL
----------->  ----------->    ----------->    ----------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED
                                <-----------    <-----------
            circuit_established                 circuit_pending
                                REACH_ACK
                                ----------->   circuit_established
                                XIDFRAME      DLC_XID
                                ----------->  ----------->
         XID        DLC_XID         XIDFRAME         DLC_XID
  <---------   <-----------     <-----------    <-----------
XID           DLC_XID         XIDFRAME        DLC_XID
--------->    ----------->    ----------->    ----------->

        SNRM    DLC_CONTACT       CONTACT      DLC_CONTACTED
  <---------   <-----------    <-----------    <-----------
              contact_pending                 connect_pending

UA            DLC_CONTACTED   CONTACTED       DLC_CONTACT
--------->    ----------->    ----------->    ----------->
                 connected                      connected

   IFRAMEs      DLC_INFOs        IFRAMEs        DLC_INFOs
<---------->  <------------>  <------------>  <------------>

Next up: a leased SDLC PU 2.0 device as the target station ๐ŸŒธ This time the target is the SDLC box, so the DLSw partner has to answer for it. Notice the notes in the diagram about when it replies, like what happens with TEST/SNRM/DISC, and how the XID gets handled ๐Ÿ‘€

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw       Target
 Station        partner                          partner         Station
                                                                 (SDLC)
              disconnected                    disconnected

              DLC_RESOLVE_C   CANUREACH_ex
              ----------->    ----------->   reply if virtual MAC/SAP
                                             for SDLC station is
                                             configured, if SDLC
                                             station responds to
              DLC_RESOLVE_R    ICANREACH_ex  TEST/SNRM/DISC, etc.
               <-----------    <-----------
              DLC_XID         CANUREACH_cs    DLC_START_DL    SNRM
              ----------->    ----------->    ----------->    --------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED        UA
                                <-----------    <-----------    <-------
          circuit_established                 circuit_pending
                                                              RNR
                              REACH_ACK                       --------->
                              ----------->   circuit_established
                              XIDFRAME        DLC_XID
                              ----------->    -----------> respond with
                                                           XID configured
                                                           for station
                                                           or forward
                                                           XID to
                                                           station and
                                                           send
                   DLC_XID        XIDFRAME         DLC_XID response
              <-----------    <-----------    <-----------
              DLC_CONTACTED   CONTACT         DLC_CONTACT     RR
              ----------->    ----------->    ----------->    --------->
             connect_pending                contact_pending

                 DLC_CONTACT       CONTACTED    DLC_CONTACTED
                <-----------    <-----------    <-----------
                connected                        connected

                DLC_INFOs        IFRAMEs        DLC_INFOs       IFRAMEs
              <------------>  <------------>  <------------>  <------->

Now the mirror image: a switched SDLC PU 2.0 device as the target station ๐ŸŽ€ Same setup, but this time the DLSw side answers TEST/XID/SNRM/DISC, and the XID that was received gets echoed back, so the flow looks a little different ๐Ÿ’–

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw       Target
 Station        partner                          partner         Station
                                                                 (SDLC)
              disconnected                    disconnected

              DLC_RESOLVE_C   CANUREACH_ex
              ----------->    ----------->    reply if virtual MAC/SAP
                                              for SDLC station is
                                              configured, if SDLC
                                              station responds to
              DLC_RESOLVE_R     ICANREACH_ex  TEST/XID/SNRM/DISC, etc.
               <-----------     <-----------
              DLC_XID         CANUREACH_cs    DLC_START_DL    XID
              ----------->    ----------->    ----------->    --------->
              circuit_start                   resolve_pending

                                ICANREACH_cs   DLC_DL_STARTED        XID
                                <-----------   <-----------    <--------

          circuit_established                 circuit_pending

                              REACH_ACK
                              ----------->   circuit_established

                                XIDFRAME        DLC_XID
                                ----------->    -----------> respond
                                                             with XID
                                                             received
                     DLC_XID        XIDFRAME        DLC_XID  above
                <-----------    <-----------     <---------
             DLC_CONTACTED   CONTACT         DLC_CONTACT     SNRM
             ----------->    ----------->    ----------->    --------->
             connect_pending                  contact_pending

                DLC_CONTACT       CONTACTED    DLC_CONTACTED          UA
               <-----------    <-----------    <-----------    <--------
                connected                        connected

                DLC_INFOs        IFRAMEs        DLC_INFOs       IFRAMEs
              <------------>  <------------>  <------------>  <-------->

Last one, and it's a fun one ๐ŸŒˆ This is an SDLC T2.1 device as the target station. The T2.1 origin station looks exactly like the LAN T2.1 origin station, so you don't need a separate picture for it ๐Ÿซถ Here the DLSw side can check whether the station is powered up using TEST/XID/DISC, and you'll see null XIDs and a bunch of XIDs flying around before the SNRM finally lands ๐Ÿ˜ญ

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

              disconnected                    disconnected

              DLC_RESOLVE_C   CANUREACH_ex
              ----------->    ----------->    implementer's choice
                                              (virtual MAC/SAP
                                               configured,
                                               check to see if station
                                               is powered up using
              DLC_RESOLVE_R     ICANREACH_ex   TEST/XID/DISC, etc.)
               <-----------     <-----------
              DLC_XID         CANUREACH_cs    DLC_START_DL    null XID
              ----------->    ----------->    ----------->    --------->
              circuit_start                   resolve_pending

                                ICANREACH_cs    DLC_DL_STARTED       XID
                                <-----------    <-----------    <-------

          circuit_established                 circuit_pending
                              REACH_ACK
                              ----------->   circuit_established
                              XIDFRAME        DLC_XID
                              ----------->    ----------->  respond with
                                                            XID received
                     DLC_XID        XIDFRAME        DLC_XID above
                <-----------    <-----------    <----------
                 DLC_XIDs       XIDFRAMEs        DLC_XIDs         XIDs
              <------------>  <------------>  <------------>  <-------->
              DLC_CONTACTED   CONTACT         DLC_CONTACT     SNRM
              ----------->    ----------->    ----------->    --------->
              connect_pending                 contact_pending

                 DLC_CONTACT       CONTACTED    DLC_CONTACTED         UA
                <-----------    <-----------    <-----------    <-------
                connected                        connected

                DLC_INFOs        IFRAMEs        DLC_INFOs       IFRAMEs
              <------------>  <------------>  <------------>  <-------->

okay so this one's about restarting the whole end-to-end connection ๐Ÿ’… the figure below shows the message flows that happen when that restart goes down. the Data Link Switches terminate the existing connection and land in the Circuit Established state, just waiting for a brand new connection to kick off ๐Ÿฆ‹

  Data Link   Data Link                     Data Link   Data Link
   Control     Switch                        Switch      Control
  ---------------------                     ---------------------
       +-----------+                             +-----------+
       | Connected |                             | Connected |
 SABME +-----------+                             +-----------+
----------->                 RESTART_DL
   DM           ------------------------------------->     DISC
<-----------                                               -------->
                                                            UA
                      DL_RESTARTED (Case 1)              <--------
                <-------------------------------------
       +-----------+                             +-----------+
       |Circuit Est|                             |Circuit Est|
       +-----------+                             +-----------+
                     ........... or ...........
 SABME
----------->           DL_RESTARTED (Case 2)
    UA          <-------------------------------------
<-----------                                     +-----------+
                                                 |Circuit Est|
                             CONTACT             +-----------+
   RNR           ------------------------------------>
<----------

Figure 5. DLSw Link Restart Message Protocols

bestie, when the origin station sends a SABME command, the origin DLSw sends a RESTART_DL message to the target DLSw. a DM response also goes back to the origin station and the data link gets restarted ๐Ÿ”ฅ

when the target DLSw gets RESTART_DL, it issues a DISC command to the target station. that station is expected to send back a UA response. then the target DLSw restarts its own data link and sends a DL_RESTARTED message back to the origin DLSw. during all of this, both Data Link Switches move from the Connected state to the Circuit Established state โœจ

if the origin station resends the SABME command, the origin DLSw sends a CONTACT message to the target DLSw. if SABME shows up before DL_RESTARTED arrives (that's case 2 in the figure, iykyk ๐Ÿ™ˆ), the CONNECT message gets held until DL_RESTARTED comes in. from there, everything lines up with the connect sequence we already covered ๐Ÿ’–


6.3. Disconnect Protocols ๐Ÿšช

this figure shows what happens when the end system ends an existing connection. it's not just the connection that gets terminated, the circuit between the Data Link Switches gets taken down too ๐Ÿ’€

 Data Link  Data Link                      Data Link  Data Link
  Control    Switch                         Switch     Control
 --------------------                      --------------------
      +-----------+                             +-----------+
      | Connected |                             | Connected |
      +-----------+                             +-----------+
  DISC
---------->                  HALT_DL
   UA         ------------------------------------->      DISC
<----------                                              --------->
                                                           UA
                           DL_HALTED                    <--------
              <-------------------------------------
      +-----------+                             +-----------+
      |Disconnectd|                             |Disconnectd|
      +-----------+                             +-----------+

                      ......... or ..........

      +-----------+                             +-----------+
      | Connected |                             | Connected |
      +-----------+                             +-----------+
   DISC              TCP Connection Failure               DISC
<--------     <------------------------------------>    --------->
    UA                                                     UA
-------->                                               <--------
      +-----------+                             +-----------+
      |Disconnectd|                             |Disconnectd|
      +-----------+                             +-----------+

Figure 6. DLSw Disconnect Message Protocols

so when the origin station sends a DISC command, the origin DLSw replies with a UA response and issues a HALT_DL message to the target DLSw. once the target DLSw gets HALT_DL, it sends a DISC command to the target station. the target station responds with a UA response, and that makes the target DLSw send a DL_HALTED message back to the origin DLSw. during this whole exchange, both Data Link Switches go from the Connected state to the Disconnected state ๐Ÿซถ

now the other plot twist ๐Ÿ˜ญ if the TCP connection between two Data Link Switches fails, every connection multiplexed on that failed TCP connection gets taken down. that means both Data Link Switches send DISC commands to all the local systems tied to those failed connections. the second a Data Link Switch sends its DISC command, it enters the DISCONNECTED state for each circuit ๐Ÿ’œ


7.0. Capabilities Exchange Formats/Protocol ๐ŸŽ€

the Data Link Switching Capabilities Exchange is a special DLSw Switch-to-Switch control message. it describes what the sending data link switch is capable of ๐Ÿ‘‘ it gets sent right after the switch-to-switch connection is established, and it can also be sent during run time, optionally, if some operational parameters have changed and the partner switch needs to know ๐ŸŒˆ

the actual contents live in the data field right after the SSP message header. the Capabilities Exchange itself is formatted as a single General Data Stream (GDS) Variable made up of multiple type "LT" structured subfields ๐Ÿงš

the SSP Message Header has these fields set for the Capabilities Exchange:

Offset   Field                 Value
------   -----                 -----
0x00     Version Number        0x31
0x01     Header Length         0x48 (decimal 72)
0x02     Message Length        same as LL in GDS Variable
0x14     Message Type          0x20 (CAP_EXCHANGE)
0x16     Protocol Id           0x42
0x17     Header Number         0x01
0x23     Message Type          0x20 (CAP_EXCHANGE)
0x38     Direction             0x01 for CapEx request
                               0x02 for CapEx response

any other SSP header fields aren't referenced here, and they should be set to zero ๐Ÿ“

the DLSw Capabilities Exchange Request has this overall format:

+----+----+-----------------+
| LL | ID | Control Vectors |
+----+----+-----------------+
  • 0-1: the length, in binary, of the DLSw Capabilities Exchange Request GDS Variable. the value of LL is the sum of the length of all fields in the GDS Variable (that's the length of LL plus the length of ID plus the length of Control Vectors) ๐Ÿงฎ
  • 2-3: GDS Id, which is 0x1520 ๐Ÿ”ฅ
  • 4-n: Control Vectors, made up of type LT structured subfields (aka the DLSw Capabilities Exchange Structured Subfields) ๐Ÿ’…

type LT structured subfields have a 1-byte length field (the "L"), a 1-byte type field (the "T"), and n bytes of data. the length field counts itself plus the structured subfield. the structured subfield is the type field plus the data, so the length works out to n + 2. this means all data inside a structured subfield is limited to 253 bytes โญ

7.1. Control Vector Id Range ๐ŸŒธ

Control Vector identifiers (aka Type) from 0x80 through 0xCF are reserved for use by the Data Link Switching standard ๐Ÿ“š

Control Vector identifiers (aka Type) from 0xD0 through 0xFD are used for vendor-specific stuff ๐Ÿ› ๏ธ

here are the currently defined vectors:

Vector Description                       Hex Value

Vendor Id Control Vector                 0x81
DLSw Version Control Vector              0x82
Initial Pacing Window Control Vector     0x83
Version String Control Vector            0x84
Mac Address Exclusivity Control Vector   0x85
Supported SAP List Control Vector        0x86
TCP Connections Control Vector           0x87
NetBIOS Name Exclusivity Control Vector  0x88
MAC Address List Control Vector          0x89
NetBIOS Name List Control Vector         0x8A
Vendor Context Control Vector            0x8B
Reserved for future use                  0x8C - 0xCF
Vendor Specific                          0xD0 - 0xFD

7.2. Control Vector Order and Continuity ๐Ÿฆ‹

the order matters a LOT here, because the required control vectors can seriously change how the Capabilities Exchange GDS Variable gets parsed ๐Ÿ˜ญ so the required ones have to come first, in this exact order: Vendor Id, DLSw Version Number, Initial Pacing Window, Supported SAP List. everything else can show up in any order โœจ

control vectors that can repeat within the same message (like the MAC Address List Control Vector and the NetBIOS Name List Control Vector) aren't necessarily next to each other. it's advisable, but not required, to put the Exclusivity Control Vector before either of those two, so the individual MAC addresses or NetBIOS names are already known before they get parsed ๐Ÿ™Œ

both the Vendor Context and Vendor Specific control vectors can be repeated. if there are multiple Vendor Context control vectors, the specified context stays in effect for all Vendor Specific control vectors until the next Vendor Context control vector shows up in the Capabilities Exchange ๐Ÿซง

7.3. Initial Capabilities Exchange ๐Ÿ’–

the Capabilities Exchange is always the first SSP message sent on a new SSP connection between two DLSw switches, no exceptions ๐Ÿš€ this initial exchange tells each switch which DLSw version the other is running, plus any other required info and details about optional extensions the switches can support ๐Ÿ’œ

if a DLSw gets an initial capabilities message that's formatted wrong, or has invalid or unsupported data that stops it from interoperating correctly with the partner DLSw, it should send a Capabilities Exchange negative response ๐Ÿ™ˆ

if a DLSw gets a negative response to its own initial capabilities message, it should take down its TCP connections with the offended partner ๐Ÿ’€

Note: Pre v1.0 DLSw implementations don't send or respond to capabilities messages. you can spot them by the lack of a capabilities exchange as the first message on a new SSP connection. this document doesn't try to specify how to interoperate with back-level DLSw implementations. ๐Ÿผ

7.4. Run-Time Capabilities Exchange ๐ŸŽ€

okay so the capabilities exchange always happens when the SSP connection starts between two DLSw switches ๐Ÿฆ‹ but it can also happen at run-time, usually when someone changes a config โœจ

running this is OPTIONAL ๐Ÿ’… if a node doesn't support receiving or using a run-time exchange and gets one anyway, it SHOULD discard it quietly (no negative response, bestie ๐Ÿ™ˆ). if a node does support it, it SHOULD send back a positive or negative response, whichever fits. the one who gets a negative response is not REQUIRED to tear down its TCP connections with the partner who sent it. no drama needed ๐Ÿ’œ

a run-time exchange can have one or more of these control vectors. fun fact: the ones REQUIRED at start-up are NOT in a run-time exchange ๐Ÿ‘‘

  1. MAC Address Exclusivity CV,
  2. NetBIOS Name Exclusivity CV,
  3. MAC Address List CV,
  4. NetBIOS Name List CV,
  5. Supported SAP List CV,
  6. Vendor Context CV,
  7. Vendor Specific CVs

the big rule here: a run-time exchange is a REPLACEMENT operation ๐Ÿงš so every relevant MAC address and NetBIOS name MUST be included in it. and changes to capabilities at run-time will not affect existing link station circuits, so your current connections are safe ๐Ÿซถ

7.5. Capabilities Exchange Filtering Responsibilities ๐Ÿ’…

ok, quick one ๐ŸŒธ the people who receive the SAP, MAC, and NetBIOS lists are not REQUIRED to actually use them for filtering traffic, whether that's at start-up or at run-time. no pressure, lol โœจ

7.6. DLSw Capabilities Exchange Structured Subfields ๐ŸŒˆ

here's the lineup of the Capabilities Exchange subfields. the details for each one are in the sections right after this table ๐Ÿ’–

         Required                      Allowed @
    ID   @ Startup  Length  Repeatable* Runtime  Order  Content
   ====  =========  ======  ==========  =======  =====  ===============
   0x81     Y        0x05        N         N       1    Vendor ID

   0x82     Y        0x04        N         N       2    DLSw Version

   0x83     Y        0x04        N         N       3    Initial pacing
                                                        window

   0x84     N      >=0x02        N         N       5+   Version String

   0x85     N        0x03        N         Y       5+   MAC Address
                                                        Exclusivity

   0x86     Y        0x12        N         Y       4    Supported SAP
                                                        List

   0x87     N        0x03        N         N       5+   TCP Connections

   0x88     N        0x03        N         Y       5+   NetBIOS Name
                                                        Exclusivity

   0x89     N        0x0E        Y         Y       5+   MAC Address
                                                        List

   0x8A     N      <=0x13        Y         Y       5+   NetBIOS Name
                                                        List

   0x8B     N        0x05        Y         Y       5+   Vendor Context

   0xD0     N       varies       Y         Y       5+   Vendor Specific

   *Note: "Repeatable" means a Control Vector is repeatable within a single
   message.

7.6.1. Vendor Id (0x81) Control Vector ๐Ÿฆ‹

the Vendor Id CV tells everyone the manufacturer's IEEE-assigned Organizationally Unique Identifier (OUI) for the Data Link Switch that's sending the DLSw Capabilities Exchange ๐Ÿ’œ the OUI goes out in non-canonical (Token-Ring) format. this one is REQUIRED and MUST be the first control vector, so it's always the main character ๐Ÿ‘‘

Offset  Length  Value  Contents
------  ------  -----  --------
   0       1    0x05   Length of the Vendor Id structured
                       subfield

   1       1    0x81   key = 0x81  that identifies this as the
                       Vendor Id structured subfield

  2-4      3           the 3-byte Organizationally Unique
                       Identifier (OUI) for the vendor
                       (non-canonical format)

7.6.2. DLSw Version (0x82) Control Vector โœจ

this one tells you which version of the DLSw standard the sending Data Link Switch supports ๐ŸŒธ it's REQUIRED and MUST follow the Vendor Id Control Vector, no skipping ahead ๐Ÿ™ˆ

Offset  Length  Value  Contents
------  ------  -----  --------
   0       1    0x04   Length of the Version String structured
                       subfield

   1       1    0x82   key = 0x82  that identifies this as the
                       DLSw Version structured subfield

   2       1           the hexadecimal value representing the
                       DLSw standard Version number of the
                       sending Data Link Switch.
                         0x01 (indicates version 1 - closed pages)

   3       1           the hexadecimal value representing the
                       DLSw standard Release number of the
                       sending Data Link Switch.
                         0x00 (indicates release 0)

7.6.3. Initial Pacing Window (0x83) Control Vector ๐Ÿ“

this CV sets the starting value of the receive pacing window size for the sending Data Link Switch ๐Ÿง it's REQUIRED and MUST follow the DLSw Version Control Vector, so the order really matters here bestie ๐Ÿ’…

Offset  Length  Value  Contents
------  ------  -----  --------
   0       1    0x04   Length of the Initial Pacing Window
                       structured subfield

   1       1    0x83   key = 0x83  that identifies this
                       as the Initial Pacing Window
                       structured subfield

  2-3      2           the pacing window size, specified
                       in byte normal form..
Note: the pacing window size MUST be non-zero. zero is a no-go, periodt ๐Ÿ™…โ€โ™€๏ธ

7.6.4. Version String (0x84) Control Vector ๐Ÿ’œ

this one shares the particular version number of the sending Data Link Switch ๐ŸŒˆ the format of the version string is up to the vendor. this control vector is OPTIONAL, so it's totally your call โœจ

Offset  Length  Value  Contents
------  ------  -----  --------
   0       1    0xn    Length of the Version String
                       structured subfield

   1       1    0x84   key = 0x84  that identifies
                       this as the Version String
                       structured subfield

  2-n     n-2          the ASCII string that identifies
                       the software version for the
                       sending DLSw.

7.6.5. MAC Address Exclusivity (0x85) Control Vector ๐Ÿ”ฅ

okay this one is lowkey important ๐Ÿ‘€ it tells you how to read the MAC Address List CV data. specifically, it says whether the MAC addresses in the MAC Address List CVs are the ONLY ones you can reach through the sending Data Link Switch ๐Ÿฆ‹

if there's a MAC Address List CV but the MAC Address Exclusivity CV is missing, then those MAC addresses are NOT assumed to be the only ones reachable through that switch. no assumptions, bestie ๐Ÿ’–

a node can say it has no local MAC addresses at all ๐Ÿซถ by including the MAC Address List Exclusivity CV (with byte 2 == 0x01) and NOT including any instances of the MAC Address List CV. (that's a MAY, so it's the node's choice ๐Ÿงš)

Offset  Length  Value  Contents
------  ------  -----  --------
   0       1    0x03   Length of the Exclusivity structured
                       subfield

   1       1    0x85   key = 0x85 that identifies this as the
                       MAC address Exclusivity structured
                       subfield

   2       1           an indicator of the relationship of the
                       MAC addresses to the sending Data Link
                       Switch.
                         0x00     the MAC addresses specified in
                                  this Capabilities Exchange
                                  can be accessed via this
                                  switch but are not the
                                  exclusive set (i.e., other
                                  entities are accessible in
                                  addition to the ones specified)
                         0x01     the MAC addresses specified in
                                  this Capabilities Exchange
                                  are the only ones accessible
                                  via this switch.

7.6.6 SAP List Support (0x86) Control Vector โœจ๐ŸŽ€

Okay so the SAP List Support control vector is how a sending Data Link Switch shows off which Logical Link Control SAPs (DSAPs and SSAPs) it's actually supporting ๐Ÿ’… The DLSw that sends it is basically saying "these are my faves, use them for SNA, and NetBIOS too if you want" ๐Ÿฆ‹ The receiving DLSw can even use the list to filter explorer traffic (TEST, XID, or NetBIOS UI frames) so it doesn't reach the DLSw state machine. Iconic filtering, honestly ๐Ÿ˜ญ

For SNA, a DLSw should set bits for all SAP values (SSAP or DSAP) that may be used for SNA traffic. For NetBIOS support, the bit for SAP 0xF0 should be set (if not supported then the same bit should be cleared). ๐ŸŒธ

Each bit in the SAP control vector data field represents a SAP, as defined below. This vector is required and must follow the Initial Pacing Window Control Vector. Bestie, don't skip this ordering rule ๐Ÿ™ˆ

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1     0x12  Length of the Supported SAP List structured
                          subfield

      1       1     0x86  key = 0x86 that identifies this as the
                          Supported SAP List structured subfield

     2-17    16           the 16-byte bit vector describing all
                          even numbered SAPs enabled.

                          Each Bit within the 16 byte bit vector will
                          indicate whether an even numbered SAP is
                          enabled (b'1') or disabled (b'0').

                          Each Byte within the 16 byte bit vector
                          will be numbered from 0 - F. (Most
                          significant byte first).

                          Byte 0   1   2   3   ...   F
                               XX  XX  XX  XX  ...   XX

                          The bits in each byte indicate whether an
                          even numbered SAP is enabled (b'1') or
                          disabled (b'0'). (Most significant bit first)

                          Bits 7   6   5   4   ...   0
                          SAP  0   2   4   6   ...   E

                          By combining the byte label with the enabled
                          bits, all supported SAPs can be determined.

                          In the following diagram, 'n' would equal 0
                          through F depending on which byte was being
                          interpreted.

                          Bit ordering is shown below with bit
                          7 being the most significant bit and bit
                          0 the least significant bit.

                          7654 3210
                          bbbb bbbb....
                          |||| ||||
                          |||| |||SAP 0xnE enabled or not
                          |||| |||
                          |||| ||SAP 0xnC enabled or not
                          |||| ||
                          |||| |SAP 0xnA enabled or not
                          |||| |
                          |||| SAP 0xn8 enabled or not
                          ||||
                          |||SAP 0xn6 enabled or not
                          |||
                          ||SAP 0xn4 enabled or not
                          ||
                          |SAP 0xn2 enabled or not
                          |
                          SAP 0xn0 enabled or not

Let's do an example, because this is where it clicks ๐Ÿงš Say you want every User Definable SAP from 0x04 to 0xEC for SNA Data Link Switching, plus SAP 0xF0 for NetBIOS Data Link Switching. Here's how that looks, bit by bit:

   Offset  SAPs          Binary       Hex

   0       4,8,C         0010 1010    0x2A
   1       10,14,18,1C   1010 1010    0xAA
   2       20,24,28,2C   1010 1010    0xAA
   3       30,34,38,3C   1010 1010    0xAA
   4       40,44,48,4C   1010 1010    0xAA
   5       50,54,58,5C   1010 1010    0xAA
   6       60,64,68,6C   1010 1010    0xAA
   7       70,74,78,7C   1010 1010    0xAA
   8       80,84,88,8C   1010 1010    0xAA
   9       90,94,98,9C   1010 1010    0xAA
   A       A0,A4,A8,AC   1010 1010    0xAA
   B       B0,B4,B8,BC   1010 1010    0xAA
   C       C0,C4,C8,CC   1010 1010    0xAA
   D       D0,D4,D8,DC   1010 1010    0xAA
   E       E0,E4,E8,EC   1010 1010    0xAA
   F       F0            1000 0000    0x80

7.6.7 TCP Connections (0x87) Control Vector ๐Ÿ”ฅ

The TCP Connections control vector is how a DLSw says it can handle a different number of TCP Connections for Data Link Switching traffic. The base implementation uses two TCP Connections, one for each direction of data traffic, so that's the default vibe ๐Ÿ’œ

This control vector is optional. If it gets left out of a DLSw Capabilities Exchange, then two TCP Connections are assumed. It's also assumed that if a Data Link Switch can support one TCP Connection, it can support two TCP Connections ๐ŸŒˆ

If TCP Connections CV values agree and the number of connections is one, then the DLSw with the higher IP address must tear down the TCP connections on its local port 2065. Hot tip: that's the one with the higher IP address, so double-check your numbers ๐Ÿซถ

The format of the TCP Connections Control Vector is shown below:

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1    0x03   Length of the TCP Connections structured
                          subfield

      1       1    0x87   key = 0x87  that identifies this as the
                          TCP Connections structured subfield

      2       1           an indicator of the support for an
                          alternate number of TCP Connections by
                          the sending Data Link Switch.
                            0x01      the number of TCP Connections
                                      may be brought down to one
                                      after Capabilities Exchange
                                      is completed.
                            0x02      the number of TCP Connections
                                      will remain at two for
                                      the duration of the DLSw
                                      connection.

7.6.8 NetBIOS Name Exclusivity (0x88) Control Vector ๐Ÿ“

The NetBIOS Name Exclusivity control vector tells you how to read the NetBIOS Name List control vector data. Specifically, it says whether the NetBIOS Names in the NetBIOS Name List control vectors are the only ones you can reach through the sending Data Link Switch ๐Ÿ‘‘

If a NetBIOS Name List control vector is specified and the NetBIOS Name Exclusivity control vector is missing, then the NetBIOS Names are not assumed to be the only ones accessible via this switch. So no, you can't just assume it's exclusive ๐Ÿ™…โ€โ™€๏ธ

A node can say it supports no local NetBIOS names by including the NetBIOS Name List Exclusivity CV (with byte 2 == 0x01) and not including any instances of the NetBIOS Name List CV. That's a very intentional, very main character move โญ

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1    0x03   Length of the Exclusivity structured
                          subfield

      1       1    0x88   key = 0x88 that identifies this as the
                          NetBIOS Name Exclusivity structured
                          subfield

      2       1           an indicator of the relationship of the
                          NetBIOS Names to the sending Data Link
                          Switch.
                            0x00     the NetBIOS Names specified in
                                     this Capabilities Exchange
                                     can be accessed via this
                                     switch but are not the
                                     exclusive set (i.e., other
                                     entities are accessible in
                                     addition to the ones specified)

                            0x01     the NetBIOS Names specified in
                                     this Capabilities Exchange
                                     are the only ones accessible
                                     via this switch.

7.6.9 MAC Address List (0x89) Control Vector ๐Ÿ’–

The MAC Address List control vector lists one or more MAC addresses that the sending Data Link Switch can reach. It gives a single MAC address value plus a MAC address mask, and together those pick out one address or a whole range of them ๐Ÿงš Heads up: MAC addresses and masks are in non-canonical (Token-Ring) format in this control vector, so don't mix up your bit order ๐Ÿ’…

This control vector is optional and can be repeated if necessary. Stack 'em up ๐ŸŽ€

Note 1: If a particular MAC address, <mac-addr>, satisfies the following algorithm, then <mac-addr> is assumed to be accessible via the sending Data Link Switch:

   <mac-addr> & <mac-addr-mask> == <mac-addr-value>

where:

           <mac-addr-value> is the MAC Address
                            Value specified in
                            this control vector

           <mac-addr-mask>  is the MAC Address
                            Mask specified in
                            this control vector

Note 2: If an individual MAC Address is desired, then <mac-addr-value> should be the individual MAC address and <mac-addr-mask> should be 0xFFFFFFFFFFFF. Individual addresses get the full mask, no cap ๐Ÿ™ˆ

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1    0x0E   Length of the MAC Address List
                          structured subfield

      1       1    0x89   key = 0x89  that identifies this as the
                          MAC Address List structured subfield

     2-7      6           the 6-byte MAC Address Value,
                          <mac-addr-value> in the above formula

     8-13     6           the 6-byte MAC Address Mask,
                          <mac-addr-mask> in the above formula

7.6.10 NetBIOS Name List (0x8A) Control Vector ๐Ÿฆ‹

The NetBIOS Name List control vector identifies one or more NetBIOS names that the sending Data Link Switch can reach. Each control vector carries a single NetBIOS name in ASCII, but that name can have "don't care" and "wildcard" characters so it can match a whole bunch of names ๐ŸŒธ A ? in a character position means that position is a "don't care". A * at the end of a name means everything after it is a "don't care". Only a * at the very end counts as a wildcard, so anywhere else it's just a regular character ๐Ÿ™ƒ

Blanks or nulls at the end of NetBIOS names in this control vector are ignored. NetBIOS names with fewer than 16 bytes that don't end with * are not assumed to have a trailing *. The "wildcard" character has to be explicit, no guessing allowed ๐Ÿซ 

NetBIOS group names can exist across several LANs/networks, so group names from a NetBIOS Name List Control Vector can't be treated the same as individual names. The Individual/Group Flag is how Data Link Switches tell the two apart ๐Ÿ‘‘

This control vector is optional and can be repeated if necessary. โœจ

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1    0xn    Length of the NetBIOS Name List
                          structured subfield (maximum = 0x13)

      1       1    0x8A   key = 0x8A  that identifies this as the
                          NetBIOS Name List structured subfield

      2       1           Individual/Group Flag
                            0x00 - Individual NetBIOS Name
                            0x01 - Group NetBIOS Name

     3-n     n-3          the NetBIOS name with possible embedded
                          '?' and terminating '*'.

7.6.11 Vendor Context (0x8B) Control Vector โœจ

okay bestie, this one is the Vendor Context control vector ๐ŸŽ€ It tells everyone the manufacturer's IEEE assigned Organizationally Unique Identifier (OUI) of the Data Link Switch that's sending the DLSw Capabilities Exchange. The OUI goes in non-canonical (Token-Ring) format ๐Ÿ’…

This control vector is optional ๐Ÿซถ Its whole job is to set the context for any Vendor Specific control vectors that come after it in the Capabilities Exchange. If you send more than one Vendor Context control vector, the most recent context stays in effect for all the Vendor Specific control vectors until the next Vendor Context control vector shows up ๐Ÿฆ‹

   Offset  Length  Value  Contents
   ------  ------  -----  --------
      0       1    0x05   Length of the Vendor Context structured
                          subfield

      1       1    0x8B   key = 0x8B  that identifies this as the
                          Vendor Context structured subfield

     2-4      3           the 3-byte Organizationally Unique
                          Identifier (OUI) for the vendor
                          (non-canonical format)

7.7 Capabilities Exchange Responses ๐Ÿ’Œ

there are two kinds of DLSw Capabilities Exchange Responses: positive and negative ๐ŸŒธ A positive response goes back to the sending Data Link Switch when there were no errors in the DLSw Capabilities Exchange Request. A negative response goes back when there's at least one error ๐Ÿ˜ญ

A positive DLSw Capabilities Exchange Response has this overall format:

+----+----+
| LL | ID |
+----+----+
  • Bytes 0-1: the length, in binary, of the DLSw Capabilities Exchange Response GDS Variable. For this one, LL is 0x0004.
  • Bytes 2-3: the GDS Id, which is 0x1521 ๐Ÿ’–

A negative DLSw Capabilities Exchange Response has this overall format:

+----+----+--------+--------+
| LL | ID | Offset | Reason |
+----+----+--------+--------+
  • Bytes 0-1: the length, in binary, of the DLSw Capabilities Exchange Response GDS Variable. LL is the sum of the length of all the fields in the GDS Variable (so LL + ID + the Offsets/Reasons).
  • Bytes 2-3: the GDS Id, which is 0x1522 ๐Ÿฆ‹
  • Bytes 4-5: the Offset into the DLSw Capabilities Exchange Request where the error is. The Offset should always point to the start of the GDS Variable or to a specific control vector ๐Ÿงš
  • Bytes 6-7: the Reason code that uniquely identifies the error. These are the specific values:
  0x0001        invalid GDS length for a DLSw Capabilities
                Exchange Request.  (The value of Offset
                is ignored.)

  0x0002        invalid GDS id for a DLSw Capabilities
                Exchange Request.  (The value of Offset
                is ignored.)

  0x0003        Vendor Id control vector is missing.  (The
                value of Offset is ignored.)

  0x0004        DLSw Version control vector is missing. (The
                value of Offset is ignored.)

  0x0005        Initial Pacing Window control vector is
                missing.  (The value of Offset is ignored.)

  0x0006        length of control vectors doesn't correlate
                to the length of the GDS variable

  0x0007        invalid control vector id

  0x0008        length of control vector invalid

  0x0009        invalid control vector data value

  0x000A        duplicate control vector (for non-repeating
                control vectors)

  0x000B        out-of-sequence control vector (for
                repeating control vector)

  0x000C        DLSw Supported SAP List control vector is
                missing.

                (The value of Offset is ignored.)

NOTE: you can get multiple Offset, Reason pairs back in one response, with one pair for each error that was found ๐Ÿ”ฅ


8. Pacing/Flow Control ๐ŸŒŠ

this section covers the required Pacing and Flow Control mechanisms that a Data Link Switch uses ๐Ÿ’…

it's out of scope for this document to set a policy for how an implementation maps SSP flow control to the native data link flow control at the edges ๐Ÿ™ˆ But the paragraphs below give a general big-picture overview of how the mechanism is meant to be used โœจ

there are two types of flows covered by the flow control mechanism: connection-oriented and connectionless ๐Ÿฆ‹ For connection-oriented flows, the implementer maps the native flow control of the two data links at the boundaries onto the SSP flow control. That gives you end-to-end flow control that "pushes back" all the way to the originating station in either direction ๐Ÿ’œ

connectionless traffic is a whole different story, because there's no native flow control mechanism for connectionless data links ๐Ÿ˜ญ At first it's tempting to just let connectionless traffic flow through the DLSw cloud unthrottled. But the reason these flows get flow control inside the DLSw cloud is so that, if frames ever need to be discarded, that discarding gets "pushed" back to the ingress of the cloud. This "early discarding" of excessive DATAGRAMs keeps the cloud deterministic without wasting network bandwidth ๐Ÿง 

8.1 Basic Overview ๐ŸŽ€

each circuit has two data flows, one in each direction ๐Ÿ’– Every data flow has its own independent flow control mechanism. For each data flow there's an entity that originates the traffic, called the sender, and a target entity that receives it, called the receiver ๐Ÿซถ

a sender can only send data when its receiver has explicitly granted permission to send a set number of data units. Data units are either a DGRMFRAME or an INFOFRAME ๐ŸŒธ

the receiver grants permission by sending a Flow Control Indicator (FCIND, defined later). The sender must acknowledge every FCIND by sending a Flow Control Acknowledgment (FCACK, defined later) ๐Ÿ”ฅ

a sending implementation has to keep track of these values:

  1. GrantedUnits - the number of units (frames) the sender currently has permission to send.
  2. CurrentWindow - a discrete number of units, controlled by the receiver, that is the basis for granting additional units.
  3. InitialWindowSize - global for all circuits on a transport connection. It's learned during the capabilities exchange when the transport connection is established, and it sets the initial value for CurrentWindow whenever a circuit is established ๐Ÿ‘‘

a receiving implementation has to keep track of these values:

  1. CurrentWindow - a discrete number of units, controlled by the receiver, that is the basis for granting additional units.
  2. InitialWindowSize - global for all circuits on a transport connection. It's sent during the capabilities exchange when the transport connection is established, and it sets the initial value for CurrentWindow whenever a circuit is established.
  3. FCACKOwed - the sender owes an FCACK. If this is true, no FCIND may be sent ๐Ÿ™ˆ

8.2 Frame Format ๐Ÿฆ‹

the Flow control Byte sits at offset 15 in both the Information and Control SSP messages. From a flow control point of view, the flow control information in those two frames is handled exactly the same way โœจ

here's the layout of the Flow Control Byte (Bit 7 is the most significant and Bit 0 is the least significant bit of the octet):

      bit   7   6   5   4   3   2   1   0
          +---+---+---+---+---+---+---+---+
          |FCI|FCA| reserved  |    FCO    |
          +---+---+---+---+---+---+---+---+
  • FCI: Flow Control Indicator
  • FCA: Flow Control Ack
  • FCO: Flow Control Operator Bits
        000 - Repeat Window Operator
        001 - Increment Window Operator
        010 - Decrement Window Operator
        011 - Reset Window Operator
        100 - Halve Window Operator
        101 - Reserved
        110 - Reserved
        111 - Reserved

a frame with the FCI bit set is called a Flow Control Indication (FCIND) ๐Ÿ’… An FCIND manages the flow in the opposite direction from the frame that carries it.

a frame with the FCA bit set is called a Flow Control Acknowledgment (FCACK) ๐Ÿ’– An FCACK manages the flow in the same direction as the frame that carries it.

NOTE: a frame can be both an FCIND and an FCACK ๐ŸŽ€

a frame carrying an FCIND or FCACK can also contain data for the flow in the direction it's traveling ๐Ÿซถ In that case the FCIND or FCACK is called piggy-backed. An FCIND that isn't piggy-backed is called an Independent Flow Control Indication (IFCIND), and an FCACK that isn't piggy-backed is called an Independent Flow Control Acknowledgment (IFCACK). IFCIND and IFCACK messages are sent in an Independent Flow Control SSP message (type 0x21) ๐Ÿงš

NOTE: a frame can be both an IFCIND and an IFCACK ๐ŸŒˆ

it's really useful to carry flow control information inside control messages so you don't have to send a flow-control-only message ๐Ÿ’œ The diagram below shows which messages can carry valid flow control information:

 ======                            ___                           ======
 |    |        ---------        __/   \__       ---------        |    |
 |    |      __|  _|_  |__     /   IP    \    __|  _|_  |__      |    |
 ======        |   |   |      <  Network  >     |   |   |        ======
/______\       ---------       \__     __/      ---------       /______\
 Origin       Origin DLSw         \___/        Target DLSw      Target
 Station        partner                          partner        Station

   May have valid
    FCI/FCA/FCO    Data carrying

         N             N          CANUREACH_cs
                                  ----------->
         Y*            N            ICANREACH_cs

                                    <-----------
         Y             N          REACH_ACK
                                  ----------->
         Y             Y            XIDFRAMEs
                                  <------------>
         Y             Y            DGRMFRAMEs
                                  <------------>
         Y             N          CONTACT
                                  ----------->
         Y             N               CONTACTED
                                    <-----------
         Y             Y             INFOFRAMEs
                                  <------------>
         Y             N          RESTART_DL
                                  ----------->
         Y             N               DL_RESTARTED
                                    <-----------
         Y             N          CONTACT
                                  ----------->
         Y             N               CONTACTED
                                    <-----------
         N             N          HALT_DL
                                  ----------->
         N             N               DL_HALTED
                                    <-----------
*Note: ICANREACH_cs cannot carry FCA, because there could never be an outstanding FCI for it to acknowledge ๐Ÿ™ˆ

8.3 Granting Permission to Send Data ๐Ÿ’Œ

a receiver gives a sender permission to send units of data by sending an FCIND ๐ŸŒธ Each FCIND also has a flow control operator, which is encoded in the FCO bits of the FCIND header. With one exception (the Reset Window operator), every operator can be either piggy-backed or carried in an IFCIND โœจ

the five flow control operators are outlined below:

8.3.1 Repeat Window Operator ๐Ÿ”

okay so the Repeat Window operator is the chill one ๐Ÿ’… CurrentWindow doesn't move at all, and we just add it onto GrantedUnits ๐Ÿฆ‹

(CurrentWindow unchanged)
GrantedUnits += CurrentWindow

8.3.2 Increment Window Operator ๐Ÿ“ˆ

bestie this one bumps CurrentWindow up by one first, then adds the new number to GrantedUnits ๐ŸŽ€

CurrentWindow++
GrantedUnits += CurrentWindow

8.3.3 Decrement Window Operator ๐Ÿ“‰

same energy but going down โœจ it bumps CurrentWindow down by one, then adds the new number to GrantedUnits

CurrentWindow--
GrantedUnits += CurrentWindow
NOTE: This operator may only be sent if CurrentWindow is greater than one. ๐Ÿ™ˆ

8.3.4 Reset Window Operator ๐Ÿงน

this one is a full reset moment ๐Ÿ’€ it wipes both CurrentWindow and GrantedUnits back to zero

CurrentWindow = 0;
GrantedUnits  = 0;
NOTE: This operator may only flow on an independent pacing indication (may NOT be piggy-backed). ๐Ÿšซ
NOTE: After sending this operator, the only legal subsequent operator is Increment Window. ๐ŸŒธ

8.3.5 Halve Window Operator ๐Ÿฐ

the Halve Window operator shall be processed like this ๐Ÿซถ if CurrentWindow is bigger than 1, cut it in half, then add whatever's left to GrantedUnits

IF CurrentWindow > 1 THEN
    CurrentWindow = CurrentWindow / 2
ENDIF
GrantedUnits += CurrentWindow

Note: The divide by two operation is an unsigned integer divide (round down) or bit shift right operation. ๐Ÿงฎ

8.4. Acknowledging a Flow Control Operator ๐Ÿ’Œ

every sender must acknowledge each FCIND with an FCACK, and that FCACK gets piggy-backed on the next frame going the other way in all cases except the Reset Window Operator ๐Ÿซถ no exceptions, periodt

the receiver may have no more than one unacknowledged FCIND outstanding at any time, with one exception ๐Ÿ‘‘ a Reset Window Operator may be sent while another FCIND is still waiting on its acknowledgment

NOTE: The FCI and FCO bits of the FCACK are used independently by the flow in the opposite direction ๐Ÿฆ‹

8.4.1 Acknowledging a Reset Window Operator ๐Ÿงผ

since this operator wipes out all the units that were granted before, the sender must acknowledge this FCIND using an IFCACK (Independent Flow Control Acknowledgment) ๐Ÿ’… this is the only case where IFCACK is used, so it's kind of a big deal

should a sender get a non-reset FCIND and then a Reset Window FCIND before it acks the first one, it only acknowledges the Reset Window ๐Ÿ™ˆ the reset is the one that matters

NOTE: The FCI and FCO bits on these frames are used independently by the flow in the opposite direction. ๐ŸŒˆ

8.5 Capabilities Exchange Initial Window Size ๐Ÿค

when two nodes set up a transport connection, they do a capabilities exchange (and yes, this part is a requirement ๐Ÿ’–) you can check out the Capabilities Exchange section 7 for the deets ๐Ÿงš the two nodes are required to swap the following parameter:

InitialWindowSize -  This indicates to the partner what
                     the sending flow entity initializes
                     its CurrentWindow value to for each
                     multiplexed circuit subsequently
                     established on that transport
                     connection.  This value must be
                     non-zero.

8.6 Circuit Startup ๐Ÿš€

the startup process is super simple โœจ

CurrentWindow = InitialWindowSize
GrantedUnits  = 0

NOTE: The InitialWindow Size variable has a scope of one per DLSw transport connection, while CurrentWindow and Granted units are maintained on a per circuit basis. At circuit startup, a sender may not send data units until the receiver grants explicit permission with an FCIND message. This grant may be an independent FCIND message or the FCIND may be piggy-backed on any of the message types listed in section 8.2. ๐ŸŽ€ so basically the sender waits for a green light before it sends anything ๐Ÿšฆ

8.7 Example Receiving Implementations ๐Ÿ‘€

the next two examples show receiving implementations that get more complicated as they go ๐Ÿ’… they're not meant to be complete implementations, they're just here to illustrate the protocol, so don't panic if things feel a bit incomplete โœจ

NOTE: The examples are independent of the buffering model ( buffers may be deterministicly or statistically committed) ๐Ÿง 

NOTE: The examples assume a process model where each event processes to completion without being preempted by another event. โณ

8.7.1 Fixed Pacing Example ๐Ÿง

first, here are the variables we're adding on top of InitialWindowSize, CurrentWindow and FCACKOwed ๐Ÿ’–

GrantDelayed     - Boolean
GrantedUnits     - Outstanding Units

the following section describes how each event gets processed in this example implementation ๐Ÿฆ‹

8.7.1.1 Circuit Startup ๐ŸŒŸ

CurrentWindow    = InitialWindowSize
FCACKOwed        = FALSE
GrantDelayed     = FALSE
GrantedUnits     = 0
Repeat Window Operator

8.7.1.2 Check Buffers Available ๐Ÿงบ

can my implementation afford to grant CurrentWindow just now? ๐Ÿค”

8.7.1.3 Buffers Become Available ๐Ÿซง

IF Check Buffers Available THEN
   Send FCIND( Repeat Window)
   GrantDelayed = FALSE
ELSE
   Wait on buffers to become available (LIFO)
ENDIF

8.7.1.4 Repeat Window Operator ๐Ÿ”

IF Check Buffers Available THEN
    Send FCIND( Repeat Window)
ELSE
   GrantDelayed = TRUE
   Wait on buffers to become available (FIFO)
ENDIF

8.7.1.5 Send FCIND( operator) ๐Ÿ“ค

GrantedUnits += CurrentWindow
FCACKOwed     = TRUE
Encode and Transmit FCIND piggybacked or as IFCIND

8.7.1.6 A Frame Arrives from Sender ๐Ÿ“ฌ

GrantedUnits--;
IF frame is FCACK THEN
   IF FCACKOwed THEN
      FCACKOwed = FALSE
   ELSE
      Protocol Violation
   ENDIF
ENDIF
IF NOT GrantDelayed THEN
   IF GrantedUnits <= CurrentWindow THEN
       IF FCACKOwed THEN
         Protocol Violation
       ELSE
         Repeat Window Operator
       ENDIF
   ENDIF
ENDIF

8.7.2 Adaptive Pacing Example ๐ŸŒท

this one is the glow-up version ๐Ÿ’ซ it adjusts the window size and granted units based on buffer availability and transport utilization ๐Ÿ“Š

NOTE: This example ignores other factors which might compel the receiving implementation to adjust the window size (i.e., Outbound queue length, traffic priority, ...) ๐Ÿ™ƒ

here are the variables, on top of InitialWindowSize, CurrentWindow and FCACKOwed ๐Ÿ’…

GrantDelayed     - Boolean
GrantedUnits     - Outstanding Units

8.7.2.1 Circuit Startup ๐ŸŒˆ

CurrentWindow    = InitialWindowSize
FCACK            = FALSE
GrantDelayed     = FALSE
GrantedUnits     = 0
Repeat Window Operator

8.7.2.2 Check Buffers Available ( X) ๐Ÿงบ

Can my implementation afford to grant X units just now?

8.7.2.3 Buffers Become Available ๐Ÿซง

IF Check Buffers Available THEN
   CurrentWindow--;
   Send FCIND( Decrement Window)
   GrantDelayed = FALSE
ELSE
   Wait on buffers to become available (LIFO)
ENDIF

8.7.2.4 Repeat Window Operator ๐Ÿ”

IF Check Buffers Available (CurrentWindow) THEN
    Send FCIND( Repeat Window)
ELSE
   GrantDelayed = TRUE
   Wait on buffers to become available (FIFO)
ENDIF

8.7.2.5 Increment Window Operator ๐Ÿ“ˆ

IF Check Buffers Available ( CurrentWindow + 1) THEN
    CurrentWindow++
    Send FCIND( Increment Window)
ELSE
    Repeat Window Operator
ENDIF

8.7.2.6 Send FCIND( operator) ๐Ÿ“ค

FCACKOwed     = TRUE
GrantedUnits += CurrentWindow
Encode and Transmit FCIND piggybacked or as IFCIND

8.7.2.7 An FCACK Arrives from Sender ๐Ÿ“ฌ

GrantedUnits--;
IF NOT FCACKOwed THEN
   Protocol Violation
ENDIF
FCACKOwed = FALSE;
IF NOT GrantDelayed THEN
   IF GrantedUnits < CurrentWindow THEN
       Increment Window Operator
   ELSE IF GrantedUnits == CurrentWindow THEN
       Repeat Window Operator
   END
ENDIF

8.7.2.8 A Non-FCACK Frame Arrives from Sender ๐Ÿ“ญ

GrantedUnits--;
IF NOT GrantDelayed THEN
   IF FCACKOwed THEN
      IF GrantedUnits < CurrentWindow THEN
         Protocol Violation
      END
   ELSE
      IF GrantedUnits <= CurrentWindow THEN
         Repeat Window Operator
      ENDIF
   ENDIF
ENDIF

8.8 Adaptive Pacing Example Flow Diagrams ๐ŸŽจ

8.8.1 Example Flows from the Above Implementation ๐ŸŒŠ

time for the pictures ๐Ÿฅน this diagram shows adaptive pacing in action (the Halve Window and Reset operations get their own diagrams later on โœจ)

-----SENDER-----                     ----RECEIVER----
Granted   Window                     Window   Granted
  0         2   circuit established    2         0
  2         2   <-------- FCIND(Rpt)   2         2
  1         2   FCACK-------------->   2         1
  4         3   <-------- FCIND(Inc)   3         4
  3         3   FCACK-------------->   3         3
                       +- FCIND(Rpt)   3         6
  2         3   DATA---|----------->   3         5
  1         3   DATA---|----------->   3         4
  4         3   <------+
  3         3   FCACK-------------->   3         3
  6         3   <-------- FCIND(Rpt)   3         6
  5         3   FCACK-------------->   3         5
  4         3   DATA--------------->   3         4
  3         3   DATA--------------->   3         3
                       +- FCIND(Rpt)   3         6
  2         3   DATA---|----------->   3         5
  1         3   DATA---|----------->   3         4
  0         3   DATA---|----------->   3         3
  3         3   <------+
  2         3   FCACK-------------->   3         2
  6         4   <-------- FCIND(Inc)   4         6
  5         4   FCACK-------------->   4         5
  4         4   DATA--------------->   4         4
                                     Waiting on Buffer
                       +- FCIND(Dec)   3         7
  3         4   DATA---|----------->   3         6
  2         4   DATA---|----------->   3         5
  1         4   DATA---|----------->   3         4
  0         4   DATA---|----------->   3         3
  3         3   <------+
  2         3   FCACK-------------->   3         2
                                     Waiting on Buffer
                       +- FCIND(Dec)   2         4
  1         3   DATA---|----------->   2         3
  0         3   DATA---|----------->   2         2
  2         2   <------+
  1         2   FCACK-------------->   2         1
  4         3   <-------- FCIND(Inc)   3         4
  3         3   FCACK-------------->   3         3
  6         3   <-------- FCIND(Rpt)   3         6
  5         3   FCACK-------------->   3         5
  4         3   DATA--------------->   3         4
  3         3   DATA--------------->   3         3
  6         3   <-------- FCIND(Rpt)   3         6

8.8.2. Example Halve Window Flow โœจ

okay bestie, this flow shows the Halve Window Operator in action ๐Ÿฆ‹ watch the sender's granted units and window size drop as the receiver hits a resource shortage ๐Ÿ’€

      -----SENDER-----                     ----RECEIVER----
      Granted   Window                     Window   Granted
        0         2   circuit established    2         0
        2         2   <-------- FCIND(Rpt)   2         2
        1         2   FCACK-------------->   2         1
        4         3   <-------- FCIND(Inc)   3         4
        3         3   FCACK-------------->   3         3
                                             Resource Shortage
        2         3   DATA--------------->   1         2
        1         3   DATA--------------->   1         1
        0         3   DATA--------------->   1         0
        1         1   <-------- FCIND(Hlv)   1         1
        0         1   FCACK-------------->   1         0

NOTE: The Halve Window Operator could have been sent before the granted units fell to zero. The implementer may make a choice based on the severity of the condition. ๐ŸŒธ

8.8.3. Example Reset Window Flows ๐ŸŽ€

this one is the ResetWindow operation when the receiver has no FCIND outstanding, so it's a clean little reset โœจ

   -----SENDER-----                     ----RECEIVER----
   Granted   Window                     Window   Granted
     0         2   circuit established    2         0
     2         2   <-------- FCIND(Rpt)   2         2
     1         2   FCACK-------------->   2         1
     4         3   <-------- FCIND(Inc)   3         4
     3         3   FCACK-------------->   3         3
                          +- FCIND(Rpt)   3         6
     2         3   DATA---|----------->   3         5
     1         3   DATA---|----------->   3         4
     4         3   <------+
     3         3   FCACK-------------->   3         3
     6         3   <-------- FCIND(Rpt)   3         6
     5         3   FCACK-------------->   3         5
                                          Resource shortage!

     0         0   <-------- FCIND(Rst)   0         5 (note still
   committed)
     0         0   IFCACK------------->   0         0
                                          Condition eases
     1         1   <-------- FCIND(Inc)   1         1
     0         1   FCACK-------------->   1         0
     2         2   <-------- FCIND(Inc)   2         2
     1         2   FCACK-------------->   3         4

the next two flows are the Reset Window operation when the receiver does have an outstanding FCIND ๐Ÿ‘‘ slay

   -----SENDER-----                     ----RECEIVER----
   Granted   Window                     Window   Granted
     0         2   circuit established    2         0
     2         2   <-------- FCIND(Rpt)   2         2
     1         2   FCACK-------------->   2         1
     4         3   <-------- FCIND(Inc)   3         4
     3         3   FCACK-------------->   3         3
                          +- FCIND(Rpt)   3         6
     2         3   DATA---|----------->   3         5
                          |               Resource shortage!
                          |+-FCIND(Rst)   0         5
     1         3   DATA---||---------->   0         4
     4         3   <------+|
     3         3   FCACK---+---------->   0         3 (Not IFCACK!)
     2         3   DATA----|---------->   0         2
     0         0   <-------+
     0         0   IFCACK------------->   0         0
                                          Condition eases
     1         1   <-------- FCIND(Inc)   1         1
     0         1   FCACK-------------->   1         0
     2         2   <-------- FCIND(Inc)   2         2
     1         2   FCACK-------------->   3         4
   -----SENDER-----                     ----RECEIVER----
   Granted   Window                     Window   Granted
     0         2   circuit established    2         0
     2         2   <-------- FCIND(Rpt)   2         2
     1         2   FCACK-------------->   2         1
     4         3   <-------- FCIND(Inc)   3         4
     3         3   FCACK-------------->   3         3
                          +- FCIND(Rpt)   3         6
     2         3   DATA---|----------->   3         5
                          |               Resource shortage!
                          |+-FCIND(Rst)   0         5
     1         3   DATA---||---------->   0         4
     4         3   <------+|
     0         0   <-------+
     0         0   IFCACK------------->   0         0
                                          Condition eases
     1         1   <-------- FCIND(Inc)   1         1
     0         1   FCACK-------------->   1         0
     2         2   <-------- FCIND(Inc)   2         2
     1         2   FCACK-------------->   3         4

8.9. Other Considerations ๐Ÿงš

8.9.1. Protocol Violations ๐Ÿ™ˆ

okay so these are the events that count as protocol violations, and yes I'm taking them seriously ๐Ÿ˜ญ

  1. Sender exceeds granted units or does not acknowledge FCIND on first frame after its receipt (the receiver can not discern the difference between the two).
  2. Receiver does not follow a Reset Window Operator with an Increment Window Operator.
  3. Receiver has two unacknowledged FCINDs ( other than Reset Window) outstanding.
  4. Receiver sends Decrement Window Operator with a window size of one.
  5. Receiver attempts to increment the window size beyond 0xFFFF.
what the node does about a violation is up to its implementation ๐Ÿ’… if it decides to take down the circuit where the violation happened, HALT_DL is the appropriate action.

Acknowledgments ๐Ÿซถ

Original RFC 1434 Authors:

  • Roy C. Dixon, IBM
  • David M. Kushi, IBM

Chair of APPN Implementers Workshop Data Link Switching Related Interest Group:

  • Louise Herndon Wells, Internetworking Technology Institute

Working Group Chairs (and significant contributors to this document):

  • Connect/Disconnect (State Machines): Steve Klein, IBM
  • Capabilities Exchange: Wayne Clark, Cisco Systems
  • Flow Control (Adaptive Pacing): Shannon Nix, Metaplex
  • Priority/Class of Service: Gene Cox, IBM

Other significant contributors:

  • Peter Gayek, IBM
  • Paul Brittain, Data Connection Limited

References ๐Ÿ“š

  1. ISO 8802-2/IEEE Std 802.2 International Standard, Information Processing Systems, Local Area Networks, Part 2: Logical Link Control, December 31, 1989.
  2. IBM LAN Technical Reference IEEE 802.2 and NETBIOS Application Program Interfaces SC30-3587-00, December 1993.
  3. ISO/IEC DIS 10038 DAM 2, MAC Bridging, Source Routing Supplement, December 1991.
  4. ISO 8802-2/IEEE Std 802.1D International Standard, Information Processing Systems, Local Area Networks, Part 2: MAC layer Bridging.

Security Considerations ๐Ÿ”’

Security issues are not discussed in this memo. no vibes to report, bestie ๐ŸŒˆ

Chair's Address ๐ŸŒท

Louise Wells Internetwork Technology Institute 2021 Stratford Dr. Milpitas, CA 95035

EMail: lhwells@cup.portal.com

Editor's Address ๐Ÿฆ‹

Alan K. Bartky Manager of Technology Sync Research Inc. 7 Studebaker Irvine, CA 91728-2013

Phone: 1-714-588-2070 EMail: alan@sync.com

Note: Any questions or comments relative to the contents of this RFC should be sent to the following Internet address: aiw-dlsw@networking.raleigh.ibm.com.

This address will be used to coordinate the handling of responses.

NOTE 1: This is a widely subscribed mailing list and messages sent to this address will be sent to all members of the DLSw mailing list. For specific questions relating to subscribing to the AIW and any of it's working groups send email to: appn@vnet.ibm.com

Information regarding all of the AIW working groups and the work they are producing can be obtained by copying, via anonymous ftp, the file aiwinfo.psbin or aiwinfo.txt from the Internet host networking.raleigh.ibm.com, located in directory aiw.

NOTE 2: These mailing lists and addresses are subject to change. ๐ŸŽ€ bye bestie, you did amazing ๐Ÿ’–

๐Ÿ“ฆ where this page comes from