IPv4.Mod 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE IPv4; (** AUTHOR "pjm, mvt"; PURPOSE "IPv4 and ARP protocols"; *)
  3. IMPORT SYSTEM, Machine, Kernel, Modules, Clock, KernelLog, Network, IP;
  4. CONST
  5. (* DEBUG *)
  6. DEBUG = TRUE;
  7. (* ARP *)
  8. ARPHdrLen = 8;
  9. ARPPktLen = 28;
  10. EtherTypeARP* = 806H;
  11. ARPMonitor = FALSE; (* monitor all ARP packets *)
  12. ARPHashSize = 256; (* size of ARP hash table *)
  13. MinARPTime = 1000; (* minimum time between ARP requests in ms *)
  14. (* IP *)
  15. EtherTypeIP* = 800H;
  16. MinIPHdrLen*= 20;
  17. MaxIPHdrLen* = 60;
  18. TOS = 10X; (* type-of-service on outgoing datagrams *)
  19. BroadcastAdr = LONGINT(0FFFFFFFFH);
  20. TYPE
  21. ARPEntry = POINTER TO RECORD
  22. next: ARPEntry;
  23. ip: IP.Adr;
  24. ether: Network.LinkAdr;
  25. sendTime, updateTime, updateDate: LONGINT;
  26. complete: BOOLEAN;
  27. buf: IP.Packet; (* buffer for a packet waiting to be sent, NIL if none *)
  28. END;
  29. TYPE
  30. Interface* = OBJECT(IP.Interface)
  31. VAR
  32. (* ARP hash table *)
  33. arpTable: ARRAY ARPHashSize OF ARPEntry;
  34. NARPEntries: LONGINT;
  35. (* The interface is trying to get an IP from a DHCP *)
  36. doingDHCPRequest*: BOOLEAN;
  37. (** Constructor - Open an IPv4 interface and add it to the IP configuration.
  38. "name" must be a unique name for this interface (tested in "AddInterface").
  39. "dev" must be a Network.LinkDevice that can be used in other interfaces => multiple IP addresses on the
  40. same interface. *)
  41. PROCEDURE &Constr*(name: IP.Name; dev: Network.LinkDevice; VAR res: WORD);
  42. VAR
  43. i: LONGINT;
  44. BEGIN
  45. ASSERT(dev # NIL);
  46. SELF.dev := dev;
  47. protocol := IP.IPv4;
  48. doingDHCPRequest := FALSE;
  49. (* set name *)
  50. IF name = "" THEN
  51. res := IP.NoInterfaceName;
  52. RETURN;
  53. END;
  54. COPY(name, SELF.name);
  55. (* init addresses *)
  56. localAdr := IP.NilAdr;
  57. maskAdr := IP.NilAdr;
  58. gatewayAdr := IP.NilAdr;
  59. subnetAdr := IP.NilAdr;
  60. broadAdr.usedProtocol := IP.IPv4;
  61. broadAdr.ipv4Adr := BroadcastAdr;
  62. (* init ARP *)
  63. FOR i := 0 TO ARPHashSize-1 DO
  64. arpTable[i] := NIL;
  65. END;
  66. NARPEntries := 0;
  67. (* init DNS *)
  68. DNScount := 0;
  69. closed := FALSE;
  70. IP.AddInterface(SELF, res);
  71. IF res = IP.Ok THEN
  72. (* install receivers *)
  73. dev.InstallReceiver(SELF, EtherTypeIP, IPInput, IsIPPacketValid, IsIPPacketForSingleInt, IsIPPacketAccepted, IP.IPForwarding); (* IPv4 *)
  74. dev.InstallReceiver(SELF, EtherTypeARP, ARPInput, IsARPPacketValid, IsARPPacketForSingleInt, IsARPPacketAccepted, FALSE); (* ARP *)
  75. ELSE
  76. closed := TRUE;
  77. END;
  78. END Constr;
  79. (** Close and deactivate the interface, i.e. remove it from the configuration. *)
  80. PROCEDURE Close*;
  81. BEGIN {EXCLUSIVE}
  82. ASSERT(~closed);
  83. closed := TRUE;
  84. (* remove receivers *)
  85. dev.RemoveReceiver(SELF, EtherTypeIP); (* IPv4 *)
  86. dev.RemoveReceiver(SELF, EtherTypeARP); (* ARP *)
  87. IP.RemoveInterface(SELF);
  88. END Close;
  89. (** Send an IP packet on this interface. *)
  90. PROCEDURE Send*(type: LONGINT; fip:IP. Adr; CONST l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, TTL: LONGINT);
  91. VAR
  92. l3hdr: ARRAY MaxIPHdrLen OF CHAR;
  93. BEGIN
  94. ASSERT (fip.usedProtocol = 4, 2345 );
  95. IF closed THEN RETURN END; (* just in case of concurrent Send/Close *)
  96. (* set IP header *)
  97. l3hdr[0] := CHR(IP.IPv4*10H + MinIPHdrLen DIV 4); (* IP version and header length *)
  98. l3hdr[1] := TOS; (* type-of-service *)
  99. Network.PutNet2(l3hdr, 2, MinIPHdrLen+h4len+dlen); (* total packet length *)
  100. Network.PutNet2(l3hdr, 4, GetNextID()); (* identification *)
  101. Network.Put2(l3hdr, 6, 0); (* fragmentation *)
  102. l3hdr[8] := CHR(TTL); (* time-to-live *)
  103. l3hdr[9] := CHR(type); (* IP type code *)
  104. Network.Put4(l3hdr, 12, localAdr.ipv4Adr); (* set local address *)
  105. Network.Put4(l3hdr, 16, fip.ipv4Adr); (* set foreign address *)
  106. Network.Put2(l3hdr, 10, 0); (* checksum := 0 *)
  107. IF ~(Network.ChecksumIP IN dev.calcChecksum) THEN
  108. Network.Put2(l3hdr, 10, IP.Checksum2(l3hdr, 0, MinIPHdrLen, 0)); (* calculate checksum *)
  109. END;
  110. (* perform sending *)
  111. DoSend(fip, l3hdr, l4hdr, data, MinIPHdrLen, h4len, dofs, dlen);
  112. END Send;
  113. (* Internal procedure to perform the rest of the send operation. Used by "Send" and for IP forwarding. *)
  114. PROCEDURE DoSend*(destAdr: IP.Adr; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT) ;
  115. VAR
  116. linkDst: Network.LinkAdr;
  117. BEGIN
  118. ASSERT (destAdr.usedProtocol = 4, 2345);
  119. IF h3len+h4len+dlen <= dev.mtu THEN
  120. IF dev.type = Network.TypeEthernet THEN
  121. IF IP.AdrsEqual (destAdr, localAdr) THEN
  122. (* send local loopback *)
  123. Machine.AtomicInc(IP.NIPSentLocalLoopback);
  124. dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, TRUE);
  125. ELSIF IsBroadcast(destAdr) (* (fip = broadAdr) OR OR (fip = BroadcastAdr) OR (fip = OldBroadcastAdr) *) THEN
  126. (* send broadcast *)
  127. Machine.AtomicInc(IP.NIPSentBroadcast);
  128. dev.Send(dev.broadcast, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
  129. ELSIF IsMulticast(destAdr) THEN
  130. (* Drop Multicast packet, NIY *)
  131. ELSE
  132. IF (~IP.IsNilAdr (gatewayAdr)) & ~SameSubnet(destAdr.ipv4Adr, subnetAdr.ipv4Adr, maskAdr.ipv4Adr) THEN
  133. Machine.AtomicInc(IP.NIPSentToGateway);
  134. destAdr := gatewayAdr;
  135. ELSE
  136. Machine.AtomicInc(IP.NIPSentToSubnet);
  137. END;
  138. IF ARPLookup(destAdr, linkDst) THEN
  139. dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
  140. ELSE
  141. ARPQueue(destAdr, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen);
  142. END;
  143. END;
  144. ELSE
  145. (* Network.TypePointToPoint *)
  146. Machine.AtomicInc(IP.NIPSentPointToPoint);
  147. dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, IP.AdrsEqual (destAdr, localAdr));
  148. END;
  149. ELSE
  150. Machine.AtomicInc(IP.NIPCantFragment);
  151. END;
  152. END DoSend;
  153. (* Receive an ARP packet *)
  154. PROCEDURE ARPInput* (dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
  155. VAR
  156. src, dst: IP.Adr;
  157. forus: BOOLEAN;
  158. BEGIN
  159. src := ARPReadSrcAdr (buffer);
  160. dst := ARPReadDestAdr (buffer);
  161. IF IP.AdrsEqual (src, localAdr) THEN
  162. (* duplicate source address! *)
  163. Machine.AtomicInc(NARPRcvDuplicate);
  164. KernelLog.Enter;
  165. KernelLog.String("IP: Address "); IP.OutAdr(src); KernelLog.String(" hijacked by ");
  166. Network.OutLinkAdr(SYSTEM.VAL(Network.LinkAdr, buffer.data[buffer.ofs+8]), dev.adrSize); KernelLog.Ln;
  167. KernelLog.Exit;
  168. ELSIF (buffer.data[buffer.ofs+7] = 1X) OR (buffer.data[buffer.ofs+7] = 2X) THEN
  169. (* request or reply *)
  170. IF ~ODD(LONG(ORD(buffer.data[buffer.ofs+8]))) & (~IP.IsNilAdr(src)) THEN
  171. forus := (IP.AdrsEqual(dst, localAdr));
  172. ARPEnter(src, SYSTEM.VAL(Network.LinkAdr, buffer.data[buffer.ofs+8]), forus);
  173. IF (buffer.data[buffer.ofs+7] = 1X) & forus THEN
  174. (* request for us *)
  175. ARPReply(buffer.data, buffer.ofs);
  176. END;
  177. ELSE
  178. (* nil IP address or non-unicast ethernet address supplied *)
  179. Machine.AtomicInc(NARPBadAddr)
  180. END
  181. ELSE
  182. Machine.AtomicInc(NARPRcvIgnored)
  183. END;
  184. (* Return the buffer *)
  185. Network.ReturnBuffer(buffer);
  186. END ARPInput;
  187. (* Receive an IP packet *)
  188. PROCEDURE IPInput(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
  189. VAR
  190. hlen: LONGINT;
  191. src, dst: IP.Adr;
  192. receiver: IP.Receiver;
  193. int: IP.Interface;
  194. BEGIN
  195. hlen := ORD(buffer.data[buffer.ofs]) MOD 10H * 4;
  196. src := ReadSrcAdr (buffer);
  197. dst := ReadDestAdr (buffer);
  198. IF ~IsBroadcast(src) & ~IsMulticast(src) THEN
  199. IF (IP.AdrsEqual (dst,localAdr)) OR IsBroadcast(dst) (* (dst = broadAdr) OR
  200. (dst = BroadcastAdr) OR (dst = OldBroadcastAdr) *) THEN
  201. (* packet is for us *)
  202. type := ORD(buffer.data[buffer.ofs+9]);
  203. receiver := IP.receivers[type];
  204. IF receiver # NIL THEN
  205. (* do receiver upcall *)
  206. buffer.l3ofs := buffer.ofs;
  207. INC(buffer.ofs, hlen);
  208. DEC(buffer.len, hlen);
  209. receiver(SELF, type, src, dst, buffer);
  210. Machine.AtomicInc(IP.NIPDelivered);
  211. (* Exit here w/o returning buffer because it is passed to a receiver *)
  212. RETURN;
  213. ELSE
  214. Machine.AtomicInc(IP.NIPNoReceiver);
  215. END;
  216. ELSIF IsMulticast(dst) THEN
  217. (* Drop multicast packet, NIY *)
  218. ELSIF IP.IPForwarding THEN
  219. int := IP.InterfaceByDstIP(dst);
  220. IF int # NIL THEN
  221. int.DoSend(dst, buffer.data, buffer.data, buffer.data, 0, 0, buffer.ofs, buffer.len);
  222. Machine.AtomicInc(IP.NIPForwarded)
  223. ELSE
  224. Machine.AtomicInc(IP.NIPNotForUs)
  225. END;
  226. ELSE
  227. Machine.AtomicInc(IP.NIPNotForUs)
  228. END
  229. ELSE
  230. Machine.AtomicInc(IP.NIPSrcIsBroadcast)
  231. END;
  232. (* Exit and return buffer here because it is no longer used *)
  233. Network.ReturnBuffer(buffer);
  234. END IPInput;
  235. (** Check if adr is a broadcast address *)
  236. PROCEDURE IsBroadcast*(adr: IP.Adr) : BOOLEAN;
  237. BEGIN
  238. ASSERT (adr.usedProtocol = 4, 2345);
  239. RETURN (adr.ipv4Adr = broadAdr.ipv4Adr) OR
  240. (adr.ipv4Adr = subnetAdr.ipv4Adr) OR (adr.ipv4Adr = BroadcastAdr)
  241. END IsBroadcast;
  242. (** Check if adr is a multicast address *)
  243. PROCEDURE IsMulticast*(adr: IP.Adr) : BOOLEAN;
  244. VAR
  245. arr: ARRAY 4 OF CHAR;
  246. BEGIN
  247. ASSERT (adr.usedProtocol = 4, 2345);
  248. IP.AdrToArray(adr, arr, 0, FALSE);
  249. RETURN (ORD(arr[0]) >= 224) & (ORD(arr[0]) < 240)
  250. END IsMulticast;
  251. (** Performs a check for Network if a packet is accepted by this interface *)
  252. PROCEDURE IsIPPacketAccepted(buffer: Network.Buffer): BOOLEAN;
  253. VAR
  254. dstAdr: LONGINT;
  255. interface: IP.Interface;
  256. accept: BOOLEAN;
  257. BEGIN
  258. dstAdr := Network.Get4(buffer.data, buffer.ofs+16);
  259. IF IP.IsNilAdr(localAdr) THEN
  260. IF doingDHCPRequest THEN
  261. (* Check if there are other interface waiting for this packet if not take it could be DHCP *)
  262. interface := IP.interfaces;
  263. WHILE (interface # NIL) & (interface.localAdr.ipv4Adr # dstAdr) DO
  264. interface := interface.next;
  265. END;
  266. IF interface # NIL THEN
  267. accept := FALSE;
  268. ELSE
  269. accept := TRUE;
  270. END;
  271. ELSE
  272. (* An interface with no IP does not take packets *)
  273. accept := FALSE;
  274. END;
  275. ELSE
  276. accept := dstAdr = localAdr.ipv4Adr;
  277. END;
  278. RETURN accept;
  279. END IsIPPacketAccepted;
  280. (** Set addresses. Is normally called just after instanciation, but can also be called later, e.g. by DHCP.
  281. If "gatewayAdr" is "NilAdr", the subnet is considered to have no gateway, else it must be in the same
  282. subnet as the "localAdr".
  283. "domain" can be an empty string. It is normally used by a DNS implementation. It is not used in IP directly. *)
  284. PROCEDURE SetAdrs*(localAdr, maskAdr, gatewayAdr: IP.Adr; VAR res: WORD);
  285. VAR
  286. maskSet: SET;
  287. BEGIN {EXCLUSIVE}
  288. IF DEBUG THEN
  289. ASSERT ((IP.IsNilAdr(localAdr)) OR (localAdr.usedProtocol = 4), 2345);
  290. ASSERT ((IP.IsNilAdr(maskAdr)) OR (maskAdr.usedProtocol = 4), 2345);
  291. ASSERT ((IP.IsNilAdr(gatewayAdr)) OR (gatewayAdr.usedProtocol = 4), 2345);
  292. END;
  293. IF ~IP.IsNilAdr (localAdr) THEN
  294. (* Check, if all IPv6 or all IPv4 *)
  295. IF ((localAdr.usedProtocol # maskAdr.usedProtocol) OR
  296. ((~IP.IsNilAdr (gatewayAdr)) & (localAdr.usedProtocol # gatewayAdr.usedProtocol))) THEN
  297. res := IP.MixedIpProtocols;
  298. RETURN;
  299. END;
  300. (* Check if addresses are of same protocol as interface *)
  301. IF localAdr.usedProtocol # IP.IPv4 THEN
  302. res := IP.IPv6AdrUsedOnIPv4Interface;
  303. RETURN;
  304. END;
  305. END;
  306. (* set addresses *)
  307. SELF.localAdr := localAdr;
  308. SELF.maskAdr := maskAdr;
  309. SELF.gatewayAdr := gatewayAdr;
  310. (* compute other addresses *)
  311. maskSet := SYSTEM.VAL(SET, maskAdr.ipv4Adr);
  312. subnetAdr.usedProtocol := IP.IPv4;
  313. subnetAdr.ipv4Adr := SYSTEM.VAL (LONGINT, SYSTEM.VAL (SET, localAdr.ipv4Adr) * maskSet);
  314. broadAdr.usedProtocol := IP.IPv4;
  315. broadAdr.ipv4Adr := SYSTEM.VAL (LONGINT, SYSTEM.VAL (SET, subnetAdr.ipv4Adr) + (-maskSet));
  316. IF (~IP.IsNilAdr (gatewayAdr)) &
  317. ( ~SameSubnet(gatewayAdr.ipv4Adr, localAdr.ipv4Adr, maskAdr.ipv4Adr)) THEN
  318. res := IP.GatewayNotInSubnet;
  319. ELSE
  320. res := IP.Ok;
  321. END;
  322. END SetAdrs;
  323. (* Reads the source address of a IPv4 packet buffer *)
  324. PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): IP.Adr;
  325. VAR
  326. adr: IP.Adr;
  327. BEGIN
  328. adr.usedProtocol := IP.IPv4;
  329. adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+12);
  330. RETURN adr;
  331. END ReadSrcAdr;
  332. (* Reads the destination address of a IPv4 packet buffer *)
  333. PROCEDURE ReadDestAdr* (buffer: Network.Buffer): IP.Adr;
  334. VAR
  335. adr: IP.Adr;
  336. BEGIN
  337. adr.usedProtocol := IP.IPv4;
  338. adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+16);
  339. RETURN adr;
  340. END ReadDestAdr;
  341. (** Creates a pseudo-header for checksum calculation (TCP/UDP) and returns the length of this header *)
  342. PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR; src, dst: IP.Adr; protocol, pktLengthUpperLayer: LONGINT): LONGINT;
  343. BEGIN
  344. (* UDP/TCP Pseudo-header (for checksum calculation)
  345. 00 32 source address
  346. 04 32 destination address
  347. 08 08 zero = 0
  348. 09 08 protocol = 17
  349. 10 16 UDP/TCP length *)
  350. Network.Put4(pseudoHdr, 0, src.ipv4Adr); (* local IP address *)
  351. Network.Put4(pseudoHdr, 4, dst.ipv4Adr); (* foreign IP address *)
  352. Network.PutNet2(pseudoHdr, 8, protocol); (* IP type code of UDP/TCP*)
  353. Network.PutNet2(pseudoHdr, 10, pktLengthUpperLayer); (* UPD/TCP length *)
  354. RETURN 12; (* IPv4 pseudo header length *)
  355. END WritePseudoHeader;
  356. (* Reads the source address of a ARP packet buffer *)
  357. PROCEDURE ARPReadSrcAdr* (buffer: Network.Buffer): IP.Adr;
  358. VAR
  359. adr: IP.Adr;
  360. BEGIN
  361. adr.usedProtocol := IP.IPv4;
  362. adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+14);
  363. RETURN adr;
  364. END ARPReadSrcAdr;
  365. (* Reads the destination address of a ARP packet buffer *)
  366. PROCEDURE ARPReadDestAdr* (buffer: Network.Buffer): IP.Adr;
  367. VAR
  368. adr: IP.Adr;
  369. BEGIN
  370. adr.usedProtocol := IP.IPv4;
  371. adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+24);
  372. RETURN adr;
  373. END ARPReadDestAdr;
  374. (** Enumerate all ARP table entries. *)
  375. PROCEDURE ARPEnumerate*(handle: IP.ARPHandler);
  376. VAR
  377. p: ARPEntry;
  378. i: LONGINT;
  379. BEGIN
  380. FOR i := 0 TO ARPHashSize-1 DO
  381. p := arpTable[i];
  382. WHILE p # NIL DO
  383. handle(p.ip, p.complete, p.ether, 6, p.sendTime, p.updateTime, p.updateDate, i);
  384. p := p.next
  385. END
  386. END
  387. END ARPEnumerate;
  388. (* Update or add an ARP entry. *)
  389. PROCEDURE ARPEnter(ip:IP. Adr; ether: Network.LinkAdr; forus: BOOLEAN);
  390. VAR
  391. p, q: ARPEntry;
  392. n: LONGINT;
  393. (* Create a new entry at the front of the hash list *)
  394. PROCEDURE NewEntry;
  395. BEGIN
  396. NEW(p);
  397. p.ip := ip;
  398. p.buf := NIL;
  399. p.sendTime := Kernel.GetTicks() - minARPTime;
  400. p.complete := FALSE;
  401. p.next := arpTable[n];
  402. arpTable[n] := p;
  403. Machine.AtomicInc(NARPEntries);
  404. END NewEntry;
  405. BEGIN {EXCLUSIVE}
  406. ASSERT (ip.usedProtocol = 4, 2345);
  407. n := ARPHash(ip.ipv4Adr);
  408. p := arpTable[n];
  409. WHILE (p # NIL) & (~IP.AdrsEqual(p.ip,ip)) DO
  410. p := p.next;
  411. END;
  412. IF (p = NIL) & (ARPMonitor OR forus) THEN
  413. NewEntry();
  414. END;
  415. IF p # NIL THEN (* update address *)
  416. IF ARPMonitor & p.complete & ~Network.Equal(ether, p.ether, 0, 0, 6) THEN
  417. (* mapping changed! *)
  418. q := p.next;
  419. WHILE (q # NIL) & (~Network.Equal(ether, q.ether, 0, 0, 6) OR ~IP.AdrsEqual(q.ip, ip)) DO
  420. q := q.next
  421. END;
  422. IF q # NIL THEN (* we had this changed mapping before *)
  423. p := q; (* update it *)
  424. ELSE
  425. (* insert new mapping at front *)
  426. KernelLog.Enter;
  427. KernelLog.String("IP: Address for "); IP.OutAdr(p.ip);
  428. KernelLog.String(" changed from "); Network.OutLinkAdr(p.ether, 6);
  429. KernelLog.String(" to "); Network.OutLinkAdr(ether, 6);
  430. KernelLog.Exit;
  431. NewEntry();
  432. END;
  433. END;
  434. (* send queued packet *)
  435. IF p.buf # NIL THEN
  436. dev.Send(ether, EtherTypeIP, p.buf^, p.buf^, p.buf^, 0, 0, 0, LEN(p.buf^), FALSE);
  437. p.buf := NIL; (* 26.02.04 : fixes the resend bug *)
  438. END;
  439. (* update entry *)
  440. p.ether := ether;
  441. p.complete := TRUE;
  442. Clock.Get(p.updateTime, p.updateDate);
  443. END
  444. END ARPEnter;
  445. (* Send an ARP reply. Assume arp/ofs contains a valid ARP request packet. *)
  446. PROCEDURE ARPReply(VAR arp: ARRAY OF CHAR; ofs: LONGINT);
  447. BEGIN
  448. Machine.AtomicInc(NARPReply);
  449. arp[ofs+7] := 2X; (* reply operation *)
  450. Network.Copy(arp, arp, ofs+8, ofs+18, 6+4); (* target := sender *)
  451. Network.Copy(dev.local, arp, 0, ofs+8, 6); (* sender ethernet address *)
  452. Network.Put4(arp, ofs+14, localAdr.ipv4Adr); (* sender ip address *)
  453. dev.Send(SYSTEM.VAL(Network.LinkAdr, arp[ofs + 18]), EtherTypeARP, arp, arp, arp, 0, 0, ofs, ARPPktLen, FALSE);
  454. END ARPReply;
  455. (* Look for the ethernet address matching the specified ip address. *)
  456. PROCEDURE ARPLookup(ip: IP.Adr; VAR ether: Network.LinkAdr): BOOLEAN;
  457. VAR p: ARPEntry; c: BOOLEAN;
  458. BEGIN
  459. ASSERT (ip.usedProtocol = 4, 2345);
  460. p := arpTable[ARPHash(ip.ipv4Adr)];
  461. LOOP
  462. IF p = NIL THEN RETURN FALSE END;
  463. IF IP.AdrsEqual (p.ip, ip) THEN
  464. c := p.complete; (* to allow concurrent "Enter" *)
  465. ether := p.ether;
  466. RETURN c;
  467. END;
  468. p := p.next
  469. END
  470. END ARPLookup;
  471. (* Queue an IP packet awaiting an ARP reply. *)
  472. PROCEDURE ARPQueue(dst: IP.Adr; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
  473. VAR p: ARPEntry; n: LONGINT;
  474. BEGIN {EXCLUSIVE}
  475. ASSERT (dst.usedProtocol = 4, 2345);
  476. Machine.AtomicInc(NARPPut);
  477. n := ARPHash(dst.ipv4Adr);
  478. p := arpTable[n];
  479. WHILE (p # NIL) & (~IP.AdrsEqual (p.ip, dst)) DO
  480. p := p.next
  481. END;
  482. IF p = NIL THEN
  483. (* not found, create a new incomplete entry *)
  484. NEW(p);
  485. p.complete := FALSE;
  486. p.ip := dst;
  487. p.sendTime := Kernel.GetTicks() - minARPTime;
  488. (* store one packet with the incomplete entry *)
  489. NEW(p.buf, h3len+h4len+dlen);
  490. Network.Copy(l3hdr, p.buf^, 0, 0, h3len);
  491. Network.Copy(l4hdr, p.buf^, 0, h3len, h4len);
  492. Network.Copy(data, p.buf^, dofs, h3len+h4len, dlen);
  493. (* publish the incomplete entry *)
  494. p.next := arpTable[n];
  495. arpTable[n] := p;
  496. Machine.AtomicInc(NARPEntries);
  497. END;
  498. IF p.complete THEN
  499. (* address arrived in the mean-time, so send the packet *)
  500. dev.Send(p.ether, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
  501. ELSE
  502. (* (re-)send ARP request *)
  503. IF Kernel.GetTicks() - p.sendTime >= minARPTime THEN
  504. ARPRequest(dst);
  505. p.sendTime := Kernel.GetTicks();
  506. ELSE
  507. Machine.AtomicInc(NARPSkipped);
  508. END
  509. END
  510. END ARPQueue;
  511. (* Send an ARP request *)
  512. PROCEDURE ARPRequest(ip: IP.Adr);
  513. VAR
  514. i: LONGINT;
  515. arp: ARRAY ARPPktLen OF CHAR;
  516. BEGIN
  517. ASSERT (ip.usedProtocol = 4, 2345);
  518. Machine.AtomicInc(NARPRequest);
  519. Network.Copy(arpProto, arp, 0, 0, ARPHdrLen);
  520. arp[7] := 1X; (* request operation *)
  521. Network.Copy(dev.local, arp, 0, 8, 6); (* sender ethernet address *)
  522. Network.Put4(arp, 14, localAdr.ipv4Adr); (* sender ip address *)
  523. (* target ethernet address *)
  524. FOR i:= 18 TO 23 DO
  525. arp[i] := 0X;
  526. END;
  527. Network.Put4(arp, 24, ip.ipv4Adr); (* target ip address *)
  528. dev.Send(dev.broadcast, EtherTypeARP, arp, arp, arp, 0, 0, 0, ARPPktLen, FALSE);
  529. END ARPRequest;
  530. (** Writes the configuration of this interface *)
  531. PROCEDURE OutInterface*;
  532. VAR i: LONGINT;
  533. str : ARRAY 32 OF CHAR;
  534. BEGIN
  535. IF closed THEN
  536. KernelLog.Enter;
  537. KernelLog.String("IP.OutInterface: Error: Interface already closed!"); KernelLog.Ln;
  538. KernelLog.Exit;
  539. ELSE
  540. KernelLog.Enter; KernelLog.Ln;
  541. KernelLog.String("=== Interface ==="); KernelLog.Ln;
  542. KernelLog.String("Interface name: "); KernelLog.String(name); KernelLog.Ln;
  543. KernelLog.String("Attached device: "); KernelLog.String(dev.name);
  544. IF dev.Linked() = Network.LinkLinked THEN
  545. KernelLog.String(" (LinkLinked)"); KernelLog.Ln;
  546. ELSIF dev.Linked() = Network.LinkNotLinked THEN
  547. KernelLog.String(" (LinkNotLinked)"); KernelLog.Ln;
  548. ELSE
  549. KernelLog.String(" (LinkUnknown)"); KernelLog.Ln;
  550. END;
  551. Network.LinkAdrToStr(dev.local, 8, str);
  552. KernelLog.String("MAC address: "); KernelLog.String(str); KernelLog.Ln;
  553. KernelLog.String("Local address: "); IP.OutAdr(localAdr); KernelLog.Ln;
  554. KernelLog.String("Netmask: "); IP.OutAdr(maskAdr); KernelLog.Ln;
  555. KernelLog.String("Gateway address: "); IP.OutAdr(gatewayAdr); KernelLog.Ln;
  556. KernelLog.String("Subnet: "); IP.OutAdr(subnetAdr); KernelLog.Ln;
  557. KernelLog.String("Net broadcast: "); IP.OutAdr(broadAdr); KernelLog.Ln;
  558. IF DNScount > 0 THEN
  559. FOR i:= 0 TO DNScount-1 DO
  560. KernelLog.String("DNS server: "); IP.OutAdr(DNS[i]); KernelLog.Ln;
  561. END;
  562. ELSE
  563. KernelLog.String("DNS server: none"); KernelLog.Ln;
  564. END;
  565. KernelLog.Exit;
  566. END;
  567. END OutInterface;
  568. END Interface;
  569. VAR
  570. (* Module variables *)
  571. nextID: INTEGER;
  572. (* ARP *)
  573. arpProto: ARRAY ARPHdrLen OF CHAR;
  574. minARPTime: LONGINT; (* minimum time between ARP requests in ticks *)
  575. (* ARP counters *)
  576. NARPPut-, NARPRcvTotal-, NARPRcvTooSmall-, NARPRcvIgnored-, NARPRcvDuplicate-, NARPBadAddr-,
  577. NARPRequest-, NARPReply-, NARPSkipped-: LONGINT;
  578. (* Return TRUE if "adr1" and "adr2" are in the same subnet defined by "mask". *)
  579. PROCEDURE SameSubnet(adr1, adr2, mask: LONGINT): BOOLEAN;
  580. CODE
  581. #IF I386 THEN
  582. MOV EAX, [EBP + adr1]
  583. MOV EBX, [EBP + adr2]
  584. MOV ECX, [EBP + mask]
  585. AND EAX, ECX
  586. AND EBX, ECX
  587. CMP EAX, EBX
  588. SETE AL
  589. #ELSIF AMD64 THEN
  590. MOV EAX, [RBP + adr1]
  591. MOV EBX, [RBP + adr2]
  592. MOV ECX, [RBP + mask]
  593. AND EAX, ECX
  594. AND EBX, ECX
  595. CMP EAX, EBX
  596. SETE AL
  597. #ELSIF ARM THEN
  598. LDR R0, [FP, #adr1]
  599. LDR R1, [FP, #adr2]
  600. LDR R2, [FP, #mask]
  601. AND R0, R0, R2
  602. AND R1, R1, R2
  603. CMP R0, R1
  604. MOVEQ R0, #1
  605. MOVNE R0, #0
  606. #ELSE
  607. unimplemented
  608. #END
  609. END SameSubnet;
  610. (* Inline hash function for ARP hash table *)
  611. PROCEDURE ARPHash(ip: LONGINT): LONGINT;
  612. CODE
  613. #IF I386 THEN
  614. MOV EAX, [EBP + ip]
  615. XCHG AL, AH
  616. ROL EAX, 16
  617. XCHG AL, AH
  618. MOV EBX, ARPHashSize
  619. XOR EDX, EDX
  620. DIV EBX
  621. MOV EAX, EDX
  622. #ELSIF AMD64 THEN
  623. MOV EAX, [RBP + ip]
  624. BSWAP EAX
  625. MOV EBX, ARPHashSize
  626. XOR EDX, EDX
  627. DIV EBX
  628. MOV EAX, EDX
  629. #ELSIF ARM THEN
  630. LDR R0, [SP, #ip]
  631. MOV R1, #ARPHashSize-1
  632. AND R0, R0, R1
  633. #ELSE
  634. unimplemented
  635. #END
  636. END ARPHash;
  637. (** Performs a check for Network if a packet is only for a single interface. Every ARP packet should go to every interface*)
  638. PROCEDURE IsARPPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
  639. BEGIN
  640. RETURN FALSE;
  641. END IsARPPacketForSingleInt;
  642. (** Performs a check for Network if a packet is for a single interface *)
  643. PROCEDURE IsIPPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
  644. BEGIN
  645. RETURN ~(buffer.data[buffer.ofs+19] = 0FFX);
  646. END IsIPPacketForSingleInt;
  647. (** Performs a check for Network if a packet is accepted by this interface. Every ARP packet is accepted *)
  648. PROCEDURE IsARPPacketAccepted(buffer: Network.Buffer): BOOLEAN;
  649. BEGIN
  650. RETURN TRUE;
  651. END IsARPPacketAccepted;
  652. (** Checks if an IPv4 packet is valid *)
  653. PROCEDURE IsIPPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
  654. VAR
  655. isValid: BOOLEAN;
  656. hlen, tlen, frag: LONGINT;
  657. BEGIN
  658. isValid := FALSE;
  659. Machine.AtomicInc(IP.NIPRcvTotal);
  660. IF buffer.len >= MinIPHdrLen THEN
  661. IF LSH(ORD(buffer.data[buffer.ofs]), -4) = IP.IPv4 THEN
  662. hlen := ORD(buffer.data[buffer.ofs]) MOD 10H * 4;
  663. IF (hlen >= MinIPHdrLen) & (hlen <= MaxIPHdrLen) THEN
  664. IF (Network.ChecksumIP IN buffer.calcChecksum) OR (IP.Checksum2(buffer.data, buffer.ofs, hlen, 0) = 0) THEN
  665. tlen := Network.GetNet2(buffer.data, buffer.ofs+2);
  666. IF (tlen >= hlen) & (tlen <= buffer.len) THEN
  667. IF tlen < buffer.len THEN
  668. (* size not used *)
  669. Machine.AtomicInc(IP.NIPTrim);
  670. buffer.len := tlen;
  671. END;
  672. frag := Network.GetNet2(buffer.data, buffer.ofs+6);
  673. IF (frag = 0) OR (frag = 4000H) THEN (* not a fragment *)
  674. IF hlen # MinIPHdrLen THEN
  675. (* process options here *)
  676. Machine.AtomicInc(IP.NIPOptions);
  677. END;
  678. isValid := TRUE;
  679. ELSE
  680. Machine.AtomicInc(IP.NIPCantReassemble)
  681. END
  682. ELSE
  683. Machine.AtomicInc(IP.NIPBadLength)
  684. END
  685. ELSE
  686. Machine.AtomicInc(IP.NIPBadChecksum)
  687. END
  688. ELSE
  689. Machine.AtomicInc(IP.NIPBadHdrLen)
  690. END
  691. ELSE
  692. Machine.AtomicInc(IP.NIPBadVersion)
  693. END
  694. ELSE
  695. Machine.AtomicInc(IP.NIPTooSmall)
  696. END;
  697. RETURN isValid;
  698. END IsIPPacketValid;
  699. (** Checks if an ARP packet is valid *)
  700. PROCEDURE IsARPPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
  701. VAR
  702. isValid: BOOLEAN;
  703. BEGIN
  704. isValid := FALSE;
  705. Machine.AtomicInc(NARPRcvTotal);
  706. IF buffer.len >= ARPPktLen THEN
  707. IF Network.Equal(buffer.data, arpProto, buffer.ofs, 0, ARPHdrLen-1) THEN
  708. isValid := TRUE;
  709. ELSE
  710. Machine.AtomicInc(NARPRcvIgnored)
  711. END
  712. ELSE
  713. Machine.AtomicInc(NARPRcvTooSmall)
  714. END;
  715. RETURN isValid;
  716. END IsARPPacketValid;
  717. (* Return a unique datagram ID *)
  718. PROCEDURE GetNextID*(): INTEGER;
  719. BEGIN {EXCLUSIVE}
  720. INC(nextID);
  721. RETURN nextID;
  722. END GetNextID;
  723. PROCEDURE Cleanup;
  724. BEGIN
  725. (* Remove all interfaces *)
  726. WHILE IP.interfaces # NIL DO
  727. IP.interfaces.Close();
  728. END;
  729. END Cleanup;
  730. BEGIN
  731. (* intializations *)
  732. nextID := 0;
  733. (* Init ARP variables *)
  734. minARPTime := MinARPTime * Kernel.second DIV 1000;
  735. arpProto[0] := 0X; arpProto[1] := 1X; (* hardware type ethernet *)
  736. arpProto[2] := CHR(EtherTypeIP DIV 100H); (* protocol type IP *)
  737. arpProto[3] := CHR(EtherTypeIP MOD 100H);
  738. arpProto[4] := 6X; arpProto[5] := 4X; (* lengths *)
  739. arpProto[6] := 0X; arpProto[7] := 0X; (* no operation *)
  740. Modules.InstallTermHandler(Cleanup);
  741. END IPv4.
  742. Free:
  743. System.Free TraceRoute VNC Ping WMFTPClient FTPClient WebFTPServer TCPServices TLS InitNetwork Ping DHCP TCP DNS UDP ICMP IPv4 IPv6 IP~
  744. Start:
  745. InitNetwork.Init
  746. Compile:
  747. PC.Compile \s IP.Mod IPv4.Mod IPv6.Mod ICMP.Mod UDP.Mod DNS.Mod TCP.Mod DHCP.Mod InitNetwork.Mod WebFTPServer.Mod FTPClient.Mod WMFTPClient.Mod Ping.Mod VNC.Mod TraceRoute.Mod~
  748. History:
  749. 02.05.2005 eb Created.