123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909 |
- MODULE ICMP; (** AUTHOR "mvt"; PURPOSE "ICMP protocol"; *)
- (*
- ICMPv4 Header
- 00 08 type
- 01 08 code
- 02 16 checksum of icmp header and data
- 04 -- contents
- ICMPv4 Echo Request/Reply Packet
- 00 08 type = 8 (request) or type = 0 (reply)
- 01 08 code = 0
- 02 16 checksum of icmp header and data
- 04 16 identifier
- 06 16 sequence number
- 08 -- optional data
- Notes:
- o Bit numbers above are Intel bit order.
- o Avoid use of SET because of PPC bit numbering issues.
- o Always access fields as 8-, 16- or 32-bit values and use DIV, MOD, ASH, ODD for bit access.
- *)
- IMPORT SYSTEM, Machine, Modules, KernelLog, IP, IPv6, Network;
- CONST
- (* DEBUG *)
- DEBUG = FALSE;
- (** Error codes *)
- Ok* = 0;
- AlreadyInstalled* = 3501;
- NeverInstalled* = 3502;
- (* ICMP type exported *)
- ICMPDstUnreachable* = 1;
- (** ICMPv4 types *)
- TypeEchoReplyv4* = 0;
- TypeDstUnreachablev4 = 3;
- TypeSourceQuenchv4 = 4;
- TypeRedirectv4 = 5;
- TypeEchoRequestv4* = 8;
- TypeTimeExceededv4* = 11;
- (* ICMPv6 error types *)
- TypeDstUnreachablev6 = 1;
- TypePacketTooBigv6 = 2;
- TypeTimeExceededv6* = 3;
- TypeParamProbv6 = 4;
- (* ICMPv6 informal messages types *)
- TypeEchoRequestv6* = 128;
- TypeEchoReplyv6* = 129;
- (* Neighbor Discovery *)
- TypeNeighborSolicitation = 135;
- TypeNeighborAdvertisement = 136;
- TypeRouterSolicitation = 133;
- TypeRouterAdvertisement = 134;
- IPTypeICMPv4 = 1; (* ICMPv4 type code for IP packets *)
- IPTypeICMPv6 = 58; (* ICMPv6 type code for IP packets *)
- ICMPHdrLen = IP.ICMPHdrLen; (* length of ICMP header *)
- MaxPseudoHdrLen = 40; (* IPv6: 40 *)
- PrefixOptHdrLen = 4; (* 4 * 8-byte block *)
- MTUOptHdrLen = 1; (* 1 * 8-byte block *)
- RtrAdvHdrLen = 12; (* Router advertisement header length *)
- TimeExcHdrLen = 4; (* ICMPv6 time exceeded header length *)
- ParamExcHdrLen = 4; (* ICMPv6 parameter problem header length *)
- TYPE
- Receiver* = PROCEDURE {DELEGATE} (int: IP.Interface; type, code: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
- VAR
- receivers: ARRAY 256 OF Receiver; (* registered receivers - array position is ICMP packet type *)
- (* Statistic variables *)
- NICMPRcvTotal-, NICMPTooSmall-, NICMPBadChecksum-, NICMPNoReceiver-, NICMPDelivered-,
- NICMPEchoRequest-, NICMPSend-: LONGINT;
- res: WORD;
- (* Receive an ICMP (v4 and v6) packet *)
- 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; (* pseudo header for calculating checksum *)
- reassembledLength: LONGINT;
- fragmentBuffer: Network.Buffer;
- BEGIN
- IF DEBUG THEN
- ASSERT ((type = IPTypeICMPv6) OR (type = IPTypeICMPv4));
- END;
- Machine.AtomicInc(NICMPRcvTotal);
- IF buffer.len >= ICMPHdrLen THEN
- (* Checksum calculation of ICMPv4 and ICMPv6 is different! In ICMPv6 another pseudo header is used *)
- IF int.protocol = IP.IPv4 THEN
- checksumOk := IP.Checksum2(buffer.data, buffer.ofs, buffer.len, 0) = 0;
- ELSIF int.protocol = IP.IPv6 THEN
- (* Get checksum from header *)
- sum := Network.GetNet2(buffer.data, buffer.ofs + 2);
- IF sum # 0 THEN
- (* calculate checksum *)
- (* set pseudo header *)
- 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
- (* fragmented packets *)
- 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;
- (* interface with unknown protocol *)
- 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
- (* do receiver upcall *)
- buffer.l4ofs := buffer.ofs;
- INC(buffer.ofs, ICMPHdrLen);
- DEC(buffer.len, ICMPHdrLen);
- receiver(int, type, code, fip, lip, buffer);
- Machine.AtomicInc(NICMPDelivered);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Machine.AtomicInc(NICMPNoReceiver);
- END;
- ELSE
- Machine.AtomicInc(NICMPBadChecksum);
- END;
- ELSE
- Machine.AtomicInc(NICMPTooSmall);
- END;
- (* Exit and return buffer here because it is no longer used *)
- Network.ReturnBuffer(buffer);
- END Input;
- (** Send an ICMP packet. The variables "type" and "code" must conatin the ICMP type and code information.
- interface can be set to send the ICMP message on a specific interface otherwise it is automatically slected. *)
- 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; (* pseudo header for calculating checksum *)
- sum: LONGINT;
- BEGIN
- (* IF no interface was given choose one *)
- IF interface = NIL THEN
- interface := IP.InterfaceByDstIP(fip);
- END;
- IF interface # NIL THEN
- Machine.AtomicInc(NICMPSend);
- (* Set ICMP header *)
- 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
- (* Use pseudo header for checksum calculation *)
- (* set pseudo header *)
- 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); (* checksum := sum *)
- interface.Send(IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
- END;
- END;
- END Send;
- (** Send an ICMP packet. The variables "type" and "code" must conatin the ICMP type and code information.
- interface must be set. The ICMPv6 packet is directly send without cache lookups etc. *)
- 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; (* pseudo header for calculating checksum *)
- sum: LONGINT;
- BEGIN
- IF DEBUG THEN
- ASSERT (interface # NIL);
- ASSERT (fip.usedProtocol = IP.IPv6);
- END;
- IF interface # NIL THEN
- Machine.AtomicInc(NICMPSend);
- (* Set ICMP header *)
- hdr[0] := CHR(type);
- hdr[1] := CHR(code);
- (* Use pseudo header for checksum calculation *)
- (* set pseudo header *)
- 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); (* checksum := sum *)
- interface.SendDirectly(linkDst, IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
- END;
- END SendDirectly;
- (** Install a receiver for this type *)
- PROCEDURE InstallReceiver*(type: LONGINT; r: Receiver; VAR res: WORD);
- 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;
- (** Remove the currently installed receiver for this type *)
- PROCEDURE RemoveReceiver*(type: LONGINT; VAR res: WORD);
- BEGIN {EXCLUSIVE}
- ASSERT((type >=0) & (type <= 255));
- IF receivers[type] = NIL THEN
- res := NeverInstalled;
- ELSE
- res := Ok;
- receivers[type] := NIL;
- END;
- END RemoveReceiver;
- (** Standard receiver that replies echo requests *)
- 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
- (* packet is fragmented *)
- 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;
- (* Unknown protocol *)
- END
- END;
- Network.ReturnBuffer(buffer);
- END ReplyEcho;
- (* Send a ICMP message *)
- PROCEDURE SendICMP* (type: LONGINT; fip: IP.Adr; buffer: Network.Buffer);
- VAR
- IPHdrLen: LONGINT; (* length of IP header to copy *)
- icmpMsg: ARRAY 72 OF CHAR; (* unused (4) + MaxIPHdrLen (60) + UDPHdrLen (8) *)
- BEGIN {EXCLUSIVE}
- CASE type OF
- ICMPDstUnreachable:
- IPHdrLen := buffer.ofs - buffer.l3ofs;
- Network.Put4(icmpMsg, 0, 0); (* unused *)
- (* 8: first 8 bytes of the original datagram-s dataIP header UDP header *)
- 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;
- (* Send a Neighbor Advertisement message *)
- 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 := {};
- (* routerFlag *)
- IF interface.isRouter THEN
- flagsSet := flagsSet + {31};
- END;
- (* solicited flag *)
- IF solicited THEN
- flagsSet := flagsSet + {30};
- END;
- (* override flag is true *)
- flagsSet := flagsSet + {29};
- Network.PutNet4(nsData, 0, SYSTEM.VAL(LONGINT, flagsSet)); (* flags & reserved *)
- FOR i := 0 TO 3 DO (* Target address 16 byte *)
- Network.Put4(nsData, 4+(i*4), Network.Get4(interface.localAdr.ipv6Adr, i * 4));
- END;
- IF ~IP.IsNilAdr(dstAdr) THEN
- (* Add a Source Link-Layer Address option *)
- nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
- nsData[20] := 2X; (* Type = 2 *)
- nsData[21] := 1X; (* Length = 1 : Ethernet MAC Address (6bytes) *)
- FOR i := 0 TO 5 DO (* Link-Layer Address *)
- nsData[22+i] := interface.dev.local[i];
- END;
- ELSE
- nsDataLen := 20;
- END;
- (* Send packet directly without Neighbor Cache lookup etc. *)
- 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;
- (* Send a Neighbor Solicitation message *)
- 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); (* Reserved *)
- FOR i := 0 TO 3 DO (* Target address 16 byte *)
- Network.Put4(nsData, 4+(i*4), Network.Get4(dstAdr.ipv6Adr, i * 4));
- END;
- IF ~IP.IsNilAdr(dstAdr) THEN
- (* Add a Source Link-Layer Address option *)
- nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
- nsData[20] := 1X; (* Type = 1 *)
- nsData[21] := 1X; (* Length = 1 : Ethernet MAC Address (6bytes) *)
- FOR i := 0 TO 5 DO (* Link-Layer Address *)
- nsData[22+i] := interface.dev.local[i];
- END;
- ELSE
- nsDataLen := 20;
- END;
- (* Send packet directly without Neighbor Cache lookup etc. *)
- 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;
- (* Send a Router Solicitation message *)
- PROCEDURE SendRouterSolicitation(interface: IPv6.Interface);
- VAR
- rsData: ARRAY IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen OF CHAR;
- rsDataLen: LONGINT;
- i: LONGINT;
- BEGIN
- Network.Put4(rsData, 0, 0); (* Reserved *)
- (* Add a source link-layer option *)
- rsDataLen := IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen;
- rsData[4] := 1X; (* Type = 1 *)
- rsData[5] := 1X; (* Length = 1: Ethernet MAC Address (6 bytes) *)
- FOR i := 0 TO 5 DO (* Link-Layer Address *)
- rsData[6+i] := interface.dev.local[i];
- END;
- SendDirectly (interface, IPv6.linkMulticastAllRoutersAdr, IPv6.linkLocalMulticastRouterAdr, rsData, 0, rsDataLen, TypeRouterSolicitation, 0, IP.MaxTTL);
- END SendRouterSolicitation;
- (* Send a Router Advertisement message *)
- 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
- (* Count number of prefix options *)
- nbrOfPrefixes := 0;
- prefixConfigItem := routerConfig.Prefixes;
- WHILE prefixConfigItem # NIL DO
- prefixConfigItem := prefixConfigItem.next;
- INC(nbrOfPrefixes);
- END;
- INC(raDataLen, nbrOfPrefixes * 8 * PrefixOptHdrLen); (* prefix options header len is written in number of 8-bytes block *)
- (* Source link-layer address option *)
- INC(raDataLen, IPv6.LLAdrOptionLen);
- (* MTU option *)
- IF routerConfig.LinkMTU # 0 THEN
- INC(raDataLen, MTUOptHdrLen * 8);
- END;
- INC(raDataLen, RtrAdvHdrLen);
- NEW(raData, raDataLen);
- (* Fill packet *)
- raData^[0] := CHR(routerConfig.CurrentHopLimit); (* Current hop limit *)
- (* Managed address configuration, other stateful configuration and home agent flag
- Home flag is always zero. *)
- 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;
- (* Add a source link-layer option *)
- raData^[offset] := 1X; (* Type = 1 *)
- raData^[offset + 1] := 1X; (* Length = 1: Ethernet MAC Address (6 bytes) *)
- FOR i := 0 TO 5 DO (* Link-Layer Address *)
- raData^[offset + 2 + i] := interface.dev.local[i];
- END;
- INC(offset, IPv6.LLAdrOptionLen);
- (* LinkMTU option *)
- 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;
- (* Prefixes *)
- prefixConfigItem := routerConfig.Prefixes;
- WHILE prefixConfigItem # NIL DO
- raData^[offset] := 3X;
- raData^[offset + 1] := 4X;
- raData^[offset + 2] := CHR(prefixConfigItem.Prefix.data);
- (* flags *)
- flags := {};
- IF prefixConfigItem.OnLink THEN
- flags := flags + {7};
- END;
- IF prefixConfigItem.Autonomous THEN
- flags := flags + {6};
- END;
- (* router address flag is always zero: Mobility support is disabled *)
- 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;
- (** Send a ICMPv6 time exceeded message *)
- PROCEDURE SendICMPv6TimeExceeded(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; code: LONGINT);
- VAR
- (* Max size of a ICMPv6 time exceeded packet including portion of discarded packet is 1280 *)
- teData: ARRAY TimeExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
- teDataLen: LONGINT;
- i: LONGINT;
- BEGIN
- Network.Put4(teData, 0, 0); (* Unused *)
- (* add portion of discarded packet *)
- teDataLen := 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;
- (** Send a ICMPv6 parameter problem message *)
- PROCEDURE SendICMPv6ParamProb(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; probPointer: LONGINT; code: LONGINT);
- VAR
- (* Max size of a ICMPv6 parameter problem packet including portion of discarded packet is 1280 *)
- ppData: ARRAY ParamExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
- ppDataLen: LONGINT;
- i: LONGINT;
- BEGIN
- Network.Put4(ppData, 0, probPointer);
- (* add portion of discarded packet *)
- ppDataLen := 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;
- (* Receive a neighbor Soliciation message *)
- 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
- (* Only IPv6 *)
- ipv6Interface := interface (IPv6.Interface);
- ipv6Interface.ReceiveNeighborSolicitation(srcAdr, dstAdr, buffer);
- ELSE
- IF DEBUG THEN
- ASSERT(TRUE);
- END;
- Network.ReturnBuffer(buffer);
- END;
- END ReceiveNeighborSolicitation;
- (* Receive a neighbor Advertisement message *)
- 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
- (* Only IPv6 *)
- ipv6Interface := interface (IPv6.Interface);
- ipv6Interface.ReceiveNeighborAdvertisement (srcAdr, dstAdr, buffer);
- ELSE
- IF DEBUG THEN
- ASSERT(TRUE);
- END;
- Network.ReturnBuffer(buffer);
- END;
- END ReceiveNeighborAdvertisement;
- (* Receive a router solicitation message *)
- 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
- (* Only IPv6 *)
- 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;
- (* Receive a router advertisement message *)
- 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
- (* Only IPv6 *)
- ipv6Interface := interface (IPv6.Interface);
- ipv6Interface.ReceiveRouterAdvertisement(srcAdr, buffer);
- ELSE
- IF DEBUG THEN
- ASSERT(TRUE);
- END;
- Network.ReturnBuffer(buffer);
- END;
- END ReceiveRouterAdvertisement;
- (* Receive a packet too big message *)
- 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
- (* Only IPv6 *)
- ipv6Interface := interface(IPv6.Interface);
- ipv6Interface.ReceivePacketTooBig(srcAdr, buffer);
- ELSE
- IF DEBUG THEN
- ASSERT(TRUE);
- END;
- Network.ReturnBuffer(buffer);
- END;
- END ReceivePacketTooBig;
- (** Reads Source or Target Link-Layer address option. Buffer.ofs has to be set to the Type byte*)
- PROCEDURE LinkLayerAdrOption (VAR buffer: Network.Buffer; VAR linkAdr: Network.LinkAdr);
- VAR
- i: LONGINT;
- BEGIN
- IF DEBUG THEN
- (* Type is Source or Target Link *)
- 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;
- (* Reads ICMP prefix information option *)
- 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])); (* Length field times 8 bytes*)
- END PrefixInfoOption;
- (* Reads ICMP redirect header option *)
- 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])); (* Length field times 8 bytes*)
- END RedirectHdrOption;
- (* Reads ICMP MTU option *)
- 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])); (* Length field times 8 bytes*)
- END MTUOption;
- (* Reads ICMP advertisement interval option *)
- 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])); (* Length field times 8 bytes*)
- END AdvIntervalOption;
- (* Reads ICMP home agent information option *)
- 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])); (* Length field times 8 bytes*)
- END HomeAgentInfoOption;
- (* Reads ICMP route information option *)
- 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])); (* Length field times 8 bytes*)
- END RouteInfoOption;
- PROCEDURE Cleanup;
- VAR
- res: WORD;
- 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;
- (* Remove ICMP receivers *)
- 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;
- (* Remove IP receivers *)
- IP.RemoveReceiver(IPTypeICMPv4);
- IP.RemoveReceiver(IPTypeICMPv6);
- END Cleanup;
- PROCEDURE InitDelegates*;
- BEGIN
- (* set delegates in IPv6 *)
- 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
- (* install internal echoRequest receiver *)
- InstallReceiver(TypeEchoRequestv4, ReplyEcho, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- InstallReceiver(TypeEchoRequestv6, ReplyEcho, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- (* Install neighbor discovery reiceivers *)
- InstallReceiver(TypeNeighborSolicitation, ReceiveNeighborSolicitation, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- InstallReceiver(TypeNeighborAdvertisement, ReceiveNeighborAdvertisement, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- (* Router Advertisement *)
- InstallReceiver(TypeRouterAdvertisement, ReceiveRouterAdvertisement, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- (* Router Solicitation *)
- InstallReceiver(TypeRouterSolicitation, ReceiveRouterSolicitation, res);
- IF DEBUG THEN ASSERT (res = Ok) END;
- (* Packet too big *)
- 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
- *)
|