Chapter 3 Management
4.8 Loop algorithms for LAN data links
4.8.1 Loop requester
The procedures below define the algorithm for the Loop Requester.
The LAN loopback protocol uses two message codes, “Forward Data” and “Reply”. Forward Data specifies that the message is to be sent onwards to another station. Reply indicates that the message terminates at this station and should be delivered to a Loop Requester. The mes-
sage sent by the requester in effect consists of a Reply, enveloped in a number of Forward Data envelopes. This provides the mechanism needed to do“loop assistance”.
If assisted loopback is desired, the caller will often supply the data link address of the sta-
tion to use as assistant. If no assistant address is supplied, then the Loop Requester attempts tofind an assistant. Stations willing to be assistant listen to the Loopback Assistance multicast address. Tofind an assistant, the requester sends a loop message to that multicast address, and uses the source address from the first received response as the assistant address for the remainder of the operation.
Note that all Loop messages (except for the one used tofind a loop assistant) are sent as sin-
gle attempts. Since the purpose of the Loop directive is to look for network problems, no retries are done during the operation. Otherwise soft errors would be obscured.
PROCEDURE LAN.LoopRequester (op: POINTER TO Operation; buff: POINTER TO Buffer) RAISES {InvalidResponse, DataLinkError, Timeout};
VAR i, j, offset, buflen: INTEGER; addresses: SET OF LANAddress; target: LANAddress;
BEGIN
op^.Version := V4; (* Initially use V4 format *) addresses := op^.Addresses;
FOR i := 1 TO op^.Count DO
IF i = 1
THEN (* For first one we have to select the address *) LAN.FindAssistant (op, buff); (* Select assistant if we need one *) LOOP
IF addresses = { }
THEN (* No target addresses left to try *) IF op^.Version = V4
THEN (* V4 didn’t work, try it with V3 *) op^.Version := V3;
addresses := op^.Addresses;
LAN.FindAssistant (op, buff); (* Find a V3 assistant if we need one *) ELSE RAISE (Timeout) (* Both versions received no response *) END
ELSE
target := « select and remove an address from addresses »;
LAN.BuildLoopMsg (buff, target, op^.AssistanceType, op^.AssistantAddress, op, i, buflen);
TRY
DLI.RequestResponse (op, buff, buff, op^.Version);
op^.Address := target; (*If we get an answer, that’s the address to use *) EXIT (* Leave the address search loop *)
EXCEPT
| Timeout: (* If no answer, keep on trying addresses *) END
4.8.1: Loop requester
69
END
END (* end of target address search loop *)
ELSE (* Not first message *)
LAN.BuildLoopMsg (buff, target, op^.AssistanceType, op^.AssistantAddress, op, i, buflen); DLI.ReqResp (op, buff, buff, op^.Version)
END;
IF buff^.Length # buflen (* If wrong length response *) THEN
RAISE (InvalidResponse, op^.Count – i) END;
offset := DLI.GetInteger (buff, 0); (* Get skip count *)
j := DLI.GetInteger (buff, offset + 2); (* Receipt number of response *)
IF j # i (* If wrong receipt number *)
OR offset + 4 + op^.Length # buflen (* or wrong offset *) THEN
RAISE (InvalidResponse, op^.Count – i) END;
FOR j := 0 to op^.Length – 1 DO
IF buff^.Data[j + offset + 4] # op^.Data (* Check test data *) THEN
RAISE (InvalidResponse, op^.Count – i) END
END END
END LAN.LoopRequester;
The following procedure builds a LAN Loopback message. The message consists of a Reply message (containing the data), preceded by one or more Forward headers. These headers list the addresses on the path the message is to take. For example, if Transmit assistance is being used, the Loopback message destination address is the assistant address; the first Forward header contains the target station address, and the second forward header contains the station address for our circuit.
PROCEDURE LAN.BuildLoopMsg (buff: POINTER TO Buffer; target: LANAddress; help: HelpType; assistant: LANAddress; op: POINTER TO Operation; receipt: INTEGER; VAR buflen: INTEGER); VAR offset: INTEGER;
BEGIN
DLI.PutInteger (buff, 0, 0); (* Initial skip count = 0 *) IF help IN {Transmit, Full} (* If first hop is to assistant *) THEN
buff^.Destination := assistant; (* Set first hop destination address *) LAN.Forward (buff, 2, target); (* First Forward header points to target *) offset := 10
ELSE (* Receive assistance or no assistance, first hop to target *) buff^.Destination := target;
offset := 2 END;
IF help IN {Receive, Full} (* If assistant used on the way back *) THEN
LAN.Forward (buff, offset, assistant); offset := offset + 8
END;
LAN.Forward (buff, offset, op^.CircPtr^.DataLinkAddress);
(* Last forward header points back to us *) offset := offset + 8;
DLI.PutInteger (buff, offset, Reply); (* Put in Reply header *) DLI.PutInteger (buff, offset + 2, receipt);
FOR j := 0 to op^.Length – 1 DO
buff^.Data[j + offset + 4] := op^.Data (* Load the test data pattern into the buffer *) END;
buflen := op^.Length + offset + 4; (* total loop message length *) buff^.Length := buflen
END LAN.BuildLoopMsg;
PROCEDURE LAN.Forward (buff: POINTER TO Buffer; offset: INTEGER; address; LANAddress); BEGIN
DLI.PutInteger (buff, offset, ForwardData); DLI.PutAddress (buff, offset + 2, address) END LAN.Forward;
PROCEDURE LAN.FindAssistant (op: POINTER TO Operation; buff: POINTER TO Buffer); VAR assistants: SET OF LANAddress;
BEGIN
IF op^.AssistanceType # None (* Need to select an assistant? *) THEN
assistants := op^.AssistantAddresses; (* Initialize the list of addresses to try *) LOOP
IF assistants = { }
THEN (* No assistant addresses left to try *) IF op^.Version = V4
THEN (* V4 didn’t work, try it with V3
op^.Version := V3;
assistants := op^.AssistantAddresses
ELSE RAISE (Timeout) (* Both versions received no response *) END
ELSE
target := « select and remove an address from assistants »; LAN.BuildLoopMsg (buff, target, None, NullAddress, op, –1); TRY
DLI.Transact (op, buff, buff); (* Do a “direct” loop to the selected address *) op^.AssistantAddress := buff^.Source; (* Whoever responds is the assistant *) EXIT (* Leave the assistant search loop *)
EXCEPT
| Timeout: (* If no answer, keep on trying addresses *) END END END END END LAN.FindAssistant;
4.8.2 Loop server
There is always one Loop Server active for each LAN circuit. It keeps a receive pending at all times. When a message comes in (which will have function code ForwardData), the message is modified appropriately and sent onwards. Invalid messages are quietly ignored.
Note that the Loop Server is required to support the full range of valid message sizes for each data link.
PROCEDURE LAN.LoopServer (circ: POINTER TO Circuit); VAR op: POINTER TO Operation;
buff: POINTER TO Buffer; offset: INTEGER;
4.9: XID and TEST algorithms
71
nexthop: LANAddress; BEGIN
NEW (op); (* Get an Operation record *)
op^.CircPtr := circ; op^.Op := LoopServer; LOOP
op^.Address := NullAddress; (* We’ll listen to any remote station address *) op^.Version := Unknown; (* Accept any version *)
DLI.Receive (op, buff, Infinite); (* Wait for a message, however long it takes *) offset := DLI.GetInteger (buff, 0); (* Get the offset value from message *)
IF buff^.Length % offset+10 (* Must have our header plus next guy’s msgtype *) THEN
nexthop := GetAddress (buff, offset+2); (* Get address to send to *) IF nexthop[0] = 0 (* Must not be a multicast address *) THEN
buff^.Destination := nexthop; (* Forwarding address is our destination *) DLI.PutInteger (buff, 0, offset+8); (* Update Offset in message buffer *) DLI.Send (op, buff, op^.Version)
END END;
DLI.ReceiveDone (buff) (* Done using the receive buffer *)
END (* Repeat that forever *)
END LAN.LoopServer;