EnetInterfaces.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. MODULE EnetInterfaces;
  2. (**
  3. AUTHOR: Alexey Morozov, HighDim GmbH, 2015
  4. PURPOSE: Ethernet networking stack, network interface management
  5. *)
  6. IMPORT
  7. S := SYSTEM, EnetBase, EnetTiming;
  8. CONST
  9. MaxNumInterfaces* = 2; (** maximal number of supported network interfaces *)
  10. TYPE
  11. Int32 = EnetBase.Int32;
  12. Int16 = EnetBase.Int16;
  13. Int = EnetBase.Int;
  14. UInt = EnetBase.UInt;
  15. Packet = EnetBase.Packet;
  16. IpAddr = EnetBase.IpAddr;
  17. MacAddr = EnetBase.MacAddr;
  18. Interface = EnetBase.Interface;
  19. VAR
  20. intfs-: ARRAY MaxNumInterfaces OF Interface;
  21. numIntfs-: LONGINT;
  22. (** plugable locks for concurrent manipulation of the interface list *)
  23. acquireIntfsWrite*, releaseIntfsWrite*: PROCEDURE{DELEGATE}();
  24. acquireIntfsRead*, releaseIntfsRead*: PROCEDURE{DELEGATE}();
  25. (**
  26. Initialize an interface; must be preallocated
  27. *)
  28. PROCEDURE InitInterface*(
  29. intf: Interface;
  30. dev: EnetBase.LinkDevice;
  31. VAR res: Int
  32. ): BOOLEAN;
  33. BEGIN
  34. IF intf = NIL THEN res := EnetBase.ErrInvalidValue; RETURN FALSE; END;
  35. EnetBase.InitInterface(intf);
  36. IF dev = NIL THEN res := EnetBase.ErrInvalidValue; RETURN FALSE; END;
  37. intf.dev := dev;
  38. dev.intf := intf;
  39. res := 0;
  40. RETURN TRUE;
  41. END InitInterface;
  42. (**
  43. Register an interface
  44. *)
  45. PROCEDURE Add*(intf: Interface; VAR res: Int): BOOLEAN;
  46. VAR
  47. b: BOOLEAN;
  48. i: Int;
  49. BEGIN
  50. IF EnetBase.ThreadSafe THEN acquireIntfsWrite; END;
  51. IF numIntfs < LEN(intfs) THEN
  52. (* do not allow to add an interface twice *)
  53. i := 0;
  54. WHILE (i < numIntfs) & (intfs[i] # intf) DO INC(i); END;
  55. IF i = numIntfs THEN
  56. intfs[numIntfs] := intf;
  57. INC(numIntfs);
  58. res := 0; b := TRUE;
  59. ELSE
  60. res := EnetBase.ErrAlreadyExists; b := FALSE;
  61. END;
  62. ELSE
  63. res := EnetBase.ErrOutOfBounds; b := FALSE;
  64. END;
  65. IF EnetBase.ThreadSafe THEN releaseIntfsWrite; END;
  66. RETURN b;
  67. END Add;
  68. (**
  69. Start a network interface; thread-safe in case if multithreading is enabled
  70. *)
  71. PROCEDURE Start*(intf: Interface; VAR res: Int): BOOLEAN;
  72. VAR b: BOOLEAN;
  73. BEGIN
  74. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  75. b := intf.start(intf,res);
  76. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  77. RETURN b;
  78. END Start;
  79. (**
  80. Start all network interfaces
  81. *)
  82. PROCEDURE StartAll*(VAR res: Int): BOOLEAN;
  83. VAR i, r: Int;
  84. BEGIN
  85. IF EnetBase.ThreadSafe THEN acquireIntfsRead; END;
  86. res := 0;
  87. FOR i := 0 TO numIntfs-1 DO
  88. IF ~Start(intfs[i],r) THEN res := r; END;
  89. END;
  90. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  91. RETURN res = 0;
  92. END StartAll;
  93. (**
  94. Stop a network interface; thread-safe in case if multithreading is enabled
  95. *)
  96. PROCEDURE Stop*(intf: Interface; VAR res: Int): BOOLEAN;
  97. VAR b: BOOLEAN;
  98. BEGIN
  99. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  100. b := intf.stop(intf,res);
  101. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  102. RETURN b;
  103. END Stop;
  104. (**
  105. Stop all network interfaces
  106. *)
  107. PROCEDURE StopAll*(VAR res: Int): BOOLEAN;
  108. VAR i, r: Int;
  109. BEGIN
  110. IF EnetBase.ThreadSafe THEN acquireIntfsRead; END;
  111. res := 0;
  112. FOR i := 0 TO numIntfs-1 DO
  113. IF ~Stop(intfs[i],r) THEN res := r; END;
  114. END;
  115. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  116. RETURN res = 0;
  117. END StopAll;
  118. (**
  119. Reset a network interface; thread-safe in case if multithreading is enabled
  120. *)
  121. PROCEDURE Reset*(intf: Interface; VAR res: Int): BOOLEAN;
  122. VAR b: BOOLEAN;
  123. BEGIN
  124. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  125. b := intf.reset(intf,res);
  126. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  127. RETURN b;
  128. END Reset;
  129. (**
  130. Reset all network interfaces
  131. *)
  132. PROCEDURE ResetAll*(VAR res: Int): BOOLEAN;
  133. VAR i, r: Int;
  134. BEGIN
  135. IF EnetBase.ThreadSafe THEN acquireIntfsRead; END;
  136. res := 0;
  137. FOR i := 0 TO numIntfs-1 DO
  138. IF ~Reset(intfs[i],r) THEN res := r; END;
  139. END;
  140. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  141. RETURN res = 0;
  142. END ResetAll;
  143. (**
  144. Set MAC address for a given network interface
  145. *)
  146. PROCEDURE SetMacAddr*(intf: Interface; CONST macAddr: MacAddr; VAR res: Int): BOOLEAN;
  147. VAR b: BOOLEAN;
  148. BEGIN
  149. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  150. b := intf.dev.setMacAddr(intf.dev,macAddr,res);
  151. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  152. RETURN b;
  153. END SetMacAddr;
  154. (**
  155. Setup interface link
  156. *)
  157. PROCEDURE SetLinkSpeed*(intf: Interface; CONST linkSpeed: ARRAY OF CHAR; fullDuplex: BOOLEAN; VAR res: Int): BOOLEAN;
  158. VAR b: BOOLEAN;
  159. BEGIN
  160. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  161. b := intf.dev.setLinkSpeed(intf.dev,linkSpeed,fullDuplex,res);
  162. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  163. RETURN b;
  164. END SetLinkSpeed;
  165. (**
  166. Setup IP configuration for a given network interface
  167. *)
  168. PROCEDURE SetIpConfig*(
  169. intf: Interface;
  170. CONST ipAddr: IpAddr;
  171. CONST subnetMask: IpAddr;
  172. CONST gateway: IpAddr;
  173. VAR res: Int
  174. ): BOOLEAN;
  175. VAR b: BOOLEAN;
  176. BEGIN
  177. ASSERT(intf # NIL);
  178. IF (ipAddr.ver # 4) & (ipAddr.ver # 6) THEN res := EnetBase.ErrInvalidValue; RETURN FALSE; END;
  179. IF (gateway.ver # ipAddr.ver) OR (subnetMask.ver # ipAddr.ver) THEN res := EnetBase.ErrInvalidValue; RETURN FALSE; END;
  180. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; intf.dev.acquireRx; END;
  181. IF ipAddr.ver = 4 THEN
  182. intf.ipv4Addr := ipAddr;
  183. intf.ipv4SubnetMask := subnetMask;
  184. intf.ipv4Gateway := gateway;
  185. intf.ipv4Prefix := S.VAL(UInt,S.VAL(SET,UInt(ipAddr.addr[0])) * S.VAL(SET,UInt(subnetMask.addr[0])));
  186. ELSE
  187. intf.ipv6Addr := ipAddr;
  188. intf.ipv6SubnetMask := subnetMask;
  189. intf.ipv6Gateway := gateway;
  190. intf.ipv6Prefix.addr[0] := S.VAL(UInt,S.VAL(SET,UInt(ipAddr.addr[0])) * S.VAL(SET,UInt(subnetMask.addr[0])));
  191. intf.ipv6Prefix.addr[1] := S.VAL(UInt,S.VAL(SET,UInt(ipAddr.addr[1])) * S.VAL(SET,UInt(subnetMask.addr[1])));
  192. intf.ipv6Prefix.addr[2] := S.VAL(UInt,S.VAL(SET,UInt(ipAddr.addr[2])) * S.VAL(SET,UInt(subnetMask.addr[2])));
  193. intf.ipv6Prefix.addr[3] := S.VAL(UInt,S.VAL(SET,UInt(ipAddr.addr[3])) * S.VAL(SET,UInt(subnetMask.addr[3])));
  194. END;
  195. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; intf.dev.releaseRx; END;
  196. RETURN TRUE;
  197. END SetIpConfig;
  198. (**
  199. Get a packet for transmission from a packet pool of a given interface; thread-safe
  200. *)
  201. PROCEDURE GetTxPacket*(intf: Interface; VAR packet: Packet): BOOLEAN;
  202. VAR b: BOOLEAN;
  203. BEGIN
  204. IF EnetBase.ThreadSafe THEN intf.dev.txPacketPool.acquire; END;
  205. b := EnetBase.PacketFifoGet(intf.dev.txPacketPool,packet);
  206. IF EnetBase.ThreadSafe THEN intf.dev.txPacketPool.release; END;
  207. RETURN b;
  208. END GetTxPacket;
  209. (**
  210. Send a packet via a given interface; thread-safe
  211. *)
  212. PROCEDURE SendPacket*(intf: Interface; packet: Packet; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  213. VAR b: BOOLEAN;
  214. BEGIN
  215. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; END;
  216. b := intf.dev.sendPacket(intf.dev,packet,flags,completionHandler,res);
  217. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; END;
  218. RETURN b;
  219. END SendPacket;
  220. (**
  221. Forward an Ethernet packet to a given destination
  222. *)
  223. PROCEDURE ForwardEth*(intf: Interface; packet: Packet; CONST dstMacAddr: MacAddr; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  224. BEGIN
  225. packet.ethFrameHdr.dstMacAddr := dstMacAddr;
  226. packet.ethFrameHdr.srcMacAddr := intf.dev.macAddr;
  227. RETURN SendPacket(intf,packet,flags,completionHandler,res);
  228. END ForwardEth;
  229. (** Send a reply based on the received packet at the level of Ethernet *)
  230. PROCEDURE ReplyEth*(intf: Interface; packet: Packet; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  231. BEGIN
  232. packet.ethFrameHdr.dstMacAddr := packet.ethFrameHdr.srcMacAddr;
  233. packet.ethFrameHdr.srcMacAddr := intf.dev.macAddr;
  234. RETURN SendPacket(intf,packet,flags,completionHandler,res);
  235. END ReplyEth;
  236. (** Forward an IP packet to a given destination *)
  237. PROCEDURE ForwardIp*(intf: Interface; packet: Packet; CONST dstIpAddr: IpAddr; CONST dstMacAddr: MacAddr; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  238. BEGIN
  239. IF EnetBase.FlagIpv6 IN flags THEN (* IPv6 *)
  240. HALT(100);
  241. ELSE (* IPv4 *)
  242. packet.ipv4Hdr.dstIpAddr := dstIpAddr.addr[0];
  243. packet.ipv4Hdr.srcIpAddr := intf.ipv4Addr.addr[0];
  244. END;
  245. RETURN ForwardEth(intf,packet,dstMacAddr,flags,completionHandler,res);
  246. END ForwardIp;
  247. (** Send a reply based on the received packet at the level of IP protocol *)
  248. PROCEDURE ReplyIp*(intf: Interface; packet: Packet; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  249. BEGIN
  250. IF EnetBase.FlagIpv6 IN flags THEN (* IPv6 *)
  251. HALT(100);
  252. ELSE (* IPv4 *)
  253. packet.ipv4Hdr.dstIpAddr := packet.ipv4Hdr.srcIpAddr;
  254. packet.ipv4Hdr.srcIpAddr := intf.ipv4Addr.addr[0];
  255. END;
  256. RETURN ReplyEth(intf,packet,flags,completionHandler,res);
  257. END ReplyIp;
  258. (** Forward an UDP packet to a given destination *)
  259. PROCEDURE ForwardUdp*(intf: Interface; packet: Packet; CONST dstIpAddr: IpAddr; srcPort, dstPort: Int16; CONST dstMacAddr: MacAddr; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  260. BEGIN
  261. packet.udpHdr.srcPort := srcPort;
  262. packet.udpHdr.dstPort := dstPort;
  263. RETURN ForwardIp(intf,packet,dstIpAddr,dstMacAddr,flags,completionHandler,res);
  264. END ForwardUdp;
  265. (** Send a reply based on the received packet at the level of UDP protocol *)
  266. PROCEDURE ReplyUdp*(intf: Interface; packet: Packet; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  267. VAR port: Int16;
  268. BEGIN
  269. (*
  270. swap source and destination ports
  271. *)
  272. port := packet.udpHdr.dstPort;
  273. packet.udpHdr.dstPort := packet.udpHdr.srcPort;
  274. packet.udpHdr.srcPort := port;
  275. RETURN ReplyIp(intf,packet,flags,completionHandler,res);
  276. END ReplyUdp;
  277. (** Resolve an IP address *)
  278. PROCEDURE ResolveIpAddr*(CONST ipAddr: IpAddr; VAR macAddr: MacAddr; VAR intf: Interface; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  279. VAR
  280. i: Int;
  281. b: BOOLEAN;
  282. BEGIN
  283. IF EnetBase.ThreadSafe THEN acquireIntfsRead; END;
  284. FOR i := 0 TO numIntfs-1 DO
  285. intf := intfs[i];
  286. IF EnetBase.IpAddrFromSameSubnet(intf,ipAddr) THEN
  287. IF ipAddr.ver = 4 THEN
  288. IF intf.ipv4AddrResolve # NIL THEN
  289. b := intf.ipv4AddrResolve(intf,ipAddr,macAddr,completionHandler,res);
  290. ELSE
  291. res := EnetBase.ErrInvalidValue; b := FALSE;
  292. END;
  293. ELSE
  294. IF intf.ipv6AddrResolve # NIL THEN
  295. b := intf.ipv6AddrResolve(intf,ipAddr,macAddr,completionHandler,res);
  296. ELSE
  297. res := EnetBase.ErrInvalidValue; b := FALSE;
  298. END;
  299. END;
  300. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  301. RETURN b;
  302. END;
  303. END;
  304. (* the specified IP address is not local to any of the available interfaces *)
  305. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  306. res := EnetBase.ErrUnresolvedAddr;
  307. RETURN FALSE;
  308. END ResolveIpAddr;
  309. (** Update the state of a network interface; to be called regularly in a loop *)
  310. PROCEDURE Update*(intf: Interface; VAR res: Int): BOOLEAN;
  311. VAR b: BOOLEAN;
  312. BEGIN
  313. IF EnetBase.ThreadSafe THEN intf.dev.acquireRx; END;
  314. b := intf.dev.updateRx(intf.dev,res);
  315. IF EnetBase.ThreadSafe THEN intf.dev.releaseRx; END;
  316. IF ~b THEN RETURN FALSE; END;
  317. IF EnetBase.ThreadSafe THEN intf.dev.acquireTx; END;
  318. b := intf.dev.updateTx(intf.dev,res);
  319. IF EnetBase.ThreadSafe THEN intf.dev.releaseTx; END;
  320. IF ~b THEN RETURN FALSE; END;
  321. IF ~EnetBase.ProcessIntfRecvPackets(intf,res) OR ~EnetBase.ProcessIntfTasks(intf,res) THEN RETURN FALSE; END;
  322. res := 0;
  323. RETURN TRUE;
  324. END Update;
  325. (**
  326. Update the state of all network interfaces
  327. *)
  328. PROCEDURE UpdateAll*(VAR res: Int): BOOLEAN;
  329. VAR i, r: Int;
  330. BEGIN
  331. IF EnetBase.ThreadSafe THEN acquireIntfsRead; END;
  332. res := 0;
  333. FOR i := 0 TO numIntfs-1 DO
  334. IF ~Update(intfs[i],r) THEN res := r; END;
  335. END;
  336. IF EnetBase.ThreadSafe THEN releaseIntfsRead; END;
  337. RETURN res = 0;
  338. END UpdateAll;
  339. END EnetInterfaces.