ARM.IPv4.Mod 25 KB

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