EnetBase.Mod 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. MODULE EnetBase;
  2. (**
  3. AUTHOR: Alexey Morozov, HighDim GmbH, 2015
  4. PURPOSE: Ethernet networking stack
  5. *)
  6. IMPORT
  7. S := SYSTEM, EnetEnvironment, EnetUtils, Trace := EnetTrace, EnetTiming;
  8. TYPE
  9. Int8* = SHORTINT;
  10. Int16* = INTEGER;
  11. Int32* = LONGINT;
  12. Int* = LONGINT; (** system signed integer type *)
  13. UInt* = ADDRESS; (** system unsigned integer type *)
  14. UnalignedInt32 = EnetUtils.UnalignedInt32;
  15. CONST
  16. ThreadSafe* = FALSE; (** set to TRUE to enable thread safety features *)
  17. LittleEndianSystem* = TRUE; (** TRUE if the system has little endian data ordering *)
  18. (** Link speed values in Mbps *)
  19. LinkSpeedAuto* = "Auto";
  20. Mbps10* = "10";
  21. Mbps100* = "100";
  22. Mbps1000* = "1000";
  23. MaxNumEthFrameHandlers* = 32; (** maximal number of plugable custom Ethernet frame handlers *)
  24. (** Basic Ethernet frame types *)
  25. EtherTypeIpv4* = 0x0008;
  26. EtherTypeIpv6* = 0xDD86;
  27. EtherTypeArp* = 0x0608;
  28. (**
  29. Protocols on top of IP (Level 3)
  30. *)
  31. ProtoIcmp* = 0x01; (** ICMP *)
  32. ProtoTcp* = 0x06; (** TCP *)
  33. ProtoUdp* = 0x11; (** UDP *)
  34. (**
  35. IP-specific constants
  36. *)
  37. IpDiffServ* = 0; (* default value of "Differentiated Services" field in an IP packet *)
  38. IpEcn* = 0; (** default value of "Explicit Congestion Notification" field in an IP packet *)
  39. IpTtl* = 255; (** time to live for an IP packet *)
  40. (**
  41. Packet sending flags
  42. *)
  43. FlagNoDataCopy* = 0; (** do not copy user-provided data for sending a packet, the data will be used by reference; use completion handlers to assure that the data is not referenced anymore *)
  44. FlagNoFlushDCache* = 1; (** avoid flushing data cache for the user-provided data (used for platforms with explicit cache manipulation e.g. ARM) *)
  45. (**
  46. Packet handling flags
  47. *)
  48. FlagIpv6* = 0; (** passed to the IP packet handler to indicate IP version 6 *)
  49. (**
  50. Error codes
  51. *)
  52. OpInProgress* = -1; (** operation is still in progress *)
  53. ErrInvalidValue* = 1; (** a parameter has invalid value *)
  54. ErrTimeoutExpired* = 2; (** timeout has expired *)
  55. ErrCannotDoWhenActive* = 3; (** operation cannot be performed when the interface/device is active *)
  56. ErrNotActive* = 4; (** operation cannot be performed when the interface/device is not active *)
  57. ErrNoIntfFound* = 5; (** no interface found to perform a given operation *)
  58. ErrUnresolvedAddr* = 6; (** address not resolved error *)
  59. ErrOutOfResources* = 7; (** out of resources *)
  60. ErrOutOfBounds* = 8; (** out of bounds *)
  61. ErrAlreadyExists* = 9; (** an object already exists *)
  62. (**
  63. PHY-specific error codes
  64. *)
  65. ErrMdioBusy* = 10; (** MDIO interface is busy *)
  66. ErrPhyNotDetected* = 11; (** PHY device is not detected *)
  67. ErrSpeedAutonegoFailure* = 12; (** a failure to autonegotiate the link speed *)
  68. (**
  69. Link device specific error codes
  70. *)
  71. ErrRxPacketPoolEmpty* = 13; (** RX packet pool got empty *)
  72. ErrRxPacketPoolFull* = 14; (** RX packet pool got full *)
  73. ErrRecvPacketFifoFull* = 15; (** received packet FIFO got full *)
  74. ErrTxPacketPoolEmpty* = 16; (** TX packet pool got empty *)
  75. EnableTrace * = FALSE;
  76. TYPE
  77. (**
  78. MAC address
  79. *)
  80. MacAddr* = RECORD
  81. addr*: ARRAY 6 OF Int8;
  82. END;
  83. IpAddr* = RECORD
  84. addr*: ARRAY 4 OF Int32;
  85. ver*: Int8;
  86. END;
  87. (** Ethernet frame header (14 bytes) *)
  88. EthFrameHdr* = RECORD
  89. dstMacAddr*: MacAddr; (** destination MAC address *)
  90. srcMacAddr*: MacAddr; (** source MAC address *)
  91. etherType*{ALIGNED(1)}: Int16; (** type of the Ethernet frame; value >= 1536 corresponds to a Ethernet II frame *)
  92. END;
  93. (**
  94. IP version 4 packet header (20 bytes)
  95. *)
  96. Ipv4Hdr* = RECORD
  97. verAndIhl*: Int8; (** 4-bit version field (4 for For IPv4) and 4-bit value of Internet Header Length (IHL) *)
  98. dscpAndEcn*: Int8; (** 6-bit Differentiated Services Code Point (DSCP) and 2-bit Explicit Congestion Notification (ECN) *)
  99. length*{ALIGNED(1)}: Int16; (** 16-bit size of the entire packet (fragment), including header and data, in bytes *)
  100. fragmentId*{ALIGNED(1)}: Int16; (** identification field and is primarily used for uniquely identifying the group of fragments of a single IP datagram *)
  101. flagsAndFragmentOffs*{ALIGNED(1)}: Int16; (** 3-bit flags field used to control or identify fragments and 13-bit fragment offset field, measured in units of eight-byte blocks (64 bits), and specifies the offset of a particular fragment relative to the beginning of the original unfragmented IP datagram *)
  102. ttl*: Int8; (** Time To Live (TTL) *)
  103. protocol*: Int8; (** defines the protocol used in the data portion of the IP datagram *)
  104. checksum*{ALIGNED(1)}: Int16; (** header checksum *)
  105. srcIpAddr*{ALIGNED(1)}: UnalignedInt32; (** source IPv4 address *)
  106. dstIpAddr*{ALIGNED(1)}: UnalignedInt32; (** destination IPv4 address *)
  107. END;
  108. (**
  109. IP version 6 packet header (XY bytes)
  110. *)
  111. Ipv6Hdr* = RECORD
  112. protocol*: Int8; (** defines the protocol used in the data portion of the IP datagram *)
  113. srcIpAddr*{ALIGNED(1)}: ARRAY 4 OF UnalignedInt32; (** source IPv6 address *)
  114. dstIpAddr*{ALIGNED(1)}: ARRAY 4 OF UnalignedInt32; (** destination IPv6 address *)
  115. END;
  116. (**
  117. Address Resolution Protocol (ARP) packet header (28 bytes)
  118. *)
  119. ArpHdr* = RECORD
  120. hwType*{ALIGNED(1)}: Int16;
  121. protoType*{ALIGNED(1)}: Int16;
  122. hwAddrLen*: Int8;
  123. protoAddrLen*: Int8;
  124. operation*{ALIGNED(1)}: Int16;
  125. srcMacAddr*: MacAddr;
  126. srcIpAddr*{ALIGNED(1)}: UnalignedInt32;
  127. dstMacAddr*: MacAddr;
  128. dstIpAddr*{ALIGNED(1)}: UnalignedInt32;
  129. END;
  130. (**
  131. Internet Control Message Protocol (ICMP) packet basic part of the header (4 bytes)
  132. *)
  133. IcmpHdr0* = RECORD
  134. type*: Int8; (** message type *)
  135. code*: Int8; (** message subtype *)
  136. checksum*{ALIGNED(1)}: Int16; (** checksum computed from the header and data *)
  137. END;
  138. (**
  139. ICMP header (8 bytes)
  140. *)
  141. IcmpHdr* = RECORD(IcmpHdr0)
  142. restOfHdr*{ALIGNED(1)}: UnalignedInt32; (** rest of the header (content depends on the value of "type" field) *)
  143. END;
  144. (**
  145. ICMP echo request/reply header
  146. *)
  147. IcmpEchoHdr* = RECORD(IcmpHdr0)
  148. id*{ALIGNED(1)}: Int16; (** echo message identifier *)
  149. seq*{ALIGNED(1)}: Int16; (** echo message sequence number *)
  150. END;
  151. (**
  152. User Datagram Protocol header (8 bytes)
  153. *)
  154. UdpHdr* = RECORD
  155. srcPort*{ALIGNED(1)}: Int16; (** sender's port number when meaningful and should be assumed to be the port to reply to if needed *)
  156. dstPort*{ALIGNED(1)}: Int16; (** receiver's port number *)
  157. length*{ALIGNED(1)}: Int16; (** length of the UDP header and UDP data, in bytes *)
  158. checksum*{ALIGNED(1)}: Int16; (** checksum computed from the header and data *)
  159. END;
  160. (** Transmit Control Protocol header (XY bytes) *)
  161. TcpHdr* = RECORD
  162. END;
  163. (**
  164. Network packet
  165. *)
  166. Packet* = POINTER TO PacketDesc;
  167. PacketDesc* = RECORD
  168. data*: POINTER TO ARRAY OF CHAR; (** packet data *)
  169. dataOffs*: Int; (** data array offset (set up by the corresponding link device) *)
  170. dataLen*: Int; (** packet data length in bytes *)
  171. (* Level 2 *)
  172. ethFrameHdr*: POINTER{UNSAFE,UNTRACED} TO EthFrameHdr;
  173. (* Level 3 *)
  174. ipv4Hdr*: POINTER{UNSAFE,UNTRACED} TO Ipv4Hdr;
  175. ipv6Hdr*: POINTER{UNSAFE,UNTRACED} TO Ipv6Hdr;
  176. arpHdr*: POINTER{UNSAFE,UNTRACED} TO ArpHdr;
  177. (* Level 4 *)
  178. icmpHdr*: POINTER{UNSAFE,UNTRACED} TO IcmpHdr;
  179. udpHdr*: POINTER{UNSAFE,UNTRACED} TO UdpHdr;
  180. tcpHdr*: POINTER{UNSAFE,UNTRACED} TO TcpHdr;
  181. payloadOffs*: Int; (** payload offset for the top level protocol, relative to dataOffs *)
  182. ownedByDev*: BOOLEAN; (** TRUE if the packet is owned by a link device and cannot be used by the user *)
  183. ownedByUser*: BOOLEAN; (** TRUE if the packet is owned by the user *)
  184. ownerPool*: PacketFifo; (** owner pool of the packet; used for returning received packets *)
  185. intf*: Interface;
  186. END;
  187. (** procedure type for handling packets received from an interface *)
  188. PacketHandler* = PROCEDURE(intf: Interface; packet: Packet; flags: SET);
  189. (**
  190. Ethernet frame handler descriptor
  191. *)
  192. EthFrameHandlerDesc* = RECORD
  193. etherType*: Int16;
  194. packetHandler*: PacketHandler;
  195. END;
  196. (** IP address cache *)
  197. IpAddrCache* = POINTER TO IpAddrCacheDesc;
  198. IpAddrCacheDesc* = RECORD
  199. cleanCache*: PROCEDURE{DELEGATE}(cache: IpAddrCache; cleanStatic: BOOLEAN);
  200. addStaticEntry*: PROCEDURE{DELEGATE}(cache: IpAddrCache; CONST ipAddr: IpAddr; CONST macAddr: MacAddr; VAR res: Int): BOOLEAN;
  201. enumerateEntries*: PROCEDURE{DELEGATE}(cache: IpAddrCache; enumerator: PROCEDURE{DELEGATE}(entry: IpAddrCacheEntry));
  202. acquireWrite*, acquireRead*: PROCEDURE{DELEGATE}();
  203. releaseWrite*, releaseRead*: PROCEDURE{DELEGATE}();
  204. intf*: Interface;
  205. END;
  206. (** an entry of an IP address cache *)
  207. IpAddrCacheEntry* = POINTER TO IpAddrCacheEntryDesc;
  208. IpAddrCacheEntryDesc* = RECORD
  209. ipAddr*: IpAddr;
  210. macAddr*: MacAddr;
  211. END;
  212. (** IP address resolution procedure *)
  213. IpAddrResolver* = PROCEDURE{DELEGATE}(intf: Interface; CONST ipAddr: IpAddr; VAR macAddr: MacAddr; completionHandler: TaskHandler; VAR res: Int): BOOLEAN;
  214. (**
  215. Network interface
  216. *)
  217. Interface* = POINTER TO InterfaceDesc;
  218. InterfaceDesc* = RECORD
  219. start*, stop*, reset*, finalize*: PROCEDURE{DELEGATE}(intf: Interface; VAR res: Int): BOOLEAN;
  220. (**
  221. IPv4 network settings
  222. *)
  223. ipv4Addr*: IpAddr; (** IPv4 address of the interface *)
  224. ipv4SubnetMask*: IpAddr; (** IPv4 subnet mask *)
  225. ipv4Prefix*: Int32; (** IPv4 address prefix *)
  226. ipv4Gateway*: IpAddr; (** IPv4 default gateway address *)
  227. (**
  228. IPv6 network settings
  229. *)
  230. ipv6Addr*: IpAddr; (** IPv6 address of the interface *)
  231. ipv6SubnetMask*: IpAddr; (** IPv6 subnetwork mask *)
  232. ipv6Prefix*: IpAddr; (** IPv6 address prefix *)
  233. ipv6Gateway*: IpAddr; (** IPv6 default gateway address *)
  234. dev*: LinkDevice; (** Link device *)
  235. (** plugable LAN IPv4 address resolution functionality *)
  236. ipv4AddrCache*: IpAddrCache; (** IPv4 address resolution cache *)
  237. ipv4AddrResolve*: IpAddrResolver;
  238. (** plugable LAN IPv6 address resolution functionality *)
  239. ipv6AddrCache*: IpAddrCache; (** IPv6 address resolution cache *)
  240. ipv6AddrResolve*: IpAddrResolver;
  241. (* interface-specific periodic and non-periodic tasks *)
  242. nonPeriodicTasks, periodicTasks: TaskHandler;
  243. acquireTasks*, releaseTasks*: PROCEDURE{DELEGATE}();
  244. ethFrameHandlers: ARRAY MaxNumEthFrameHandlers OF EthFrameHandlerDesc;
  245. numEthFrameHandlers: Int;
  246. ipPacketHandlers: ARRAY 256 OF PacketHandler;
  247. (* packet handlers for basic protocols *)
  248. arpHandler: PacketHandler;
  249. icmpHandler: PacketHandler;
  250. udpHandler: PacketHandler;
  251. tcpHandler: PacketHandler;
  252. END;
  253. (**
  254. Ethernet link device
  255. all methods are thread unsafe!
  256. *)
  257. LinkDevice* = POINTER TO LinkDeviceDesc;
  258. LinkDeviceDesc* = RECORD
  259. macAddr*: MacAddr; (** MAC address of the device *)
  260. phyWrite*: PROCEDURE(dev: LinkDevice; phyAddr, regAddr: UInt; data: UInt; VAR res: Int): BOOLEAN;
  261. phyRead*: PROCEDURE(dev: LinkDevice; phyAddr, regAddr: UInt; VAR data: UInt; VAR res: Int): BOOLEAN;
  262. setMacAddr*: PROCEDURE(dev: LinkDevice; CONST macAddr: MacAddr; VAR res: Int): BOOLEAN;
  263. setLinkSpeed*: PROCEDURE(dev: LinkDevice; CONST speed: ARRAY OF CHAR; fullDuplex: BOOLEAN; VAR res: Int): BOOLEAN;
  264. setOptions*: PROCEDURE(dev: LinkDevice; optionsPage: Int; options: SET; VAR res: Int): BOOLEAN;
  265. start*, stop*, reset*, finalize*: PROCEDURE(dev: LinkDevice; VAR res: Int): BOOLEAN;
  266. newPacket*: PROCEDURE(): Packet;
  267. setPacketPayload*: PROCEDURE(dev: LinkDevice; packet: Packet; CONST data: ARRAY OF CHAR; offset: Int; flags: SET; VAR res: Int): BOOLEAN;
  268. sendPacket*: PROCEDURE(dev: LinkDevice; packet: Packet; flags: SET; completionHandler: TaskHandler; VAR res: Int): BOOLEAN;
  269. updateRx*: PROCEDURE(dev: LinkDevice; VAR res: Int): BOOLEAN; (** update receive path *)
  270. updateTx*: PROCEDURE(dev: LinkDevice; VAR res: Int): BOOLEAN; (** update transmit path *)
  271. rxPacketPool*: PacketFifo;
  272. txPacketPool*: PacketFifo;
  273. linkState*: BOOLEAN; (** TRUE if the link is establshed *)
  274. linkSpeed*: ARRAY 32 OF CHAR; (** textual representation of the link speed in Mbps *)
  275. fullDuplex*: BOOLEAN; (** TRUE for full duplex link, otherwise the link is half-duplex *)
  276. recvPackets*: PacketFifo; (** ordered list (FIFO) of received packets *)
  277. isActive*: BOOLEAN; (** TRUE if device is active *)
  278. acquireRx*, acquireTx*: PROCEDURE{DELEGATE}();
  279. releaseRx*, releaseTx*: PROCEDURE{DELEGATE}();
  280. intf*: Interface;
  281. END;
  282. (**
  283. Packet FIFO buffer
  284. *)
  285. PacketFifo* = POINTER TO PacketFifoDesc;
  286. PacketFifoDesc* = RECORD
  287. packets*: POINTER TO ARRAY OF Packet;
  288. count*: Int; (** number of packets in the FIFO *)
  289. wrPos*: Int; (** write pointer position *)
  290. rdPos*: Int; (** read pointer position *)
  291. acquire*, release*: PROCEDURE{DELEGATE}(); (** locks used when thread-safety is enabled *)
  292. END;
  293. (**
  294. Task handler descriptor
  295. *)
  296. TaskHandler* = POINTER TO TaskHandlerDesc;
  297. TaskHandlerDesc* = RECORD
  298. res*: Int; (** result code *)
  299. handle*: PROCEDURE{DELEGATE}(handler: TaskHandler); (** handler procedure *)
  300. param*: ANY; (** handler parameter *)
  301. next*: TaskHandler; (** linked list of handlers *)
  302. (* used for task management *)
  303. taskExpireTime, taskInterval: EnetTiming.Time;
  304. prevTask, nextTask: TaskHandler;
  305. END;
  306. (**
  307. Initialization of a network interface descriptor
  308. intf: interface to initialize, must be preallocated
  309. *)
  310. PROCEDURE InitInterface*(intf: Interface);
  311. VAR i: Int;
  312. BEGIN
  313. intf.ipv4Addr := NilIpAddr;
  314. intf.ipv4Gateway := NilIpAddr;
  315. intf.ipv4SubnetMask := NilIpAddr;
  316. intf.ipv4Prefix := 0;
  317. intf.ipv6Addr := NilIpAddr;
  318. intf.ipv6Gateway := NilIpAddr;
  319. intf.ipv6SubnetMask := NilIpAddr;
  320. intf.ipv6Prefix := NilIpAddr;
  321. intf.numEthFrameHandlers := 0;
  322. FOR i := 0 TO LEN(intf.ipPacketHandlers)-1 DO intf.ipPacketHandlers[i] := NIL; END;
  323. intf.arpHandler := NIL;
  324. intf.icmpHandler := NIL;
  325. intf.udpHandler := NIL;
  326. intf.tcpHandler := NIL;
  327. intf.dev := NIL;
  328. END InitInterface;
  329. (**
  330. Return a packet to its owner pool; thread-safe in case if multithreading is enabled
  331. *)
  332. PROCEDURE ReturnPacketToOwnerPool*(packet: Packet): BOOLEAN;
  333. VAR b: BOOLEAN;
  334. BEGIN
  335. IF ThreadSafe THEN packet.ownerPool.acquire; END;
  336. b := PacketFifoPut(packet.ownerPool,packet);
  337. IF ThreadSafe THEN packet.ownerPool.release; END;
  338. RETURN b;
  339. END ReturnPacketToOwnerPool;
  340. (**
  341. Process received packets for agiven interface
  342. *)
  343. PROCEDURE ProcessIntfRecvPackets*(intf: Interface; VAR res: Int): BOOLEAN;
  344. VAR
  345. packet: Packet;
  346. packetHandler: PacketHandler;
  347. flags: SET;
  348. level4Hdr: ADDRESS;
  349. i: Int;
  350. BEGIN
  351. WHILE PacketFifoGet(intf.dev.recvPackets,packet) DO
  352. ASSERT(~packet.ownedByDev & ~packet.ownedByUser);
  353. packet.intf := intf;
  354. flags := {};
  355. packetHandler := NIL;
  356. (*
  357. Packet dispatching
  358. *)
  359. IF packet.ethFrameHdr.etherType = EtherTypeIpv4 THEN
  360. level4Hdr := ADDRESSOF(packet.ipv4Hdr^) + SIZEOF(Ipv4Hdr);
  361. CASE packet.ipv4Hdr.protocol OF
  362. |ProtoIcmp: packet.icmpHdr := level4Hdr; packetHandler := intf.icmpHandler;
  363. |ProtoUdp: packet.udpHdr := level4Hdr; packetHandler := intf.udpHandler;
  364. |ProtoTcp: packet.tcpHdr := level4Hdr; packetHandler := intf.tcpHandler;
  365. ELSE
  366. packetHandler := intf.ipPacketHandlers[Int(packet.ipv4Hdr.protocol) MOD 100H];
  367. END;
  368. ELSIF packet.ethFrameHdr.etherType = EtherTypeIpv6 THEN
  369. INCL(flags,FlagIpv6);
  370. level4Hdr := ADDRESSOF(packet.ipv6Hdr^) + SIZEOF(Ipv6Hdr);
  371. CASE packet.ipv6Hdr.protocol OF
  372. |ProtoIcmp: packet.icmpHdr := level4Hdr; packetHandler := intf.icmpHandler;
  373. |ProtoUdp: packet.udpHdr := level4Hdr; packetHandler := intf.udpHandler;
  374. |ProtoTcp: packet.tcpHdr := level4Hdr; packetHandler := intf.tcpHandler;
  375. ELSE
  376. packetHandler := intf.ipPacketHandlers[Int(packet.ipv4Hdr.protocol) MOD 100H];
  377. END;
  378. ELSIF packet.ethFrameHdr.etherType = EtherTypeArp THEN
  379. packetHandler := intf.arpHandler;
  380. ELSE
  381. i := 0;
  382. WHILE (i < intf.numEthFrameHandlers) & (intf.ethFrameHandlers[i].etherType # packet.ethFrameHdr.etherType) DO
  383. INC(i);
  384. END;
  385. IF i < intf.numEthFrameHandlers THEN packetHandler := intf.ethFrameHandlers[i].packetHandler; END;
  386. END;
  387. IF packetHandler # NIL THEN packetHandler(intf,packet,flags); END;
  388. IF ~packet.ownedByUser & ~packet.ownedByDev THEN (* put packet to the receive packet pool *)
  389. ASSERT(packet.ownerPool = intf.dev.rxPacketPool);
  390. IF ~ReturnPacketToOwnerPool(packet) THEN res := ErrRxPacketPoolFull; RETURN FALSE; END;
  391. END;
  392. END;
  393. res := 0;
  394. RETURN TRUE;
  395. END ProcessIntfRecvPackets;
  396. (**
  397. Process interface-specific tasks
  398. *)
  399. PROCEDURE ProcessIntfTasks*(intf: Interface; VAR res: Int): BOOLEAN;
  400. VAR
  401. t: EnetTiming.Time;
  402. task: TaskHandler;
  403. BEGIN
  404. (*
  405. execute non-periodic tasks
  406. *)
  407. IF intf.nonPeriodicTasks # NIL THEN
  408. IF ThreadSafe THEN intf.acquireTasks; END;
  409. task := intf.nonPeriodicTasks;
  410. t := EnetTiming.getTimeCounter();
  411. WHILE (task # NIL) & (task.taskExpireTime - t <= 0) DO
  412. (*Trace.String("executing non-periodic task...");*)
  413. task.handle(task);
  414. task := task.nextTask;
  415. (*Trace.StringLn(" Done!, (task=NIL)=" & (task = NIL));*)
  416. END;
  417. intf.nonPeriodicTasks := task;
  418. IF ThreadSafe THEN intf.releaseTasks; END;
  419. END;
  420. (*
  421. execute periodic tasks
  422. *)
  423. IF intf.periodicTasks # NIL THEN
  424. IF ThreadSafe THEN intf.acquireTasks; END;
  425. task := intf.periodicTasks;
  426. t := EnetTiming.getTimeCounter();
  427. WHILE (task # NIL) & (task.taskExpireTime - t <= 0) DO
  428. task.handle(task);
  429. task.taskExpireTime := t + task.taskInterval;
  430. task := task.nextTask;
  431. END;
  432. IF ThreadSafe THEN intf.releaseTasks; END;
  433. END;
  434. res := 0;
  435. RETURN TRUE;
  436. END ProcessIntfTasks;
  437. (**
  438. Setup an Ethernet frame handler for a given network interface
  439. *)
  440. PROCEDURE SetEthFrameHandler*(intf: Interface; etherType: Int16; packetHandler: PacketHandler);
  441. VAR i: Int;
  442. BEGIN
  443. ASSERT(packetHandler # NIL);
  444. i := 0; WHILE (i < intf.numEthFrameHandlers) & (intf.ethFrameHandlers[i].etherType # etherType) DO INC(i); END;
  445. ASSERT(i = intf.numEthFrameHandlers);
  446. IF etherType = EtherTypeArp THEN
  447. intf.arpHandler := packetHandler;
  448. ELSE
  449. i := intf.numEthFrameHandlers;
  450. intf.ethFrameHandlers[i].etherType := etherType;
  451. intf.ethFrameHandlers[i].packetHandler := packetHandler;
  452. END;
  453. END SetEthFrameHandler;
  454. (**
  455. Setup an IP packet handler for a given network interface
  456. *)
  457. PROCEDURE SetIpPacketHandler*(intf: Interface; protocol: Int8; packetHandler: PacketHandler);
  458. BEGIN
  459. IF protocol = ProtoIcmp THEN intf.icmpHandler := packetHandler;
  460. ELSIF protocol = ProtoTcp THEN intf.tcpHandler := packetHandler;
  461. ELSIF protocol = ProtoUdp THEN intf.udpHandler := packetHandler;
  462. ELSE
  463. intf.ipPacketHandlers[Int(protocol) MOD 100H] := packetHandler;
  464. END;
  465. END SetIpPacketHandler;
  466. (**
  467. Initialize a network packet
  468. packet: packet to initialize, must be preallocated
  469. *)
  470. PROCEDURE InitPacket*(packet: Packet);
  471. VAR
  472. level2Hdr: ADDRESS;
  473. level3Hdr: ADDRESS;
  474. BEGIN
  475. ASSERT(packet # NIL);
  476. ASSERT(packet.data # NIL);
  477. level2Hdr := ADDRESSOF(packet.data[packet.dataOffs]);
  478. packet.ethFrameHdr := level2Hdr;
  479. level3Hdr := level2Hdr + SIZEOF(EthFrameHdr);
  480. packet.arpHdr := level3Hdr;
  481. packet.ipv4Hdr := level3Hdr;
  482. packet.ipv6Hdr := level3Hdr;
  483. (* will be set up in runtime *)
  484. packet.icmpHdr := NIL;
  485. packet.udpHdr := NIL;
  486. packet.tcpHdr := NIL;
  487. END InitPacket;
  488. (**
  489. Create a packet FIFO
  490. allocSize: FIFO size to allocate
  491. *)
  492. PROCEDURE NewPacketFifo*(allocSize: Int): PacketFifo;
  493. VAR fifo: PacketFifo;
  494. BEGIN
  495. NEW(fifo);
  496. NEW(fifo.packets,allocSize);
  497. fifo.wrPos := 0;
  498. fifo.rdPos := 0;
  499. fifo.count := 0;
  500. RETURN fifo;
  501. END NewPacketFifo;
  502. (**
  503. Put an entry into a packet FIFO
  504. Returns TRUE in case of success, FALSE indicates that the FIFO is full
  505. *)
  506. PROCEDURE PacketFifoPut*(fifo: PacketFifo; packet: Packet): BOOLEAN;
  507. BEGIN
  508. IF fifo.count < LEN(fifo.packets) THEN
  509. fifo.packets[fifo.wrPos] := packet;
  510. INC(fifo.wrPos); IF fifo.wrPos >= LEN(fifo.packets) THEN fifo.wrPos := 0; END;
  511. INC(fifo.count);
  512. RETURN TRUE;
  513. ELSE
  514. RETURN FALSE;
  515. END;
  516. END PacketFifoPut;
  517. (**
  518. Get an entry from a packet FIFO
  519. Returns TRUE in case of success, FALSE indicates that the FIFO is empty
  520. *)
  521. PROCEDURE PacketFifoGet*(fifo: PacketFifo; VAR packet: Packet): BOOLEAN;
  522. BEGIN
  523. IF fifo.count > 0 THEN
  524. packet := fifo.packets[fifo.rdPos];
  525. INC(fifo.rdPos); IF fifo.rdPos >= LEN(fifo.packets) THEN fifo.rdPos := 0; END;
  526. DEC(fifo.count);
  527. RETURN TRUE;
  528. ELSE
  529. RETURN FALSE;
  530. END;
  531. END PacketFifoGet;
  532. (**
  533. Schedule a task
  534. task: the task handler to execute
  535. periodic: TRUE for a periodic task
  536. interval: time interval in time counts after the expiration of which the specified task will be executed
  537. *)
  538. PROCEDURE ScheduleTask*(intf: Interface; task: TaskHandler; periodic: BOOLEAN; interval: EnetTiming.Time);
  539. VAR
  540. handler, handlerPrev: TaskHandler;
  541. PROCEDURE PutTask(VAR taskList: TaskHandler; task: TaskHandler);
  542. BEGIN
  543. (* put the task into the list of tasks - the earliest task to execute first *)
  544. IF taskList # NIL THEN
  545. handler := taskList;
  546. IF task.taskExpireTime - handler.taskExpireTime <= 0 THEN (* the task is the earliest to execute *)
  547. task.prevTask := NIL;
  548. task.nextTask := handler;
  549. handler.prevTask := task;
  550. taskList := task;
  551. ELSE
  552. REPEAT
  553. handlerPrev := handler;
  554. handler := handler.nextTask;
  555. UNTIL (handler = NIL) OR (task.taskExpireTime - handler.taskExpireTime <= 0);
  556. IF handler # NIL THEN (* put the task in between handlerPrev and handler *)
  557. task.prevTask := handler.prevTask;
  558. task.nextTask := handler;
  559. handler.prevTask := task;
  560. ELSE (* the task is the latest to execute *)
  561. task.prevTask := handlerPrev;
  562. task.nextTask := NIL;
  563. handlerPrev.nextTask := task;
  564. END;
  565. END;
  566. ELSE
  567. task.prevTask := NIL;
  568. task.nextTask := NIL;
  569. taskList := task;
  570. END;
  571. END PutTask;
  572. BEGIN
  573. ASSERT(task.handle # NIL);
  574. ASSERT(interval > 0);
  575. IF ThreadSafe THEN intf.acquireTasks; END;
  576. task.taskExpireTime := EnetTiming.getTimeCounter() + interval;
  577. IF periodic THEN
  578. task.taskInterval := interval;
  579. PutTask(intf.periodicTasks,task);
  580. ELSE
  581. PutTask(intf.nonPeriodicTasks,task);
  582. END;
  583. IF ThreadSafe THEN intf.releaseTasks; END;
  584. END ScheduleTask;
  585. (**
  586. Remove a scheduled task
  587. *)
  588. PROCEDURE RemoveTask*(intf: Interface; task: TaskHandler);
  589. BEGIN
  590. IF ThreadSafe THEN intf.acquireTasks; END;
  591. IF task.prevTask # NIL THEN
  592. task.prevTask.nextTask := task.nextTask;
  593. ELSIF task = intf.nonPeriodicTasks THEN
  594. intf.nonPeriodicTasks := task.nextTask;
  595. ELSIF task = intf.periodicTasks THEN
  596. intf.periodicTasks := task.nextTask;
  597. END;
  598. IF task.nextTask # NIL THEN task.nextTask.prevTask := task.prevTask; END;
  599. task.nextTask := NIL;
  600. task.prevTask := NIL;
  601. IF ThreadSafe THEN intf.releaseTasks; END;
  602. END RemoveTask;
  603. PROCEDURE LinkTaskHandlers*(chain, handlerToLink: TaskHandler);
  604. BEGIN
  605. ASSERT(chain # handlerToLink);
  606. handlerToLink.next := chain.next;
  607. chain.next := handlerToLink;
  608. END LinkTaskHandlers;
  609. (* Returns TRUE if a given character represents a decimal digit *)
  610. PROCEDURE IsDecDigit(ch: CHAR): BOOLEAN;
  611. BEGIN
  612. RETURN (ORD(ch) >= ORD('0')) & (ORD(ch) <= ORD('9'));
  613. END IsDecDigit;
  614. (* Returns TRUE if a given character represents a hexadecimal digit *)
  615. PROCEDURE IsHexDigit(ch: CHAR): BOOLEAN;
  616. BEGIN
  617. RETURN ((ORD(ch) >= ORD('0')) & (ORD(ch) <= ORD('9'))) OR ((ORD(CAP(ch)) >= ORD('A')) & (ORD(CAP(ch)) <= ORD('F')));
  618. END IsHexDigit;
  619. PROCEDURE DecDigitToInt(digit: CHAR): Int;
  620. BEGIN
  621. RETURN ORD(digit) - ORD('0');
  622. END DecDigitToInt;
  623. PROCEDURE HexDigitToInt(digit: CHAR): Int;
  624. BEGIN
  625. IF IsDecDigit(digit) THEN
  626. RETURN ORD(digit) - ORD('0');
  627. ELSE
  628. RETURN ORD(CAP(digit)) - ORD('A') + 10;
  629. END;
  630. END HexDigitToInt;
  631. (* Parse a word from a string representation of an IP or MAC address *)
  632. PROCEDURE ParseAddrWord(
  633. CONST strIp: ARRAY OF CHAR;
  634. VAR pos: Int;
  635. delim: CHAR;
  636. maxNumDigits: Int;
  637. hex, lastWord: BOOLEAN;
  638. VAR word: Int
  639. ): BOOLEAN;
  640. VAR
  641. k, len: Int;
  642. strWord: ARRAY 8 OF CHAR;
  643. digitCondProc: PROCEDURE(ch: CHAR): BOOLEAN;
  644. BEGIN
  645. IF ~hex THEN digitCondProc := IsDecDigit;
  646. ELSE digitCondProc := IsHexDigit;
  647. END;
  648. len := 0;
  649. WHILE (pos < LEN(strIp)) & digitCondProc(strIp[pos]) & (len < maxNumDigits) DO strWord[len] := strIp[pos]; INC(pos); INC(len); END;
  650. IF ~lastWord THEN
  651. IF (pos = LEN(strIp)) OR (strIp[pos] # delim) OR (len = 0) THEN RETURN FALSE; END;
  652. ELSE
  653. IF (pos = LEN(strIp)) OR (strIp[pos] # 0X) OR (len = 0) THEN RETURN FALSE; END;
  654. END;
  655. strWord[len] := 0X;
  656. IF ~hex THEN (* decimal *)
  657. word := DecDigitToInt(strWord[0]);
  658. k := 1; DEC(len);
  659. WHILE len > 0 DO
  660. word := word*10 + DecDigitToInt(strWord[k]);
  661. INC(k); DEC(len);
  662. END;
  663. ELSE (* hexadecimal *)
  664. word := HexDigitToInt(strWord[0]);
  665. k := 1; DEC(len);
  666. WHILE len > 0 DO
  667. word := word*16 + HexDigitToInt(strWord[k]);
  668. INC(k); DEC(len);
  669. END;
  670. END;
  671. RETURN TRUE;
  672. END ParseAddrWord;
  673. (**
  674. Compose an IP address given its textual representation
  675. *)
  676. PROCEDURE StrToIpAddr*(CONST strIpAddr: ARRAY OF CHAR; VAR ipAddr: IpAddr): BOOLEAN;
  677. VAR
  678. d: ARRAY 8 OF Int;
  679. i, k: Int;
  680. BEGIN
  681. i := 0;
  682. IF ParseAddrWord(strIpAddr,i,".",3,FALSE,FALSE,d[0]) THEN
  683. FOR k := 1 TO 3 DO
  684. INC(i);
  685. IF ~ParseAddrWord(strIpAddr,i,".",3,FALSE,k=3,d[k]) THEN RETURN FALSE; END;
  686. END;
  687. ipAddr.addr[0] := Int32(d[3])*1000000H + Int32(d[2])*10000H + Int32(d[1])*100H + Int32(d[0]);
  688. ipAddr.ver := 4;
  689. RETURN TRUE;
  690. ELSIF ParseAddrWord(strIpAddr,i,":",4,TRUE,FALSE,d[0]) THEN
  691. FOR k := 1 TO 7 DO
  692. INC(i);
  693. IF ~ParseAddrWord(strIpAddr,i,".",3,FALSE,k=7,d[k]) THEN RETURN FALSE; END;
  694. END;
  695. (*!TODO: not sure whether this is correct, check it *)
  696. ipAddr.addr[0] := Int32(d[0])*10000H + Int32(d[1]);
  697. ipAddr.addr[1] := Int32(d[2])*10000H + Int32(d[3]);
  698. ipAddr.addr[2] := Int32(d[4])*10000H + Int32(d[5]);
  699. ipAddr.addr[3] := Int32(d[6])*10000H + Int32(d[7]);
  700. ipAddr.ver := 6;
  701. RETURN TRUE;
  702. END;
  703. RETURN FALSE;
  704. END StrToIpAddr;
  705. (**
  706. Write a textual representation of an IP address.
  707. *)
  708. PROCEDURE IpAddrToStr*(CONST ipAddr: IpAddr; VAR strIpAddr: ARRAY OF CHAR): BOOLEAN;
  709. VAR
  710. int: ARRAY 16 OF CHAR;
  711. BEGIN
  712. IF ~IsValidIpAddr(ipAddr) THEN RETURN FALSE END;
  713. IF ipAddr.ver = 4 THEN
  714. EnetUtils.IntToStr(ipAddr.addr[0] MOD 100H, strIpAddr);
  715. EnetUtils.StrAppend(strIpAddr, ".");
  716. EnetUtils.IntToStr(ipAddr.addr[0] DIV 100H MOD 100H, int);
  717. EnetUtils.StrAppend(strIpAddr, int);
  718. EnetUtils.StrAppend(strIpAddr, ".");
  719. EnetUtils.IntToStr(ipAddr.addr[0] DIV 10000H MOD 100H, int);
  720. EnetUtils.StrAppend(strIpAddr, int);
  721. EnetUtils.StrAppend(strIpAddr, ".");
  722. EnetUtils.IntToStr(ipAddr.addr[0] DIV 1000000H MOD 100H, int);
  723. EnetUtils.StrAppend(strIpAddr, int);
  724. ELSIF ipAddr.ver = 6 THEN
  725. ELSE
  726. RETURN FALSE
  727. END;
  728. RETURN TRUE
  729. END IpAddrToStr;
  730. (**
  731. Compose a MAC address given its textual representation
  732. *)
  733. PROCEDURE StrToMacAddr*(CONST strMacAddr: ARRAY OF CHAR; VAR macAddr: MacAddr): BOOLEAN;
  734. VAR
  735. i, k, d: Int;
  736. BEGIN
  737. i := 0;
  738. IF ParseAddrWord(strMacAddr,i,":",2,TRUE,FALSE,d) THEN
  739. macAddr.addr[0] := Int8(d);
  740. FOR k := 1 TO 5 DO
  741. INC(i);
  742. IF ~ParseAddrWord(strMacAddr,i,":",3,TRUE,k=5,d) THEN RETURN FALSE; END;
  743. macAddr.addr[k] := Int8(d);
  744. END;
  745. RETURN TRUE;
  746. END;
  747. RETURN FALSE;
  748. END StrToMacAddr;
  749. (** Returns TRUE if a given IP address is valid *)
  750. PROCEDURE IsValidIpAddr*(CONST ipAddr: IpAddr): BOOLEAN;
  751. BEGIN
  752. RETURN (ipAddr.ver = 4) OR (ipAddr.ver = 6);
  753. END IsValidIpAddr;
  754. (**
  755. Setup an Ethernet frame
  756. *)
  757. PROCEDURE SetEthFrame*(
  758. packet: Packet;
  759. CONST srcMacAddr, dstMacAddr: MacAddr;
  760. etherType: Int16;
  761. dataLen: Int
  762. );
  763. BEGIN
  764. packet.ethFrameHdr.dstMacAddr := dstMacAddr;
  765. packet.ethFrameHdr.srcMacAddr := srcMacAddr;
  766. packet.ethFrameHdr.etherType := etherType;
  767. packet.payloadOffs := SIZEOF(EthFrameHdr);
  768. packet.dataLen := dataLen+SIZEOF(EthFrameHdr);
  769. END SetEthFrame;
  770. (**
  771. Setup an IP packet header
  772. *)
  773. PROCEDURE SetIpPacket*(
  774. packet: Packet;
  775. CONST srcMacAddr, dstMacAddr: MacAddr;
  776. CONST srcIpAddr, dstIpAddr: IpAddr;
  777. protocol: Int8;
  778. ipDataLen: Int
  779. );
  780. BEGIN
  781. ASSERT(srcIpAddr.ver = dstIpAddr.ver);
  782. IF srcIpAddr.ver = 4 THEN
  783. SetEthFrame(packet,srcMacAddr,dstMacAddr,EtherTypeIpv4,ipDataLen+SIZEOF(Ipv4Hdr));
  784. packet.ipv4Hdr.verAndIhl := 0x40 + (SIZEOF(Ipv4Hdr) DIV 4);
  785. packet.ipv4Hdr.dscpAndEcn := Int8(IpDiffServ+IpEcn); (* type-of-service on outgoing datagrams *)
  786. IF LittleEndianSystem THEN
  787. packet.ipv4Hdr.length := EnetUtils.SwitchEndianness16(Int16(ipDataLen+SIZEOF(Ipv4Hdr)));
  788. ELSE
  789. packet.ipv4Hdr.length := Int16(ipDataLen+SIZEOF(Ipv4Hdr));
  790. END;
  791. packet.ipv4Hdr.fragmentId := 0; (*! since no fragmentation is allowed the identification field is omitted (according to RFC6864) *)
  792. packet.ipv4Hdr.flagsAndFragmentOffs := 0x0040; (* do not allow fragmentation *)
  793. packet.ipv4Hdr.ttl := Int8(IpTtl);
  794. packet.ipv4Hdr.protocol := protocol;
  795. packet.ipv4Hdr.checksum := Int16(0xd0f5); (*!TODO: compute checksum if the link device does not support IP checksum offload *)
  796. packet.ipv4Hdr.srcIpAddr := srcIpAddr.addr[0];
  797. packet.ipv4Hdr.dstIpAddr := dstIpAddr.addr[0];
  798. INC(packet.payloadOffs,SIZEOF(Ipv4Hdr));
  799. ELSE
  800. HALT(100);
  801. END;
  802. END SetIpPacket;
  803. (**
  804. Setup a UDP packet
  805. *)
  806. PROCEDURE SetUdpPacket*(
  807. packet: Packet;
  808. CONST srcMacAddr, dstMacAddr: MacAddr;
  809. CONST srcIpAddr, dstIpAddr: IpAddr;
  810. srcPort, dstPort: Int;
  811. udpDataLen: Int
  812. );
  813. BEGIN
  814. SetIpPacket(packet,srcMacAddr,dstMacAddr,srcIpAddr,dstIpAddr,ProtoUdp,udpDataLen+SIZEOF(UdpHdr));
  815. IF srcIpAddr.ver = 4 THEN
  816. packet.udpHdr := ADDRESSOF(packet.ipv4Hdr.verAndIhl) + SIZEOF(Ipv4Hdr);
  817. IF LittleEndianSystem THEN
  818. packet.udpHdr.length := EnetUtils.SwitchEndianness16(Int16(udpDataLen+SIZEOF(UdpHdr)));
  819. ELSE
  820. packet.udpHdr.length := Int16(udpDataLen+SIZEOF(UdpHdr));
  821. END;
  822. ELSE
  823. HALT(100);
  824. END;
  825. IF LittleEndianSystem THEN
  826. packet.udpHdr.srcPort := EnetUtils.SwitchEndianness16(Int16(srcPort));
  827. packet.udpHdr.dstPort := EnetUtils.SwitchEndianness16(Int16(dstPort));
  828. ELSE
  829. packet.udpHdr.srcPort := Int16(srcPort);
  830. packet.udpHdr.dstPort := Int16(dstPort);
  831. END;
  832. packet.udpHdr.checksum := 0;
  833. INC(packet.payloadOffs,SIZEOF(UdpHdr));
  834. END SetUdpPacket;
  835. (**
  836. Returns TRUE if an IP address belongs to the same subnetwork as the IP address of a given interface
  837. *)
  838. PROCEDURE IpAddrFromSameSubnet*(intf: Interface; CONST ipAddr: IpAddr): BOOLEAN;
  839. BEGIN
  840. IF ipAddr.ver = 4 THEN
  841. RETURN (S.VAL(Int32,S.VAL(SET,UInt(ipAddr.addr[0])) * S.VAL(SET,UInt(intf.ipv4SubnetMask.addr[0]))) = intf.ipv4Prefix)
  842. OR (ipAddr = BroadcastIpAddr);
  843. ELSIF ipAddr.ver = 6 THEN
  844. RETURN (S.VAL(Int32,S.VAL(SET,UInt(ipAddr.addr[0])) * S.VAL(SET,UInt(intf.ipv6SubnetMask.addr[0]))) = intf.ipv6Prefix.addr[0]) &
  845. (S.VAL(Int32,S.VAL(SET,UInt(ipAddr.addr[1])) * S.VAL(SET,UInt(intf.ipv6SubnetMask.addr[1]))) = intf.ipv6Prefix.addr[1]) &
  846. (S.VAL(Int32,S.VAL(SET,UInt(ipAddr.addr[2])) * S.VAL(SET,UInt(intf.ipv6SubnetMask.addr[2]))) = intf.ipv6Prefix.addr[2]) &
  847. (S.VAL(Int32,S.VAL(SET,UInt(ipAddr.addr[3])) * S.VAL(SET,UInt(intf.ipv6SubnetMask.addr[3]))) = intf.ipv6Prefix.addr[3])
  848. ELSE
  849. RETURN FALSE;
  850. END;
  851. END IpAddrFromSameSubnet;
  852. (**
  853. Returns TRUE if the two IP addresses are equal
  854. *)
  855. OPERATOR "="*(CONST ipAddr0, ipAddr1: IpAddr): BOOLEAN;
  856. BEGIN
  857. IF ipAddr0.ver = ipAddr1.ver THEN
  858. IF ipAddr0.ver = 4 THEN RETURN ipAddr0.addr[0] = ipAddr1.addr[0];
  859. ELSE RETURN (ipAddr0.addr[0] = ipAddr1.addr[0]) & (ipAddr0.addr[1] = ipAddr1.addr[1]) & (ipAddr0.addr[2] = ipAddr1.addr[2]) & (ipAddr0.addr[3] = ipAddr1.addr[3]);
  860. END;
  861. ELSE RETURN FALSE;
  862. END;
  863. END "=";
  864. (**
  865. Returns TRUE if the two IP addresses are not equal
  866. *)
  867. OPERATOR "#"*(CONST ipAddr0, ipAddr1: IpAddr): BOOLEAN;
  868. BEGIN
  869. RETURN ~(ipAddr0 = ipAddr1);
  870. END "#";
  871. VAR
  872. NilMacAddr-: MacAddr; (** NIL MAC address *)
  873. BroadcastMacAddr-: MacAddr; (** broadcast MAC address *)
  874. NilIpAddr-: IpAddr; (** NIL IP address *)
  875. BroadcastIpAddr -: IpAddr; (** broadcast IPv4 address *)
  876. PROCEDURE InitMod;
  877. VAR i: Int;
  878. BEGIN
  879. Trace.string := EnetEnvironment.TraceString;
  880. EnetTiming.getTimeCounter := EnetEnvironment.GetTimeCounter;
  881. EnetTiming.fromMicro := EnetEnvironment.FromMicro;
  882. EnetTiming.fromMilli := EnetEnvironment.FromMilli;
  883. FOR i := 0 TO LEN(NilMacAddr.addr)-1 DO
  884. NilMacAddr.addr[i] := 0x00;
  885. BroadcastMacAddr.addr[i] := Int8(0xFF);
  886. END;
  887. NilIpAddr.addr[0] := 0x00;
  888. NilIpAddr.addr[1] := 0x00;
  889. NilIpAddr.addr[2] := 0x00;
  890. NilIpAddr.addr[3] := 0x00;
  891. NilIpAddr.ver := 0;
  892. ASSERT(StrToIpAddr("255.255.255.255", BroadcastIpAddr));
  893. END InitMod;
  894. BEGIN
  895. InitMod;
  896. END EnetBase.