ArpaIP.mesa
Demers, September 4, 1987 6:31:23 pm PDT
DIRECTORY
Arpa USING [Address],
ArpaBuf USING [Buffer, Protocol]
;
ArpaIP: CEDAR DEFINITIONS ~ {
Types
Handle: TYPE ~ REF Object;
Object: TYPE;
Buffer: TYPE ~ ArpaBuf.Buffer;
Buffers: TYPE ~ ArpaBuf.Buffer;
Chain of buffers (linked together by b.ovh.next) containing a single IP datagram. If the datagram fits in a single buffer, that's the way it's represented; otherwise it's kept as a list of (long) fragments.
ChecksumProc: TYPE ~ PROC [b: Buffers];
Checksum computing proc used by Send.
RouteHint: TYPE ~ REF;
Cached routing information used by Send.
nullRouteHint: READONLY RouteHint;
Registration
CreateHandle: PROC [protocol: ArpaBuf.Protocol, recvProc: RecvProc, recvErrorProc: RecvProc ← NIL, acceptLongDatagrams: BOOLFALSE]
RETURNS [handle: Handle];
Register self as protocol module for given protocol.
recvProc gets called with received packets of the given protocol.
recvErrorProc gets called with received ICMP packets generated in response to packets of the given protocol.
If acceptLongDatagrams is FALSE, chains of fragments will not be presented to the recvProc or accepted on output.
! Error[$protocolAlreadyRegistered]
DestroyHandle: PROC [handle: Handle];
Unregister this protocol module.
Beware: there's a race that can cause recvProc or recvErrorProc to be called after the handle has been destroyed.
! Error[$handleDestroyed]
Receiving
RecvProc: TYPE ~ PROC [b: Buffers] RETURNS [rB: Buffers];
A RecvProc gets called with every received IP datagram. The datagram has been reassembled into a single buffer if it fits; otherwise it is represented as (large) fragments in a chain of buffers.
A RecvProc also gets called with certain ICMP datagrams. See ArpaICMP for details.
The bodyBytes is the same number that would be returned by GetUserBytes[b].
The result buffer list rB is returned to the CommDriver buffer pool. It needn't be the same as b, and may be NIL.
FreeBuffers: PROC [b: Buffers];
Free a chain of buffers. Not equivalent to CommDriver.FreeBuffer!
GetUserBytes: PROC [b: Buffer] RETURNS [bodyBytes: CARDINAL, optionsBytes: CARDINAL];
Return the number of bytes in the datagram (fragment) contained in b^. The fixed part of the IP header is not counted, and IP options are counted separately. Note the TCP or UDP header is counted in bodyBytes.
GetSource: PROC [b: Buffers] RETURNS [source: Arpa.Address];
This is how to determine the sender.
Sending
AllocBuffers: PROC [howMany: CARDINAL ← 1] RETURNS [Buffers];
Allocate a buffer list of the specified length.
SetUserBytes: PROC [b: Buffer, bodyBytes: CARDINAL, optionsBytes: CARDINAL ← 0];
Set the length of the datagram (fragment) body and options. The fixed part of the IP header isn't counted in bodyBytes, but the UDP or TCP header is.
Options may only be present in the first fragment of a chain.
SetNoFragmentation: PROC [b: Buffers, inhibitFragmentation: BOOLTRUE];
Is it okay to fragment this packet in transmission?
SetUserBytes[b] implicitly does SetNoFragmentation[b, FALSE]; so to inhibit fragmentation you must call SetNoFragmentation[b] after calling SetUserBytes[b].
Send: PROC [h: Handle, b: Buffers, dest: Arpa.Address, setChecksum: ChecksumProc ← NIL, hint: RouteHint ← NIL] RETURNS [newHint: RouteHint];
Send chain of buffers. The length field must be correct in each fragment in the chain (set by SetUserBytes), and the options length must be 0 in all but the first fragment. Fragmentation control fields will be filled in automatically, and options from the first fragment will be copied to the remaining ones as appropriate.
If the destination address is Arpa.broadcastAddress, the datagram will be broadcast on all network interfaces.
The ChecksumProc is passed in by the client to compute a higher-level protocol checksum field. It is called once, after the datagram has been routed, so the IP header source address has been filled in properly before the checksum is computed. This ugly mechanism is necessary because of the "pseudo-header" in UPD and TCP checksums.
The hint / newHint is a performance hack for cacheing of routes. If you pass NIL (the default) it will recompute the route for each send, and return NIL. If you pass nullRouteHint, if will recompute the route and return a RouteHint that can be passed in on subsequent calls to avoid the overhead of the routing computation. Use this only if you're really worried about performance.
On return, the content of buffers is unmodified. Buffers aren't freed.
! Error[$nullDestination | $destUnreachable | $datagramTooLong | $clientFragmentationError]
Options
See option type description in ArpaBuf.mesa.
In each case the position argument is 0-relative to the beginning of the entire options field, not the individual option.
FetchOptionAddress: PROC [b: Buffer, pos: CARDINAL] RETURNS [address: Arpa.Address];
FetchOptionByte: PROC [b: Buffer, pos: CARDINAL] RETURNS [value: BYTE];
FetchOptionH: PROC [b: Buffer, pos: CARDINAL] RETURNS [value: CARD16];
FetchOptionF: PROC [b: Buffer, pos: CARDINAL] RETURNS [value: CARD32];
StoreOptionAddress: PROC [b: Buffer, pos: CARDINAL, address: Arpa.Address];
StoreOptionByte: PROC [b: Buffer, pos: CARDINAL, value: BYTE];
StoreOptionH: PROC [b: Buffer, pos: CARDINAL, value: CARD16];
StoreOptionF: PROC [b: Buffer, pos: CARDINAL, value: CARD32];
Backdoor
SendToSelf: PUBLIC PROC [h: Handle, b: Buffers, dest: Arpa.Address, setChecksum: ChecksumProc];
Caller asserts that dest is an address of this machine.
Fragmentation/reassembly is avoided, and the bits are not sent on the wire.
The buffers are passed to the receiving process.
DispatchICMP: PROC [b: Buffers, protocol: ArpaBuf.Protocol];
Pass buffers to specified protocol module. Used to pass appropriate ICMP messages to protocol modules that know how to deal with them.
Utilities
Useful to higher-level protocols that are clients of IP.
OnesComplementAddBlock: UNSAFE PROC [ptr: LONG POINTER, count: CARDINAL, initialSum: CARDINAL ← 0] RETURNS [sum: CARDINAL];
Compute (efficiently) the ones-complement sum of the 16-bit words in the block [ptr..ptr+count)^. Useful for checksum procs.
MoveBytes: UNSAFE PROC [toPtr: LONG POINTER, toOffset: INT, fromPtr: LONG POINTER, fromOffset: INT, bytes: INT];
Move (efficiently) between from and to.
Errors
Error: ERROR [code: ATOM];
The error codes that can occur:
$protocolOutOfRange : bogus protocol specified to CreateHandle.
$nilRecvProc : NIL recvProc in call to CreateHandle.
$protocolAlreadyRegistered : we only allow one protocol module per protocol.
$handleDestroyed : you can't send on a handle after calling Destroy, or Destroy a handle more than once.
$notICMP : non-ICMP datagram passed to Dispatch
others as they become necessary.
}...