MODULE ICMP;
IMPORT SYSTEM, Machine, Modules, KernelLog, IP, IPv6, Network, Strings;
CONST
DEBUG = FALSE;
Ok* = 0;
AlreadyInstalled* = 3501;
NeverInstalled* = 3502;
ICMPDstUnreachable* = 1;
TypeEchoReplyv4* = 0;
TypeDstUnreachablev4 = 3;
TypeSourceQuenchv4 = 4;
TypeRedirectv4 = 5;
TypeEchoRequestv4* = 8;
TypeTimeExceededv4* = 11;
TypeDstUnreachablev6 = 1;
TypePacketTooBigv6 = 2;
TypeTimeExceededv6* = 3;
TypeParamProbv6 = 4;
TypeEchoRequestv6* = 128;
TypeEchoReplyv6* = 129;
TypeNeighborSolicitation = 135;
TypeNeighborAdvertisement = 136;
TypeRouterSolicitation = 133;
TypeRouterAdvertisement = 134;
IPTypeICMPv4 = 1;
IPTypeICMPv6 = 58;
ICMPHdrLen = IP.ICMPHdrLen;
MaxPseudoHdrLen = 40;
PrefixOptHdrLen = 4;
MTUOptHdrLen = 1;
RtrAdvHdrLen = 12;
TimeExcHdrLen = 4;
ParamExcHdrLen = 4;
TYPE
Receiver* = PROCEDURE {DELEGATE} (int: IP.Interface; type, code: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
VAR
receivers: ARRAY 256 OF Receiver;
NICMPRcvTotal-, NICMPTooSmall-, NICMPBadChecksum-, NICMPNoReceiver-, NICMPDelivered-,
NICMPEchoRequest-, NICMPSend-: LONGINT;
res: LONGINT;
PROCEDURE Input(int: IP.Interface; type: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
VAR
code: LONGINT;
receiver: Receiver;
checksumOk: BOOLEAN;
sum: LONGINT;
pseudoHdrLen: LONGINT;
pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR;
reassembledLength: LONGINT;
fragmentBuffer: Network.Buffer;
BEGIN
IF DEBUG THEN
ASSERT ((type = IPTypeICMPv6) OR (type = IPTypeICMPv4));
END;
Machine.AtomicInc(NICMPRcvTotal);
IF buffer.len >= ICMPHdrLen THEN
IF int.protocol = IP.IPv4 THEN
checksumOk := IP.Checksum2(buffer.data, buffer.ofs, buffer.len, 0) = 0;
ELSIF int.protocol = IP.IPv6 THEN
sum := Network.GetNet2(buffer.data, buffer.ofs + 2);
IF sum # 0 THEN
reassembledLength := 0;
fragmentBuffer := buffer;
WHILE fragmentBuffer # NIL DO
INC(reassembledLength, fragmentBuffer.len);
fragmentBuffer := fragmentBuffer.nextFragment;
END;
pseudoHdrLen := int.WritePseudoHeader(pseudoHdr, fip, lip, IPTypeICMPv6, reassembledLength);
sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
IF buffer.nextFragment # NIL THEN
fragmentBuffer := buffer;
WHILE fragmentBuffer.nextFragment # NIL DO
sum := IP.Checksum1(fragmentBuffer.data, fragmentBuffer.ofs, fragmentBuffer.len, sum);
fragmentBuffer := fragmentBuffer.nextFragment;
END;
sum := IP.Checksum2(fragmentBuffer.data, fragmentBuffer.ofs, fragmentBuffer.len, sum);
ELSE
sum := IP.Checksum2(buffer.data, buffer.ofs, buffer.len, sum);
END;
END;
checksumOk := sum = 0;
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
checksumOk := FALSE;
END;
IF checksumOk THEN
type := ORD(buffer.data[buffer.ofs]);
code := ORD(buffer.data[buffer.ofs+1]);
receiver := receivers[type];
IF receiver # NIL THEN
buffer.l4ofs := buffer.ofs;
INC(buffer.ofs, ICMPHdrLen);
DEC(buffer.len, ICMPHdrLen);
receiver(int, type, code, fip, lip, buffer);
Machine.AtomicInc(NICMPDelivered);
RETURN;
ELSE
Machine.AtomicInc(NICMPNoReceiver);
END;
ELSE
Machine.AtomicInc(NICMPBadChecksum);
END;
ELSE
Machine.AtomicInc(NICMPTooSmall);
END;
Network.ReturnBuffer(buffer);
END Input;
PROCEDURE Send*(interface: IP.Interface; fip: IP.Adr; VAR data: ARRAY OF CHAR; ofs, len, type, code, TTL: LONGINT);
VAR
hdr: ARRAY ICMPHdrLen OF CHAR;
pseudoHdrLen: LONGINT;
pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR;
sum: LONGINT;
BEGIN
IF interface = NIL THEN
interface := IP.InterfaceByDstIP(fip);
END;
IF interface # NIL THEN
Machine.AtomicInc(NICMPSend);
hdr[0] := CHR(type);
hdr[1] := CHR(code);
IF fip.usedProtocol = IP.IPv4 THEN
Network.Put2(hdr, 2, IP.Checksum2(data, ofs, len, IP.Checksum1(hdr, 0, 2, 0)));
interface.Send(IPTypeICMPv4, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
ELSIF fip.usedProtocol = IP.IPv6 THEN
pseudoHdrLen := interface.WritePseudoHeader(pseudoHdr, interface.localAdr, fip, IPTypeICMPv6, len+ICMPHdrLen);
sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
sum := IP.Checksum1(hdr, 0, ICMPHdrLen, sum);
sum := IP.Checksum2(data, ofs, len, sum);
Network.Put2(hdr, 2, sum);
interface.Send(IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
END;
END;
END Send;
PROCEDURE SendDirectly*(interface: IPv6.Interface; linkDst: Network.LinkAdr; fip: IP.Adr; VAR data: ARRAY OF CHAR; ofs, len, type, code, TTL: LONGINT);
VAR
hdr: ARRAY ICMPHdrLen OF CHAR;
pseudoHdrLen: LONGINT;
pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR;
sum: LONGINT;
BEGIN
IF DEBUG THEN
ASSERT (interface # NIL);
ASSERT (fip.usedProtocol = IP.IPv6);
END;
IF interface # NIL THEN
Machine.AtomicInc(NICMPSend);
hdr[0] := CHR(type);
hdr[1] := CHR(code);
pseudoHdrLen := interface.WritePseudoHeader(pseudoHdr, interface.localAdr, fip, IPTypeICMPv6, len+ICMPHdrLen);
sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
sum := IP.Checksum1(hdr, 0, ICMPHdrLen, sum);
sum := IP.Checksum2(data, ofs, len, sum);
Network.Put2(hdr, 2, sum);
interface.SendDirectly(linkDst, IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
END;
END SendDirectly;
PROCEDURE InstallReceiver*(type: LONGINT; r: Receiver; VAR res: LONGINT);
BEGIN {EXCLUSIVE}
ASSERT(r # NIL);
ASSERT((type >=0) & (type <= 255));
IF receivers[type] # NIL THEN
res := AlreadyInstalled;
ELSE
receivers[type] := r;
res := Ok;
END;
END InstallReceiver;
PROCEDURE RemoveReceiver*(type: LONGINT; VAR res: LONGINT);
BEGIN {EXCLUSIVE}
ASSERT((type >=0) & (type <= 255));
IF receivers[type] = NIL THEN
res := NeverInstalled;
ELSE
res := Ok;
receivers[type] := NIL;
END;
END RemoveReceiver;
PROCEDURE ReplyEcho*(int: IP.Interface; type, code: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
VAR
longData: POINTER TO ARRAY OF CHAR;
fragmentBuffer: Network.Buffer;
fragmentLen: LONGINT;
i: LONGINT;
BEGIN
Machine.AtomicInc(NICMPEchoRequest);
IF ~int.IsBroadcast(lip) THEN
IF fip.usedProtocol = IP.IPv4 THEN
Send(int, fip, buffer.data, buffer.ofs, buffer.len, TypeEchoReplyv4, 0, IP.MaxTTL);
ELSIF fip.usedProtocol = IP.IPv6 THEN
IF buffer.nextFragment = NIL THEN
Send(int, fip, buffer.data, buffer.ofs, buffer.len, TypeEchoReplyv6, 0, IP.MaxTTL);
ELSE
NEW(longData, IPv6.MaxFragPacketSize);
fragmentBuffer := buffer;
fragmentLen := 0;
WHILE fragmentBuffer # NIL DO
FOR i := 0 TO fragmentBuffer.len - 1 DO
longData^[fragmentLen + i] := fragmentBuffer.data[fragmentBuffer.ofs + i];
END;
INC(fragmentLen, fragmentBuffer.len);
fragmentBuffer := fragmentBuffer.nextFragment;
END;
Send(int, fip, longData^, 0, fragmentLen, TypeEchoReplyv6, 0, IP.MaxTTL);
END;
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
END
END;
Network.ReturnBuffer(buffer);
END ReplyEcho;
PROCEDURE SendICMP* (type: LONGINT; fip: IP.Adr; buffer: Network.Buffer);
VAR
IPHdrLen: LONGINT;
icmpMsg: ARRAY 72 OF CHAR;
BEGIN {EXCLUSIVE}
CASE type OF
ICMPDstUnreachable:
IPHdrLen := buffer.ofs - buffer.l3ofs;
Network.Put4(icmpMsg, 0, 0);
Network.Copy(buffer.data, icmpMsg, buffer.l3ofs, 4, IPHdrLen + 8);
Send(NIL, fip, icmpMsg, 0, 4+IPHdrLen+8, TypeDstUnreachablev4, 3, IP.MaxTTL);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
END;
END SendICMP;
PROCEDURE SendNeighborAdvertisement*(interface: IPv6.Interface; linkDst: Network.LinkAdr; dstAdr: IP.Adr; solicited: BOOLEAN);
VAR
nsData: ARRAY IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen OF CHAR;
nsDataLen: LONGINT;
i: LONGINT;
flagsSet: SET;
BEGIN
flagsSet := {};
IF interface.isRouter THEN
flagsSet := flagsSet + {31};
END;
IF solicited THEN
flagsSet := flagsSet + {30};
END;
flagsSet := flagsSet + {29};
Network.PutNet4(nsData, 0, SYSTEM.VAL(LONGINT, flagsSet));
FOR i := 0 TO 3 DO
Network.Put4(nsData, 4+(i*4), Network.Get4(interface.localAdr.ipv6Adr, i * 4));
END;
IF ~IP.IsNilAdr(dstAdr) THEN
nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
nsData[20] := 2X;
nsData[21] := 1X;
FOR i := 0 TO 5 DO
nsData[22+i] := interface.dev.local[i];
END;
ELSE
nsDataLen := 20;
END;
IF solicited THEN
SendDirectly (interface, linkDst, dstAdr, nsData, 0, nsDataLen, TypeNeighborAdvertisement, 0, IP.MaxTTL);
ELSE
SendDirectly (interface, IPv6.linkMulticastAllNodesAdr, dstAdr, nsData, 0, nsDataLen, TypeNeighborAdvertisement, 0, IP.MaxTTL);
END;
END SendNeighborAdvertisement;
PROCEDURE SendNeighborSolicitation*(interface: IPv6.Interface; linkDst: Network.LinkAdr; dstAdr: IP.Adr; multicast: BOOLEAN);
VAR
nsData: ARRAY IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen OF CHAR;
nsDataLen: LONGINT;
solicitedNodeDstAdr: IP.Adr;
i: LONGINT;
BEGIN
Network.Put4(nsData, 0, 0);
FOR i := 0 TO 3 DO
Network.Put4(nsData, 4+(i*4), Network.Get4(dstAdr.ipv6Adr, i * 4));
END;
IF ~IP.IsNilAdr(dstAdr) THEN
nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
nsData[20] := 1X;
nsData[21] := 1X;
FOR i := 0 TO 5 DO
nsData[22+i] := interface.dev.local[i];
END;
ELSE
nsDataLen := 20;
END;
IF multicast THEN
solicitedNodeDstAdr := IPv6.linkLocalMulticastNodeAdr;
FOR i := 13 TO 15 DO
solicitedNodeDstAdr.ipv6Adr[i] := dstAdr.ipv6Adr[i];
END;
solicitedNodeDstAdr.ipv6Adr[11] := 1X;
solicitedNodeDstAdr.ipv6Adr[12] := 0FFX;
SendDirectly (interface, linkDst, solicitedNodeDstAdr, nsData, 0, nsDataLen, TypeNeighborSolicitation, 0, IP.MaxTTL);
ELSE
SendDirectly (interface, linkDst, dstAdr, nsData, 0, nsDataLen, TypeNeighborSolicitation, 0, IP.MaxTTL);
END;
END SendNeighborSolicitation;
PROCEDURE SendRouterSolicitation(interface: IPv6.Interface);
VAR
rsData: ARRAY IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen OF CHAR;
rsDataLen: LONGINT;
i: LONGINT;
BEGIN
Network.Put4(rsData, 0, 0);
rsDataLen := IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen;
rsData[4] := 1X;
rsData[5] := 1X;
FOR i := 0 TO 5 DO
rsData[6+i] := interface.dev.local[i];
END;
SendDirectly (interface, IPv6.linkMulticastAllRoutersAdr, IPv6.linkLocalMulticastRouterAdr, rsData, 0, rsDataLen, TypeRouterSolicitation, 0, IP.MaxTTL);
END SendRouterSolicitation;
PROCEDURE SendRouterAdvertisement(interface: IPv6.Interface; dstAdr: IP.Adr; dstLinkAdr: Network.LinkAdr; routerConfig: IPv6.RouterConfig);
VAR
raData: POINTER TO ARRAY OF CHAR;
raDataLen: LONGINT;
nbrOfPrefixes: LONGINT;
prefixConfigItem: IPv6.PrefixConfig;
flags: SET;
offset: LONGINT;
i: LONGINT;
BEGIN
nbrOfPrefixes := 0;
prefixConfigItem := routerConfig.Prefixes;
WHILE prefixConfigItem # NIL DO
prefixConfigItem := prefixConfigItem.next;
INC(nbrOfPrefixes);
END;
INC(raDataLen, nbrOfPrefixes * 8 * PrefixOptHdrLen);
INC(raDataLen, IPv6.LLAdrOptionLen);
IF routerConfig.LinkMTU # 0 THEN
INC(raDataLen, MTUOptHdrLen * 8);
END;
INC(raDataLen, RtrAdvHdrLen);
NEW(raData, raDataLen);
raData^[0] := CHR(routerConfig.CurrentHopLimit);
flags := {};
IF routerConfig.ManagedAddressConfig THEN
flags := flags + {7};
END;
IF routerConfig.OtherStatefulConfig THEN
flags := flags + {6};
END;
raData^[1] := SYSTEM.VAL(CHAR, flags);
Network.PutNet2(raData^, 2, routerConfig.Lifetime);
Network.PutNet4(raData^, 4, routerConfig.ReachableTime);
Network.PutNet4(raData^, 8, routerConfig.RetransTimer);
offset := 12;
raData^[offset] := 1X;
raData^[offset + 1] := 1X;
FOR i := 0 TO 5 DO
raData^[offset + 2 + i] := interface.dev.local[i];
END;
INC(offset, IPv6.LLAdrOptionLen);
IF routerConfig.LinkMTU # 0 THEN
raData^[offset] := 5X;
raData^[offset+1] := 1X;
Network.Put2(raData^, offset + 2, 0);
Network.PutNet4(raData^, offset + 4, routerConfig.LinkMTU);
INC(offset, 8);
END;
prefixConfigItem := routerConfig.Prefixes;
WHILE prefixConfigItem # NIL DO
raData^[offset] := 3X;
raData^[offset + 1] := 4X;
raData^[offset + 2] := CHR(prefixConfigItem.Prefix.data);
flags := {};
IF prefixConfigItem.OnLink THEN
flags := flags + {7};
END;
IF prefixConfigItem.Autonomous THEN
flags := flags + {6};
END;
IF prefixConfigItem.IsSitePrefix THEN
flags := flags + {4};
END;
raData^[offset + 3] := SYSTEM.VAL(CHAR, flags);
Network.PutNet4(raData^, offset + 4, prefixConfigItem.ValidLifetime);
Network.PutNet4(raData^, offset + 8, prefixConfigItem.PreferredLifetime);
Network.Put4(raData^, offset + 12, 0);
IF prefixConfigItem.IsSitePrefix THEN
raData^[offset + 15] := CHR(prefixConfigItem.Prefix.data);
END;
FOR i := 0 TO 15 DO
raData^[offset + 16 + i] := prefixConfigItem.Prefix.ipv6Adr[i];
END;
INC(offset, 8 * PrefixOptHdrLen);
prefixConfigItem := prefixConfigItem.next;
END;
SendDirectly (interface, dstLinkAdr, dstAdr, raData^, 0, raDataLen, TypeRouterAdvertisement, 0, IP.MaxTTL);
END SendRouterAdvertisement;
PROCEDURE SendICMPv6TimeExceeded(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; code: LONGINT);
VAR
teData: ARRAY TimeExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
teDataLen: LONGINT;
i: LONGINT;
BEGIN
Network.Put4(teData, 0, 0);
teDataLen := Strings.Min(TimeExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen, TimeExcHdrLen + discardedPacket.len);
FOR i := TimeExcHdrLen TO teDataLen - 1 DO
teData[i] := discardedPacket.data[i - TimeExcHdrLen];
END;
Send(interface, srcAdr, teData, 0, teDataLen, TypeTimeExceededv6, code, interface.curHopLimit);
END SendICMPv6TimeExceeded;
PROCEDURE SendICMPv6ParamProb(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; probPointer: LONGINT; code: LONGINT);
VAR
ppData: ARRAY ParamExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
ppDataLen: LONGINT;
i: LONGINT;
BEGIN
Network.Put4(ppData, 0, probPointer);
ppDataLen := Strings.Min(ParamExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen, ParamExcHdrLen + discardedPacket.len);
FOR i := ParamExcHdrLen TO ppDataLen - 1 DO
ppData[i] := discardedPacket.data[i - ParamExcHdrLen];
END;
Send(interface, srcAdr, ppData, 0, ppDataLen, TypeParamProbv6, code, interface.curHopLimit);
END SendICMPv6ParamProb;
PROCEDURE ReceiveNeighborSolicitation (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
ipv6Interface: IPv6.Interface;
BEGIN
IF interface IS IPv6.Interface THEN
ipv6Interface := interface (IPv6.Interface);
ipv6Interface.ReceiveNeighborSolicitation(srcAdr, dstAdr, buffer);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
Network.ReturnBuffer(buffer);
END;
END ReceiveNeighborSolicitation;
PROCEDURE ReceiveNeighborAdvertisement (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
ipv6Interface: IPv6.Interface;
BEGIN
IF interface IS IPv6.Interface THEN
ipv6Interface := interface (IPv6.Interface);
ipv6Interface.ReceiveNeighborAdvertisement (srcAdr, dstAdr, buffer);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
Network.ReturnBuffer(buffer);
END;
END ReceiveNeighborAdvertisement;
PROCEDURE ReceiveRouterSolicitation(interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
ipv6Interface: IPv6.Interface;
BEGIN
IF interface IS IPv6.Interface THEN
ipv6Interface := interface (IPv6.Interface);
ipv6Interface.ReceiveRouterSolicitation();
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
END;
KernelLog.Enter;KernelLog.Ln; KernelLog.String("************************");KernelLog.Ln;
KernelLog.String("Received a router advertisement");
KernelLog.String("");
KernelLog.Ln; KernelLog.String("************************");KernelLog.Ln;KernelLog.Exit;
Network.ReturnBuffer(buffer);
END ReceiveRouterSolicitation;
PROCEDURE ReceiveRouterAdvertisement (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
ipv6Interface: IPv6.Interface;
BEGIN
IF interface IS IPv6.Interface THEN
ipv6Interface := interface (IPv6.Interface);
ipv6Interface.ReceiveRouterAdvertisement(srcAdr, buffer);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
Network.ReturnBuffer(buffer);
END;
END ReceiveRouterAdvertisement;
PROCEDURE ReceivePacketTooBig (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
ipv6Interface: IPv6.Interface;
BEGIN
IF interface IS IPv6.Interface THEN
ipv6Interface := interface(IPv6.Interface);
ipv6Interface.ReceivePacketTooBig(srcAdr, buffer);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
Network.ReturnBuffer(buffer);
END;
END ReceivePacketTooBig;
PROCEDURE LinkLayerAdrOption (VAR buffer: Network.Buffer; VAR linkAdr: Network.LinkAdr);
VAR
i: LONGINT;
BEGIN
IF DEBUG THEN
ASSERT ((buffer.data[buffer.ofs] = 1X) OR (buffer.data[buffer.ofs] = 2X));
END;
FOR i := 0 TO 5 DO
linkAdr[i] := buffer.data[buffer.ofs + i + 2];
END;
linkAdr[6] := 0X;
linkAdr[7] := 0X;
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END LinkLayerAdrOption;
PROCEDURE PrefixInfoOption(VAR buffer: Network.Buffer;
VAR onLink: BOOLEAN;
VAR autonomous: BOOLEAN;
VAR routerAddress: BOOLEAN;
VAR sitePrefix: BOOLEAN;
VAR validLifetime: LONGINT;
VAR preferredLifetime: LONGINT;
VAR sitePrefixLength: LONGINT;
VAR prefix: IP.Adr);
VAR
flags: SET;
i: LONGINT;
BEGIN
prefix.data := ORD(buffer.data[buffer.ofs + 2]);
flags := SYSTEM.VAL(SET, buffer.data[buffer.ofs + 3]);
onLink := 7 IN flags;
autonomous := 6 IN flags;
routerAddress := 5 IN flags;
sitePrefix := 4 IN flags;
validLifetime := Network.GetNet4(buffer.data, buffer.ofs + 4);
preferredLifetime := Network.GetNet4(buffer.data, buffer.ofs + 8);
sitePrefixLength := ORD(buffer.data[buffer.ofs + 15]);
prefix.usedProtocol := IP.IPv6;
FOR i := 0 TO 15 DO
prefix.ipv6Adr[i] := buffer.data[buffer.ofs + 16 + i]
END;
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END PrefixInfoOption;
PROCEDURE RedirectHdrOption(VAR buffer: Network.Buffer);
BEGIN
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END RedirectHdrOption;
PROCEDURE MTUOption(VAR buffer: Network.Buffer; VAR MTU: LONGINT);
BEGIN
MTU := Network.GetNet4(buffer.data, buffer.ofs + 4);
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END MTUOption;
PROCEDURE AdvIntervalOption(VAR buffer: Network.Buffer);
BEGIN
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END AdvIntervalOption;
PROCEDURE HomeAgentInfoOption(VAR buffer: Network.Buffer);
BEGIN
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END HomeAgentInfoOption;
PROCEDURE RouteInfoOption(VAR buffer: Network.Buffer);
BEGIN
DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
END RouteInfoOption;
PROCEDURE Cleanup;
VAR
res: LONGINT;
BEGIN
IPv6.sendNeighborSolicitation := NIL;
IPv6.sendNeighborAdvertisement := NIL;
IPv6.sendRouterSolicitation := NIL;
IPv6.sendRouterAdvertisement := NIL;
IPv6.icmpLinkLayerAdrOption := NIL;
IPv6.icmpPrefixInfoOption := NIL;
IPv6.icmpRedirectHdrOption := NIL;
IPv6.icmpMTUOption := NIL;
IPv6.icmpAdvIntervalOption := NIL;
IPv6.icmpHomeAgentInfoOption := NIL;
IPv6.icmpRouteInfoOption := NIL;
RemoveReceiver(TypeEchoRequestv4, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypeEchoRequestv6, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypeNeighborSolicitation, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypeNeighborAdvertisement, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypeRouterAdvertisement, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypeRouterSolicitation, res);
IF DEBUG THEN ASSERT (res = Ok) END;
RemoveReceiver(TypePacketTooBigv6, res);
IF DEBUG THEN ASSERT (res = Ok) END;
IP.RemoveReceiver(IPTypeICMPv4);
IP.RemoveReceiver(IPTypeICMPv6);
END Cleanup;
PROCEDURE InitDelegates*;
BEGIN
IPv6.sendNeighborSolicitation := SendNeighborSolicitation;
IPv6.sendNeighborAdvertisement := SendNeighborAdvertisement;
IPv6.sendRouterAdvertisement := SendRouterAdvertisement;
IPv6.sendRouterSolicitation := SendRouterSolicitation;
IPv6.sendICMPv6TimeExceeded := SendICMPv6TimeExceeded;
IPv6.sendICMPv6ParamProb := SendICMPv6ParamProb;
IPv6.icmpLinkLayerAdrOption := LinkLayerAdrOption;
IPv6.icmpPrefixInfoOption := PrefixInfoOption;
IPv6.icmpRedirectHdrOption := RedirectHdrOption;
IPv6.icmpMTUOption := MTUOption;
IPv6.icmpAdvIntervalOption := AdvIntervalOption;
IPv6.icmpHomeAgentInfoOption := HomeAgentInfoOption;
IPv6.icmpRouteInfoOption := RouteInfoOption;
END InitDelegates;
BEGIN
IF (IP.EchoReply) THEN
InstallReceiver(TypeEchoRequestv4, ReplyEcho, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypeEchoRequestv6, ReplyEcho, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypeNeighborSolicitation, ReceiveNeighborSolicitation, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypeNeighborAdvertisement, ReceiveNeighborAdvertisement, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypeRouterAdvertisement, ReceiveRouterAdvertisement, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypeRouterSolicitation, ReceiveRouterSolicitation, res);
IF DEBUG THEN ASSERT (res = Ok) END;
InstallReceiver(TypePacketTooBigv6, ReceivePacketTooBig, res);
IF DEBUG THEN ASSERT (res = Ok) END;
END;
IP.InstallReceiver(IPTypeICMPv4, Input);
IP.InstallReceiver(IPTypeICMPv6, Input);
Modules.InstallTermHandler(Cleanup);
END ICMP.
(*
History:
21.10.2003 mvt Created and moved the ICMP impelementation from the IP module to this one.
26.10.2003 mvt Adapted to new design of IP.
02.05.2005 eb IPv6 (Neighbor Discovery / EchoRequest / EchoReply
*)