ICMP.Mod 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. MODULE ICMP; (** AUTHOR "mvt"; PURPOSE "ICMP protocol"; *)
  2. (*
  3. ICMPv4 Header
  4. 00 08 type
  5. 01 08 code
  6. 02 16 checksum of icmp header and data
  7. 04 -- contents
  8. ICMPv4 Echo Request/Reply Packet
  9. 00 08 type = 8 (request) or type = 0 (reply)
  10. 01 08 code = 0
  11. 02 16 checksum of icmp header and data
  12. 04 16 identifier
  13. 06 16 sequence number
  14. 08 -- optional data
  15. Notes:
  16. o Bit numbers above are Intel bit order.
  17. o Avoid use of SET because of PPC bit numbering issues.
  18. o Always access fields as 8-, 16- or 32-bit values and use DIV, MOD, ASH, ODD for bit access.
  19. *)
  20. IMPORT SYSTEM, Machine, Modules, KernelLog, IP, IPv6, Network;
  21. CONST
  22. (* DEBUG *)
  23. DEBUG = FALSE;
  24. (** Error codes *)
  25. Ok* = 0;
  26. AlreadyInstalled* = 3501;
  27. NeverInstalled* = 3502;
  28. (* ICMP type exported *)
  29. ICMPDstUnreachable* = 1;
  30. (** ICMPv4 types *)
  31. TypeEchoReplyv4* = 0;
  32. TypeDstUnreachablev4 = 3;
  33. TypeSourceQuenchv4 = 4;
  34. TypeRedirectv4 = 5;
  35. TypeEchoRequestv4* = 8;
  36. TypeTimeExceededv4* = 11;
  37. (* ICMPv6 error types *)
  38. TypeDstUnreachablev6 = 1;
  39. TypePacketTooBigv6 = 2;
  40. TypeTimeExceededv6* = 3;
  41. TypeParamProbv6 = 4;
  42. (* ICMPv6 informal messages types *)
  43. TypeEchoRequestv6* = 128;
  44. TypeEchoReplyv6* = 129;
  45. (* Neighbor Discovery *)
  46. TypeNeighborSolicitation = 135;
  47. TypeNeighborAdvertisement = 136;
  48. TypeRouterSolicitation = 133;
  49. TypeRouterAdvertisement = 134;
  50. IPTypeICMPv4 = 1; (* ICMPv4 type code for IP packets *)
  51. IPTypeICMPv6 = 58; (* ICMPv6 type code for IP packets *)
  52. ICMPHdrLen = IP.ICMPHdrLen; (* length of ICMP header *)
  53. MaxPseudoHdrLen = 40; (* IPv6: 40 *)
  54. PrefixOptHdrLen = 4; (* 4 * 8-byte block *)
  55. MTUOptHdrLen = 1; (* 1 * 8-byte block *)
  56. RtrAdvHdrLen = 12; (* Router advertisement header length *)
  57. TimeExcHdrLen = 4; (* ICMPv6 time exceeded header length *)
  58. ParamExcHdrLen = 4; (* ICMPv6 parameter problem header length *)
  59. TYPE
  60. Receiver* = PROCEDURE {DELEGATE} (int: IP.Interface; type, code: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
  61. VAR
  62. receivers: ARRAY 256 OF Receiver; (* registered receivers - array position is ICMP packet type *)
  63. (* Statistic variables *)
  64. NICMPRcvTotal-, NICMPTooSmall-, NICMPBadChecksum-, NICMPNoReceiver-, NICMPDelivered-,
  65. NICMPEchoRequest-, NICMPSend-: LONGINT;
  66. res: WORD;
  67. (* Receive an ICMP (v4 and v6) packet *)
  68. PROCEDURE Input(int: IP.Interface; type: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
  69. VAR
  70. code: LONGINT;
  71. receiver: Receiver;
  72. checksumOk: BOOLEAN;
  73. sum: LONGINT;
  74. pseudoHdrLen: LONGINT;
  75. pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR; (* pseudo header for calculating checksum *)
  76. reassembledLength: LONGINT;
  77. fragmentBuffer: Network.Buffer;
  78. BEGIN
  79. IF DEBUG THEN
  80. ASSERT ((type = IPTypeICMPv6) OR (type = IPTypeICMPv4));
  81. END;
  82. Machine.AtomicInc(NICMPRcvTotal);
  83. IF buffer.len >= ICMPHdrLen THEN
  84. (* Checksum calculation of ICMPv4 and ICMPv6 is different! In ICMPv6 another pseudo header is used *)
  85. IF int.protocol = IP.IPv4 THEN
  86. checksumOk := IP.Checksum2(buffer.data, buffer.ofs, buffer.len, 0) = 0;
  87. ELSIF int.protocol = IP.IPv6 THEN
  88. (* Get checksum from header *)
  89. sum := Network.GetNet2(buffer.data, buffer.ofs + 2);
  90. IF sum # 0 THEN
  91. (* calculate checksum *)
  92. (* set pseudo header *)
  93. reassembledLength := 0;
  94. fragmentBuffer := buffer;
  95. WHILE fragmentBuffer # NIL DO
  96. INC(reassembledLength, fragmentBuffer.len);
  97. fragmentBuffer := fragmentBuffer.nextFragment;
  98. END;
  99. pseudoHdrLen := int.WritePseudoHeader(pseudoHdr, fip, lip, IPTypeICMPv6, reassembledLength);
  100. sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
  101. IF buffer.nextFragment # NIL THEN
  102. (* fragmented packets *)
  103. fragmentBuffer := buffer;
  104. WHILE fragmentBuffer.nextFragment # NIL DO
  105. sum := IP.Checksum1(fragmentBuffer.data, fragmentBuffer.ofs, fragmentBuffer.len, sum);
  106. fragmentBuffer := fragmentBuffer.nextFragment;
  107. END;
  108. sum := IP.Checksum2(fragmentBuffer.data, fragmentBuffer.ofs, fragmentBuffer.len, sum);
  109. ELSE
  110. sum := IP.Checksum2(buffer.data, buffer.ofs, buffer.len, sum);
  111. END;
  112. END;
  113. checksumOk := sum = 0;
  114. ELSE
  115. IF DEBUG THEN
  116. ASSERT(TRUE);
  117. END;
  118. (* interface with unknown protocol *)
  119. checksumOk := FALSE;
  120. END;
  121. IF checksumOk THEN
  122. type := ORD(buffer.data[buffer.ofs]);
  123. code := ORD(buffer.data[buffer.ofs+1]);
  124. receiver := receivers[type];
  125. IF receiver # NIL THEN
  126. (* do receiver upcall *)
  127. buffer.l4ofs := buffer.ofs;
  128. INC(buffer.ofs, ICMPHdrLen);
  129. DEC(buffer.len, ICMPHdrLen);
  130. receiver(int, type, code, fip, lip, buffer);
  131. Machine.AtomicInc(NICMPDelivered);
  132. (* Exit here w/o returning buffer because it is passed to a receiver *)
  133. RETURN;
  134. ELSE
  135. Machine.AtomicInc(NICMPNoReceiver);
  136. END;
  137. ELSE
  138. Machine.AtomicInc(NICMPBadChecksum);
  139. END;
  140. ELSE
  141. Machine.AtomicInc(NICMPTooSmall);
  142. END;
  143. (* Exit and return buffer here because it is no longer used *)
  144. Network.ReturnBuffer(buffer);
  145. END Input;
  146. (** Send an ICMP packet. The variables "type" and "code" must conatin the ICMP type and code information.
  147. interface can be set to send the ICMP message on a specific interface otherwise it is automatically slected. *)
  148. PROCEDURE Send*(interface: IP.Interface; fip: IP.Adr; VAR data: ARRAY OF CHAR; ofs, len, type, code, TTL: LONGINT);
  149. VAR
  150. hdr: ARRAY ICMPHdrLen OF CHAR;
  151. pseudoHdrLen: LONGINT;
  152. pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR; (* pseudo header for calculating checksum *)
  153. sum: LONGINT;
  154. BEGIN
  155. (* IF no interface was given choose one *)
  156. IF interface = NIL THEN
  157. interface := IP.InterfaceByDstIP(fip);
  158. END;
  159. IF interface # NIL THEN
  160. Machine.AtomicInc(NICMPSend);
  161. (* Set ICMP header *)
  162. hdr[0] := CHR(type);
  163. hdr[1] := CHR(code);
  164. IF fip.usedProtocol = IP.IPv4 THEN
  165. Network.Put2(hdr, 2, IP.Checksum2(data, ofs, len, IP.Checksum1(hdr, 0, 2, 0)));
  166. interface.Send(IPTypeICMPv4, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
  167. ELSIF fip.usedProtocol = IP.IPv6 THEN
  168. (* Use pseudo header for checksum calculation *)
  169. (* set pseudo header *)
  170. pseudoHdrLen := interface.WritePseudoHeader(pseudoHdr, interface.localAdr, fip, IPTypeICMPv6, len+ICMPHdrLen);
  171. sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
  172. sum := IP.Checksum1(hdr, 0, ICMPHdrLen, sum);
  173. sum := IP.Checksum2(data, ofs, len, sum);
  174. Network.Put2(hdr, 2, sum); (* checksum := sum *)
  175. interface.Send(IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
  176. END;
  177. END;
  178. END Send;
  179. (** Send an ICMP packet. The variables "type" and "code" must conatin the ICMP type and code information.
  180. interface must be set. The ICMPv6 packet is directly send without cache lookups etc. *)
  181. PROCEDURE SendDirectly*(interface: IPv6.Interface; linkDst: Network.LinkAdr; fip: IP.Adr; VAR data: ARRAY OF CHAR; ofs, len, type, code, TTL: LONGINT);
  182. VAR
  183. hdr: ARRAY ICMPHdrLen OF CHAR;
  184. pseudoHdrLen: LONGINT;
  185. pseudoHdr: ARRAY MaxPseudoHdrLen OF CHAR; (* pseudo header for calculating checksum *)
  186. sum: LONGINT;
  187. BEGIN
  188. IF DEBUG THEN
  189. ASSERT (interface # NIL);
  190. ASSERT (fip.usedProtocol = IP.IPv6);
  191. END;
  192. IF interface # NIL THEN
  193. Machine.AtomicInc(NICMPSend);
  194. (* Set ICMP header *)
  195. hdr[0] := CHR(type);
  196. hdr[1] := CHR(code);
  197. (* Use pseudo header for checksum calculation *)
  198. (* set pseudo header *)
  199. pseudoHdrLen := interface.WritePseudoHeader(pseudoHdr, interface.localAdr, fip, IPTypeICMPv6, len+ICMPHdrLen);
  200. sum := IP.Checksum1(pseudoHdr, 0, pseudoHdrLen, 0);
  201. sum := IP.Checksum1(hdr, 0, ICMPHdrLen, sum);
  202. sum := IP.Checksum2(data, ofs, len, sum);
  203. Network.Put2(hdr, 2, sum); (* checksum := sum *)
  204. interface.SendDirectly(linkDst, IPTypeICMPv6, fip, hdr, data, ICMPHdrLen, ofs, len, TTL);
  205. END;
  206. END SendDirectly;
  207. (** Install a receiver for this type *)
  208. PROCEDURE InstallReceiver*(type: LONGINT; r: Receiver; VAR res: WORD);
  209. BEGIN {EXCLUSIVE}
  210. ASSERT(r # NIL);
  211. ASSERT((type >=0) & (type <= 255));
  212. IF receivers[type] # NIL THEN
  213. res := AlreadyInstalled;
  214. ELSE
  215. receivers[type] := r;
  216. res := Ok;
  217. END;
  218. END InstallReceiver;
  219. (** Remove the currently installed receiver for this type *)
  220. PROCEDURE RemoveReceiver*(type: LONGINT; VAR res: WORD);
  221. BEGIN {EXCLUSIVE}
  222. ASSERT((type >=0) & (type <= 255));
  223. IF receivers[type] = NIL THEN
  224. res := NeverInstalled;
  225. ELSE
  226. res := Ok;
  227. receivers[type] := NIL;
  228. END;
  229. END RemoveReceiver;
  230. (** Standard receiver that replies echo requests *)
  231. PROCEDURE ReplyEcho*(int: IP.Interface; type, code: LONGINT; fip, lip: IP.Adr; buffer: Network.Buffer);
  232. VAR
  233. longData: POINTER TO ARRAY OF CHAR;
  234. fragmentBuffer: Network.Buffer;
  235. fragmentLen: LONGINT;
  236. i: LONGINT;
  237. BEGIN
  238. Machine.AtomicInc(NICMPEchoRequest);
  239. IF ~int.IsBroadcast(lip) THEN
  240. IF fip.usedProtocol = IP.IPv4 THEN
  241. Send(int, fip, buffer.data, buffer.ofs, buffer.len, TypeEchoReplyv4, 0, IP.MaxTTL);
  242. ELSIF fip.usedProtocol = IP.IPv6 THEN
  243. IF buffer.nextFragment = NIL THEN
  244. Send(int, fip, buffer.data, buffer.ofs, buffer.len, TypeEchoReplyv6, 0, IP.MaxTTL);
  245. ELSE
  246. (* packet is fragmented *)
  247. NEW(longData, IPv6.MaxFragPacketSize);
  248. fragmentBuffer := buffer;
  249. fragmentLen := 0;
  250. WHILE fragmentBuffer # NIL DO
  251. FOR i := 0 TO fragmentBuffer.len - 1 DO
  252. longData^[fragmentLen + i] := fragmentBuffer.data[fragmentBuffer.ofs + i];
  253. END;
  254. INC(fragmentLen, fragmentBuffer.len);
  255. fragmentBuffer := fragmentBuffer.nextFragment;
  256. END;
  257. Send(int, fip, longData^, 0, fragmentLen, TypeEchoReplyv6, 0, IP.MaxTTL);
  258. END;
  259. ELSE
  260. IF DEBUG THEN
  261. ASSERT(TRUE);
  262. END;
  263. (* Unknown protocol *)
  264. END
  265. END;
  266. Network.ReturnBuffer(buffer);
  267. END ReplyEcho;
  268. (* Send a ICMP message *)
  269. PROCEDURE SendICMP* (type: LONGINT; fip: IP.Adr; buffer: Network.Buffer);
  270. VAR
  271. IPHdrLen: LONGINT; (* length of IP header to copy *)
  272. icmpMsg: ARRAY 72 OF CHAR; (* unused (4) + MaxIPHdrLen (60) + UDPHdrLen (8) *)
  273. BEGIN {EXCLUSIVE}
  274. CASE type OF
  275. ICMPDstUnreachable:
  276. IPHdrLen := buffer.ofs - buffer.l3ofs;
  277. Network.Put4(icmpMsg, 0, 0); (* unused *)
  278. (* 8: first 8 bytes of the original datagram-s dataIP header UDP header *)
  279. Network.Copy(buffer.data, icmpMsg, buffer.l3ofs, 4, IPHdrLen + 8);
  280. Send(NIL, fip, icmpMsg, 0, 4+IPHdrLen+8, TypeDstUnreachablev4, 3, IP.MaxTTL);
  281. ELSE
  282. IF DEBUG THEN
  283. ASSERT(TRUE);
  284. END;
  285. END;
  286. END SendICMP;
  287. (* Send a Neighbor Advertisement message *)
  288. PROCEDURE SendNeighborAdvertisement*(interface: IPv6.Interface; linkDst: Network.LinkAdr; dstAdr: IP.Adr; solicited: BOOLEAN);
  289. VAR
  290. nsData: ARRAY IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen OF CHAR;
  291. nsDataLen: LONGINT;
  292. i: LONGINT;
  293. flagsSet: SET;
  294. BEGIN
  295. flagsSet := {};
  296. (* routerFlag *)
  297. IF interface.isRouter THEN
  298. flagsSet := flagsSet + {31};
  299. END;
  300. (* solicited flag *)
  301. IF solicited THEN
  302. flagsSet := flagsSet + {30};
  303. END;
  304. (* override flag is true *)
  305. flagsSet := flagsSet + {29};
  306. Network.PutNet4(nsData, 0, SYSTEM.VAL(LONGINT, flagsSet)); (* flags & reserved *)
  307. FOR i := 0 TO 3 DO (* Target address 16 byte *)
  308. Network.Put4(nsData, 4+(i*4), Network.Get4(interface.localAdr.ipv6Adr, i * 4));
  309. END;
  310. IF ~IP.IsNilAdr(dstAdr) THEN
  311. (* Add a Source Link-Layer Address option *)
  312. nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
  313. nsData[20] := 2X; (* Type = 2 *)
  314. nsData[21] := 1X; (* Length = 1 : Ethernet MAC Address (6bytes) *)
  315. FOR i := 0 TO 5 DO (* Link-Layer Address *)
  316. nsData[22+i] := interface.dev.local[i];
  317. END;
  318. ELSE
  319. nsDataLen := 20;
  320. END;
  321. (* Send packet directly without Neighbor Cache lookup etc. *)
  322. IF solicited THEN
  323. SendDirectly (interface, linkDst, dstAdr, nsData, 0, nsDataLen, TypeNeighborAdvertisement, 0, IP.MaxTTL);
  324. ELSE
  325. SendDirectly (interface, IPv6.linkMulticastAllNodesAdr, dstAdr, nsData, 0, nsDataLen, TypeNeighborAdvertisement, 0, IP.MaxTTL);
  326. END;
  327. END SendNeighborAdvertisement;
  328. (* Send a Neighbor Solicitation message *)
  329. PROCEDURE SendNeighborSolicitation*(interface: IPv6.Interface; linkDst: Network.LinkAdr; dstAdr: IP.Adr; multicast: BOOLEAN);
  330. VAR
  331. nsData: ARRAY IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen OF CHAR;
  332. nsDataLen: LONGINT;
  333. solicitedNodeDstAdr: IP.Adr;
  334. i: LONGINT;
  335. BEGIN
  336. Network.Put4(nsData, 0, 0); (* Reserved *)
  337. FOR i := 0 TO 3 DO (* Target address 16 byte *)
  338. Network.Put4(nsData, 4+(i*4), Network.Get4(dstAdr.ipv6Adr, i * 4));
  339. END;
  340. IF ~IP.IsNilAdr(dstAdr) THEN
  341. (* Add a Source Link-Layer Address option *)
  342. nsDataLen := IPv6.NeighborHdrLen + IPv6.LLAdrOptionLen;
  343. nsData[20] := 1X; (* Type = 1 *)
  344. nsData[21] := 1X; (* Length = 1 : Ethernet MAC Address (6bytes) *)
  345. FOR i := 0 TO 5 DO (* Link-Layer Address *)
  346. nsData[22+i] := interface.dev.local[i];
  347. END;
  348. ELSE
  349. nsDataLen := 20;
  350. END;
  351. (* Send packet directly without Neighbor Cache lookup etc. *)
  352. IF multicast THEN
  353. solicitedNodeDstAdr := IPv6.linkLocalMulticastNodeAdr;
  354. FOR i := 13 TO 15 DO
  355. solicitedNodeDstAdr.ipv6Adr[i] := dstAdr.ipv6Adr[i];
  356. END;
  357. solicitedNodeDstAdr.ipv6Adr[11] := 1X;
  358. solicitedNodeDstAdr.ipv6Adr[12] := 0FFX;
  359. SendDirectly (interface, linkDst, solicitedNodeDstAdr, nsData, 0, nsDataLen, TypeNeighborSolicitation, 0, IP.MaxTTL);
  360. ELSE
  361. SendDirectly (interface, linkDst, dstAdr, nsData, 0, nsDataLen, TypeNeighborSolicitation, 0, IP.MaxTTL);
  362. END;
  363. END SendNeighborSolicitation;
  364. (* Send a Router Solicitation message *)
  365. PROCEDURE SendRouterSolicitation(interface: IPv6.Interface);
  366. VAR
  367. rsData: ARRAY IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen OF CHAR;
  368. rsDataLen: LONGINT;
  369. i: LONGINT;
  370. BEGIN
  371. Network.Put4(rsData, 0, 0); (* Reserved *)
  372. (* Add a source link-layer option *)
  373. rsDataLen := IPv6.RouterSolHdrLen + IPv6.LLAdrOptionLen;
  374. rsData[4] := 1X; (* Type = 1 *)
  375. rsData[5] := 1X; (* Length = 1: Ethernet MAC Address (6 bytes) *)
  376. FOR i := 0 TO 5 DO (* Link-Layer Address *)
  377. rsData[6+i] := interface.dev.local[i];
  378. END;
  379. SendDirectly (interface, IPv6.linkMulticastAllRoutersAdr, IPv6.linkLocalMulticastRouterAdr, rsData, 0, rsDataLen, TypeRouterSolicitation, 0, IP.MaxTTL);
  380. END SendRouterSolicitation;
  381. (* Send a Router Advertisement message *)
  382. PROCEDURE SendRouterAdvertisement(interface: IPv6.Interface; dstAdr: IP.Adr; dstLinkAdr: Network.LinkAdr; routerConfig: IPv6.RouterConfig);
  383. VAR
  384. raData: POINTER TO ARRAY OF CHAR;
  385. raDataLen: LONGINT;
  386. nbrOfPrefixes: LONGINT;
  387. prefixConfigItem: IPv6.PrefixConfig;
  388. flags: SET;
  389. offset: LONGINT;
  390. i: LONGINT;
  391. BEGIN
  392. (* Count number of prefix options *)
  393. nbrOfPrefixes := 0;
  394. prefixConfigItem := routerConfig.Prefixes;
  395. WHILE prefixConfigItem # NIL DO
  396. prefixConfigItem := prefixConfigItem.next;
  397. INC(nbrOfPrefixes);
  398. END;
  399. INC(raDataLen, nbrOfPrefixes * 8 * PrefixOptHdrLen); (* prefix options header len is written in number of 8-bytes block *)
  400. (* Source link-layer address option *)
  401. INC(raDataLen, IPv6.LLAdrOptionLen);
  402. (* MTU option *)
  403. IF routerConfig.LinkMTU # 0 THEN
  404. INC(raDataLen, MTUOptHdrLen * 8);
  405. END;
  406. INC(raDataLen, RtrAdvHdrLen);
  407. NEW(raData, raDataLen);
  408. (* Fill packet *)
  409. raData^[0] := CHR(routerConfig.CurrentHopLimit); (* Current hop limit *)
  410. (* Managed address configuration, other stateful configuration and home agent flag
  411. Home flag is always zero. *)
  412. flags := {};
  413. IF routerConfig.ManagedAddressConfig THEN
  414. flags := flags + {7};
  415. END;
  416. IF routerConfig.OtherStatefulConfig THEN
  417. flags := flags + {6};
  418. END;
  419. raData^[1] := SYSTEM.VAL(CHAR, flags);
  420. Network.PutNet2(raData^, 2, routerConfig.Lifetime);
  421. Network.PutNet4(raData^, 4, routerConfig.ReachableTime);
  422. Network.PutNet4(raData^, 8, routerConfig.RetransTimer);
  423. offset := 12;
  424. (* Add a source link-layer option *)
  425. raData^[offset] := 1X; (* Type = 1 *)
  426. raData^[offset + 1] := 1X; (* Length = 1: Ethernet MAC Address (6 bytes) *)
  427. FOR i := 0 TO 5 DO (* Link-Layer Address *)
  428. raData^[offset + 2 + i] := interface.dev.local[i];
  429. END;
  430. INC(offset, IPv6.LLAdrOptionLen);
  431. (* LinkMTU option *)
  432. IF routerConfig.LinkMTU # 0 THEN
  433. raData^[offset] := 5X;
  434. raData^[offset+1] := 1X;
  435. Network.Put2(raData^, offset + 2, 0);
  436. Network.PutNet4(raData^, offset + 4, routerConfig.LinkMTU);
  437. INC(offset, 8);
  438. END;
  439. (* Prefixes *)
  440. prefixConfigItem := routerConfig.Prefixes;
  441. WHILE prefixConfigItem # NIL DO
  442. raData^[offset] := 3X;
  443. raData^[offset + 1] := 4X;
  444. raData^[offset + 2] := CHR(prefixConfigItem.Prefix.data);
  445. (* flags *)
  446. flags := {};
  447. IF prefixConfigItem.OnLink THEN
  448. flags := flags + {7};
  449. END;
  450. IF prefixConfigItem.Autonomous THEN
  451. flags := flags + {6};
  452. END;
  453. (* router address flag is always zero: Mobility support is disabled *)
  454. IF prefixConfigItem.IsSitePrefix THEN
  455. flags := flags + {4};
  456. END;
  457. raData^[offset + 3] := SYSTEM.VAL(CHAR, flags);
  458. Network.PutNet4(raData^, offset + 4, prefixConfigItem.ValidLifetime);
  459. Network.PutNet4(raData^, offset + 8, prefixConfigItem.PreferredLifetime);
  460. Network.Put4(raData^, offset + 12, 0);
  461. IF prefixConfigItem.IsSitePrefix THEN
  462. raData^[offset + 15] := CHR(prefixConfigItem.Prefix.data);
  463. END;
  464. FOR i := 0 TO 15 DO
  465. raData^[offset + 16 + i] := prefixConfigItem.Prefix.ipv6Adr[i];
  466. END;
  467. INC(offset, 8 * PrefixOptHdrLen);
  468. prefixConfigItem := prefixConfigItem.next;
  469. END;
  470. SendDirectly (interface, dstLinkAdr, dstAdr, raData^, 0, raDataLen, TypeRouterAdvertisement, 0, IP.MaxTTL);
  471. END SendRouterAdvertisement;
  472. (** Send a ICMPv6 time exceeded message *)
  473. PROCEDURE SendICMPv6TimeExceeded(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; code: LONGINT);
  474. VAR
  475. (* Max size of a ICMPv6 time exceeded packet including portion of discarded packet is 1280 *)
  476. teData: ARRAY TimeExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
  477. teDataLen: LONGINT;
  478. i: LONGINT;
  479. BEGIN
  480. Network.Put4(teData, 0, 0); (* Unused *)
  481. (* add portion of discarded packet *)
  482. teDataLen := MIN(TimeExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen, TimeExcHdrLen + discardedPacket.len);
  483. FOR i := TimeExcHdrLen TO teDataLen - 1 DO
  484. teData[i] := discardedPacket.data[i - TimeExcHdrLen];
  485. END;
  486. Send(interface, srcAdr, teData, 0, teDataLen, TypeTimeExceededv6, code, interface.curHopLimit);
  487. END SendICMPv6TimeExceeded;
  488. (** Send a ICMPv6 parameter problem message *)
  489. PROCEDURE SendICMPv6ParamProb(interface: IPv6.Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; probPointer: LONGINT; code: LONGINT);
  490. VAR
  491. (* Max size of a ICMPv6 parameter problem packet including portion of discarded packet is 1280 *)
  492. ppData: ARRAY ParamExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen OF CHAR;
  493. ppDataLen: LONGINT;
  494. i: LONGINT;
  495. BEGIN
  496. Network.Put4(ppData, 0, probPointer);
  497. (* add portion of discarded packet *)
  498. ppDataLen := MIN(ParamExcHdrLen + 1280 - IPv6.MaxIPHdrLen - ICMPHdrLen, ParamExcHdrLen + discardedPacket.len);
  499. FOR i := ParamExcHdrLen TO ppDataLen - 1 DO
  500. ppData[i] := discardedPacket.data[i - ParamExcHdrLen];
  501. END;
  502. Send(interface, srcAdr, ppData, 0, ppDataLen, TypeParamProbv6, code, interface.curHopLimit);
  503. END SendICMPv6ParamProb;
  504. (* Receive a neighbor Soliciation message *)
  505. PROCEDURE ReceiveNeighborSolicitation (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
  506. VAR
  507. ipv6Interface: IPv6.Interface;
  508. BEGIN
  509. IF interface IS IPv6.Interface THEN
  510. (* Only IPv6 *)
  511. ipv6Interface := interface (IPv6.Interface);
  512. ipv6Interface.ReceiveNeighborSolicitation(srcAdr, dstAdr, buffer);
  513. ELSE
  514. IF DEBUG THEN
  515. ASSERT(TRUE);
  516. END;
  517. Network.ReturnBuffer(buffer);
  518. END;
  519. END ReceiveNeighborSolicitation;
  520. (* Receive a neighbor Advertisement message *)
  521. PROCEDURE ReceiveNeighborAdvertisement (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
  522. VAR
  523. ipv6Interface: IPv6.Interface;
  524. BEGIN
  525. IF interface IS IPv6.Interface THEN
  526. (* Only IPv6 *)
  527. ipv6Interface := interface (IPv6.Interface);
  528. ipv6Interface.ReceiveNeighborAdvertisement (srcAdr, dstAdr, buffer);
  529. ELSE
  530. IF DEBUG THEN
  531. ASSERT(TRUE);
  532. END;
  533. Network.ReturnBuffer(buffer);
  534. END;
  535. END ReceiveNeighborAdvertisement;
  536. (* Receive a router solicitation message *)
  537. PROCEDURE ReceiveRouterSolicitation(interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
  538. VAR
  539. ipv6Interface: IPv6.Interface;
  540. BEGIN
  541. IF interface IS IPv6.Interface THEN
  542. (* Only IPv6 *)
  543. ipv6Interface := interface (IPv6.Interface);
  544. ipv6Interface.ReceiveRouterSolicitation();
  545. ELSE
  546. IF DEBUG THEN
  547. ASSERT(TRUE);
  548. END;
  549. END;
  550. KernelLog.Enter;KernelLog.Ln; KernelLog.String("************************");KernelLog.Ln;
  551. KernelLog.String("Received a router advertisement");
  552. KernelLog.String("");
  553. KernelLog.Ln; KernelLog.String("************************");KernelLog.Ln;KernelLog.Exit;
  554. Network.ReturnBuffer(buffer);
  555. END ReceiveRouterSolicitation;
  556. (* Receive a router advertisement message *)
  557. PROCEDURE ReceiveRouterAdvertisement (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
  558. VAR
  559. ipv6Interface: IPv6.Interface;
  560. BEGIN
  561. IF interface IS IPv6.Interface THEN
  562. (* Only IPv6 *)
  563. ipv6Interface := interface (IPv6.Interface);
  564. ipv6Interface.ReceiveRouterAdvertisement(srcAdr, buffer);
  565. ELSE
  566. IF DEBUG THEN
  567. ASSERT(TRUE);
  568. END;
  569. Network.ReturnBuffer(buffer);
  570. END;
  571. END ReceiveRouterAdvertisement;
  572. (* Receive a packet too big message *)
  573. PROCEDURE ReceivePacketTooBig (interface: IP.Interface; type, code: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
  574. VAR
  575. ipv6Interface: IPv6.Interface;
  576. BEGIN
  577. IF interface IS IPv6.Interface THEN
  578. (* Only IPv6 *)
  579. ipv6Interface := interface(IPv6.Interface);
  580. ipv6Interface.ReceivePacketTooBig(srcAdr, buffer);
  581. ELSE
  582. IF DEBUG THEN
  583. ASSERT(TRUE);
  584. END;
  585. Network.ReturnBuffer(buffer);
  586. END;
  587. END ReceivePacketTooBig;
  588. (** Reads Source or Target Link-Layer address option. Buffer.ofs has to be set to the Type byte*)
  589. PROCEDURE LinkLayerAdrOption (VAR buffer: Network.Buffer; VAR linkAdr: Network.LinkAdr);
  590. VAR
  591. i: LONGINT;
  592. BEGIN
  593. IF DEBUG THEN
  594. (* Type is Source or Target Link *)
  595. ASSERT ((buffer.data[buffer.ofs] = 1X) OR (buffer.data[buffer.ofs] = 2X));
  596. END;
  597. FOR i := 0 TO 5 DO
  598. linkAdr[i] := buffer.data[buffer.ofs + i + 2];
  599. END;
  600. linkAdr[6] := 0X;
  601. linkAdr[7] := 0X;
  602. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  603. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1]));
  604. END LinkLayerAdrOption;
  605. (* Reads ICMP prefix information option *)
  606. PROCEDURE PrefixInfoOption(VAR buffer: Network.Buffer;
  607. VAR onLink: BOOLEAN;
  608. VAR autonomous: BOOLEAN;
  609. VAR routerAddress: BOOLEAN;
  610. VAR sitePrefix: BOOLEAN;
  611. VAR validLifetime: LONGINT;
  612. VAR preferredLifetime: LONGINT;
  613. VAR sitePrefixLength: LONGINT;
  614. VAR prefix: IP.Adr);
  615. VAR
  616. flags: SET;
  617. i: LONGINT;
  618. BEGIN
  619. prefix.data := ORD(buffer.data[buffer.ofs + 2]);
  620. flags := SYSTEM.VAL(SET, buffer.data[buffer.ofs + 3]);
  621. onLink := 7 IN flags;
  622. autonomous := 6 IN flags;
  623. routerAddress := 5 IN flags;
  624. sitePrefix := 4 IN flags;
  625. validLifetime := Network.GetNet4(buffer.data, buffer.ofs + 4);
  626. preferredLifetime := Network.GetNet4(buffer.data, buffer.ofs + 8);
  627. sitePrefixLength := ORD(buffer.data[buffer.ofs + 15]);
  628. prefix.usedProtocol := IP.IPv6;
  629. FOR i := 0 TO 15 DO
  630. prefix.ipv6Adr[i] := buffer.data[buffer.ofs + 16 + i]
  631. END;
  632. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  633. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  634. END PrefixInfoOption;
  635. (* Reads ICMP redirect header option *)
  636. PROCEDURE RedirectHdrOption(VAR buffer: Network.Buffer);
  637. BEGIN
  638. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  639. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  640. END RedirectHdrOption;
  641. (* Reads ICMP MTU option *)
  642. PROCEDURE MTUOption(VAR buffer: Network.Buffer; VAR MTU: LONGINT);
  643. BEGIN
  644. MTU := Network.GetNet4(buffer.data, buffer.ofs + 4);
  645. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  646. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  647. END MTUOption;
  648. (* Reads ICMP advertisement interval option *)
  649. PROCEDURE AdvIntervalOption(VAR buffer: Network.Buffer);
  650. BEGIN
  651. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  652. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  653. END AdvIntervalOption;
  654. (* Reads ICMP home agent information option *)
  655. PROCEDURE HomeAgentInfoOption(VAR buffer: Network.Buffer);
  656. BEGIN
  657. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  658. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  659. END HomeAgentInfoOption;
  660. (* Reads ICMP route information option *)
  661. PROCEDURE RouteInfoOption(VAR buffer: Network.Buffer);
  662. BEGIN
  663. DEC(buffer.len, 8 * ORD(buffer.data[buffer.ofs + 1]));
  664. INC(buffer.ofs, 8 * ORD(buffer.data[buffer.ofs + 1])); (* Length field times 8 bytes*)
  665. END RouteInfoOption;
  666. PROCEDURE Cleanup;
  667. VAR
  668. res: WORD;
  669. BEGIN
  670. IPv6.sendNeighborSolicitation := NIL;
  671. IPv6.sendNeighborAdvertisement := NIL;
  672. IPv6.sendRouterSolicitation := NIL;
  673. IPv6.sendRouterAdvertisement := NIL;
  674. IPv6.icmpLinkLayerAdrOption := NIL;
  675. IPv6.icmpPrefixInfoOption := NIL;
  676. IPv6.icmpRedirectHdrOption := NIL;
  677. IPv6.icmpMTUOption := NIL;
  678. IPv6.icmpAdvIntervalOption := NIL;
  679. IPv6.icmpHomeAgentInfoOption := NIL;
  680. IPv6.icmpRouteInfoOption := NIL;
  681. (* Remove ICMP receivers *)
  682. RemoveReceiver(TypeEchoRequestv4, res);
  683. IF DEBUG THEN ASSERT (res = Ok) END;
  684. RemoveReceiver(TypeEchoRequestv6, res);
  685. IF DEBUG THEN ASSERT (res = Ok) END;
  686. RemoveReceiver(TypeNeighborSolicitation, res);
  687. IF DEBUG THEN ASSERT (res = Ok) END;
  688. RemoveReceiver(TypeNeighborAdvertisement, res);
  689. IF DEBUG THEN ASSERT (res = Ok) END;
  690. RemoveReceiver(TypeRouterAdvertisement, res);
  691. IF DEBUG THEN ASSERT (res = Ok) END;
  692. RemoveReceiver(TypeRouterSolicitation, res);
  693. IF DEBUG THEN ASSERT (res = Ok) END;
  694. RemoveReceiver(TypePacketTooBigv6, res);
  695. IF DEBUG THEN ASSERT (res = Ok) END;
  696. (* Remove IP receivers *)
  697. IP.RemoveReceiver(IPTypeICMPv4);
  698. IP.RemoveReceiver(IPTypeICMPv6);
  699. END Cleanup;
  700. PROCEDURE InitDelegates*;
  701. BEGIN
  702. (* set delegates in IPv6 *)
  703. IPv6.sendNeighborSolicitation := SendNeighborSolicitation;
  704. IPv6.sendNeighborAdvertisement := SendNeighborAdvertisement;
  705. IPv6.sendRouterAdvertisement := SendRouterAdvertisement;
  706. IPv6.sendRouterSolicitation := SendRouterSolicitation;
  707. IPv6.sendICMPv6TimeExceeded := SendICMPv6TimeExceeded;
  708. IPv6.sendICMPv6ParamProb := SendICMPv6ParamProb;
  709. IPv6.icmpLinkLayerAdrOption := LinkLayerAdrOption;
  710. IPv6.icmpPrefixInfoOption := PrefixInfoOption;
  711. IPv6.icmpRedirectHdrOption := RedirectHdrOption;
  712. IPv6.icmpMTUOption := MTUOption;
  713. IPv6.icmpAdvIntervalOption := AdvIntervalOption;
  714. IPv6.icmpHomeAgentInfoOption := HomeAgentInfoOption;
  715. IPv6.icmpRouteInfoOption := RouteInfoOption;
  716. END InitDelegates;
  717. BEGIN
  718. IF (IP.EchoReply) THEN
  719. (* install internal echoRequest receiver *)
  720. InstallReceiver(TypeEchoRequestv4, ReplyEcho, res);
  721. IF DEBUG THEN ASSERT (res = Ok) END;
  722. InstallReceiver(TypeEchoRequestv6, ReplyEcho, res);
  723. IF DEBUG THEN ASSERT (res = Ok) END;
  724. (* Install neighbor discovery reiceivers *)
  725. InstallReceiver(TypeNeighborSolicitation, ReceiveNeighborSolicitation, res);
  726. IF DEBUG THEN ASSERT (res = Ok) END;
  727. InstallReceiver(TypeNeighborAdvertisement, ReceiveNeighborAdvertisement, res);
  728. IF DEBUG THEN ASSERT (res = Ok) END;
  729. (* Router Advertisement *)
  730. InstallReceiver(TypeRouterAdvertisement, ReceiveRouterAdvertisement, res);
  731. IF DEBUG THEN ASSERT (res = Ok) END;
  732. (* Router Solicitation *)
  733. InstallReceiver(TypeRouterSolicitation, ReceiveRouterSolicitation, res);
  734. IF DEBUG THEN ASSERT (res = Ok) END;
  735. (* Packet too big *)
  736. InstallReceiver(TypePacketTooBigv6, ReceivePacketTooBig, res);
  737. IF DEBUG THEN ASSERT (res = Ok) END;
  738. END;
  739. IP.InstallReceiver(IPTypeICMPv4, Input);
  740. IP.InstallReceiver(IPTypeICMPv6, Input);
  741. Modules.InstallTermHandler(Cleanup);
  742. END ICMP.
  743. (*
  744. History:
  745. 21.10.2003 mvt Created and moved the ICMP impelementation from the IP module to this one.
  746. 26.10.2003 mvt Adapted to new design of IP.
  747. 02.05.2005 eb IPv6 (Neighbor Discovery / EchoRequest / EchoReply
  748. *)