IPOpsImpl.mesa
Last Edited by: HGM, October 7, 1984 6:33:26 am PDT
Last Edited by: Nichols, August 16, 1983 2:06 pm
Last Edited by: Taft, January 5, 1984 4:20 pm
Hal Murray May 16, 1985 2:46:55 am PDT
John Larson, June 4, 1986 11:28:05 pm PDT
DIRECTORY
Basics USING [BITNOT, HighHalf, LowHalf],
BasicTime USING [GMT, Now, Period],
CommBuffer USING [],
CommDriver USING [Buffer, GetNetworkChain, InsertReceiveProc, Network, RecvProc],
CommDriverType USING [Encapsulation],
IPDefs USING [Datagram, DatagramRec, Address, InternetHeader, maxDataLength, maxOptionLength, minIHL, DByte],
IPOps,
IPQueue USING [QueueDatagram],
IPReassembly USING [AgeFragments, Reassemble],
IPRouter USING [DatagramPointer],
PrincOpsUtils USING [ByteBlt],
Process USING [MsecToTicks, Pause],
Pup USING [Host];
IPOpsImpl:
CEDAR
PROGRAM
IMPORTS Basics, BasicTime, CommDriver, IPQueue, IPReassembly, IPRouter, PrincOpsUtils, Process
EXPORTS IPOps, CommBuffer =
BEGIN OPEN IPOps;
Encapsulation: PUBLIC TYPE = CommDriverType.Encapsulation;
Exported
MoveBytes:
PUBLIC
UNSAFE
PROC [toPtr:
LONG
POINTER, toOffset:
INT, fromPtr:
LONG
POINTER, fromOffset:
INT, length:
INT] =
UNCHECKED
BEGIN
moved: INT;
to: LONG POINTER TO PACKED ARRAY [0..500) OF CHAR = LOOPHOLE[toPtr];
from: LONG POINTER TO PACKED ARRAY [0..500) OF CHAR = LOOPHOLE[fromPtr];
IF ~(length IN [0..LAST[CARDINAL]]) THEN ERROR;
moved ← PrincOpsUtils.ByteBlt[[toPtr, toOffset, toOffset+length], [fromPtr, fromOffset, fromOffset+length]];
IF length # moved THEN ERROR;
END;
UnsafeHeaderChecksum:
UNSAFE
PROC [header:
LONG
POINTER
TO IPDefs.InternetHeader]
RETURNS [checksum: IPDefs.DByte] ~
UNCHECKED {
Compute the header checksum for a datagram.
p: LONG POINTER TO CARDINAL ← LOOPHOLE[header];
maxHeaderLength: INT ~ 10 + IPDefs.maxOptionLength / 2;
nWords: INT ~ MIN[header.IHL, maxHeaderLength];
cs: CARDINAL ← OnesComplementAddBlock[ptr: p, count: 2*nWords, initialSum: Basics.BITNOT[header.checksum]]; -- Start with negative of the checksum that's in the header so that we don't have to smash it to zero to compute the real checksum.
RETURN [Basics.BITNOT[cs]]; -- return one's complement of computed sum
};
HeaderChecksum:
PUBLIC
PROC [data: IPDefs.Datagram]
RETURNS [checksum: IPDefs.DByte] ~
TRUSTED {
Compute the header checksum for a datagram.
RETURN UnsafeHeaderChecksum[@data.inHdr];
};
ChecksumsMatch:
PROC [c1, c2: IPDefs.DByte]
RETURNS [
BOOL] ~ {
RETURN [c1 = c2 OR ((c1 = 0 OR c1 = 65535) AND (c2 = 0 OR c2 = 65535))];
};
OnesComplementAddBlock:
PUBLIC
UNSAFE
PROC [ptr:
LONG
POINTER, count:
CARDINAL, initialSum:
CARDINAL ← 0]
RETURNS [sum:
CARDINAL] ~
UNCHECKED {
Computes (efficiently) the ones-complement sum of the 16-bit words in the block [ptr .. ptr+count)^.
p: LONG POINTER TO ARRAY [0..8) OF CARDINAL ← LOOPHOLE[ptr];
s: LONG CARDINAL ← initialSum;
FOR i: CARDINAL IN [0..count MOD 8) DO s ← s + p[i]; ENDLOOP;
p ← p+count MOD 8;
THROUGH [0..count/8)
DO
s ← s + LONG[p[0]] + LONG[p[1]] + LONG[p[2]] + LONG[p[3]] + LONG[p[4]] + LONG[p[5]] + LONG[p[6]] + LONG[p[7]];
p ← p+8;
ENDLOOP;
WHILE Basics.HighHalf[s]#0
DO
s ← LONG[Basics.HighHalf[s]]+LONG[Basics.LowHalf[s]];
ENDLOOP;
RETURN[Basics.LowHalf[s]];
};
Send:
PUBLIC
PROC [etherDest: Pup.Host, buffer: CommDriver.Buffer, bytes:
CARDINAL] = {
buffer.ovh.encap ← Encapsulation[ethernetOne [etherSpare1:, etherSpare2:, etherSpare3:, etherSpare4:, etherSpare5:, ethernetOneDest: etherDest, ethernetOneSource: network.pup.host, ethernetOneType: toImp]];
network.other.send[network, buffer, bytes];
};
network: CommDriver.Network; -- handle on the Ethernet
HandleIncomingPacket: CommDriver.RecvProc =
TRUSTED
[network: CommDriver.Network, buffer: CommDriver.Buffer, bytes: NAT] RETURNS [CommDriver.Buffer]
BEGIN
The receiver process calls this procedure with new packets. While here, we check that the packet checksums and lengths are ok. Then we dive into the monitor to do reassembly and queueing.
headerPtr: LONG POINTER TO IPDefs.InternetHeader;
headerLength: INT;
data: IPDefs.Datagram;
IF buffer.ovh.encap.ethernetOneType # fromImp THEN RETURN[buffer];
headerPtr ← IPRouter.DatagramPointer[buffer];
Crosscheck IP length with bytes above
IF headerPtr.
IHL < 5
OR
NOT headerPtr.packetLength
IN [20..IPDefs.maxDataLength+20]
OR
NOT ChecksumsMatch[headerPtr.checksum, UnsafeHeaderChecksum[headerPtr]]
THEN {
-- bad packet
RETURN [buffer]; };
data ← NEW[IPDefs.DatagramRec];
headerLength ← headerPtr.IHL*4;
MoveBytes[@data.inHdr, 0, headerPtr, 0, headerLength];
MoveBytes[@data.data, 0, headerPtr, headerLength, headerPtr.packetLength-headerLength];
data.dataLength ← headerPtr.packetLength-headerLength;
data.optionLength ← headerLength - IPDefs.minIHL*4;
data ← IPReassembly.Reassemble[data];
IF data # NIL THEN IPQueue.QueueDatagram[data];
RETURN [buffer];
END;