arp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. arp.c
  5. Abstract:
  6. This module implements support for the Address Resolution Protocol, which
  7. translates network layer addresses (such as IP addresses) to physical
  8. addresses (such as MAC addresses).
  9. Author:
  10. Evan Green 5-Apr-2013
  11. Environment:
  12. Kernel
  13. --*/
  14. //
  15. // ------------------------------------------------------------------- Includes
  16. //
  17. //
  18. // Network layer drivers are supposed to be able to stand on their own (i.e. be
  19. // able to be implemented outside the core net library). For the builtin ones,
  20. // avoid including netcore.h, but still redefine those functions that would
  21. // otherwise generate imports.
  22. //
  23. #define NET_API __DLLEXPORT
  24. #include <minoca/kernel/driver.h>
  25. #include <minoca/net/netdrv.h>
  26. #include <minoca/net/ip4.h>
  27. #include "ethernet.h"
  28. //
  29. // ---------------------------------------------------------------- Definitions
  30. //
  31. #define ARP_HARDWARE_TYPE_ETHERNET 1
  32. #define ARP_OPERATION_REQUEST 1
  33. #define ARP_OPERATION_REPLY 2
  34. //
  35. // Define the packet size for Ethernet + IPv4 requests.
  36. //
  37. #define ARP_ETHERNET_IP4_SIZE 28
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. /*++
  42. Structure Description:
  43. This structure defines the structure of an ARP packet. After the members of
  44. the structure comes the sender hardware address, sender protocol address,
  45. target hardware address, and optional target protocol address. The size of
  46. these fields depends on the lengths defined in the beginning of the packet.
  47. Members:
  48. HardwareType - Stores the link protocol type. Ethernet is 1.
  49. ProtocolType - Stores the network protocol for which the ARP request is
  50. intended (an EtherType number). IPv4 is 0x0800.
  51. HardwareAddressLength - Stores the length of a hardware address. Ethernet
  52. addresses are 6 bytes.
  53. ProtocolAddressLength - Stores the length of the protocol address. IPv4
  54. addresses are 4 bytes.
  55. Operation - Stores the operation code for the ARP packet. 1 is request and
  56. 2 is reply.
  57. SenderHardwareAddress - Stores the media address of the sender.
  58. SenderProtocolAddress - Stores the internetwork address of the sender.
  59. TargetHardwareAddress - Stores the media address of the intended receiver.
  60. TargetProtocolAddress - Storse the internetwork address of the intended
  61. receiver.
  62. --*/
  63. typedef struct _ARP_PACKET {
  64. USHORT HardwareType;
  65. USHORT ProtocolType;
  66. UCHAR HardwareAddressLength;
  67. UCHAR ProtocolAddressLength;
  68. USHORT Operation;
  69. } PACKED ARP_PACKET, *PARP_PACKET;
  70. //
  71. // ----------------------------------------------- Internal Function Prototypes
  72. //
  73. KSTATUS
  74. NetpArpInitializeLink (
  75. PNET_LINK Link
  76. );
  77. VOID
  78. NetpArpDestroyLink (
  79. PNET_LINK Link
  80. );
  81. VOID
  82. NetpArpProcessReceivedData (
  83. PNET_LINK Link,
  84. PNET_PACKET_BUFFER Packet
  85. );
  86. ULONG
  87. NetpArpPrintAddress (
  88. PNETWORK_ADDRESS Address,
  89. PSTR Buffer,
  90. ULONG BufferLength
  91. );
  92. KSTATUS
  93. NetpArpSendReply (
  94. PNET_LINK Link,
  95. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  96. PNETWORK_ADDRESS DestinationNetworkAddress,
  97. PNETWORK_ADDRESS DestinationPhysicalAddress
  98. );
  99. //
  100. // -------------------------------------------------------------------- Globals
  101. //
  102. BOOL NetArpDebug = FALSE;
  103. //
  104. // ------------------------------------------------------------------ Functions
  105. //
  106. VOID
  107. NetpArpInitialize (
  108. VOID
  109. )
  110. /*++
  111. Routine Description:
  112. This routine initializes support for ARP packets.
  113. Arguments:
  114. None.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. NET_NETWORK_ENTRY NetworkEntry;
  120. KSTATUS Status;
  121. if (NetArpDebug == FALSE) {
  122. NetArpDebug = NetGetGlobalDebugFlag();
  123. }
  124. //
  125. // Register the ARP handlers with the core networking library.
  126. //
  127. RtlZeroMemory(&NetworkEntry, sizeof(NET_NETWORK_ENTRY));
  128. NetworkEntry.Domain = NetDomainArp;
  129. NetworkEntry.ParentProtocolNumber = ARP_PROTOCOL_NUMBER;
  130. NetworkEntry.Interface.InitializeLink = NetpArpInitializeLink;
  131. NetworkEntry.Interface.DestroyLink = NetpArpDestroyLink;
  132. NetworkEntry.Interface.ProcessReceivedData = NetpArpProcessReceivedData;
  133. NetworkEntry.Interface.PrintAddress = NetpArpPrintAddress;
  134. Status = NetRegisterNetworkLayer(&NetworkEntry, NULL);
  135. if (!KSUCCESS(Status)) {
  136. ASSERT(FALSE);
  137. }
  138. return;
  139. }
  140. KSTATUS
  141. NetpArpSendRequest (
  142. PNET_LINK Link,
  143. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  144. PNETWORK_ADDRESS QueryAddress
  145. )
  146. /*++
  147. Routine Description:
  148. This routine allocates, assembles, and sends an ARP request to translate
  149. the given network address into a physical address. This routine returns
  150. as soon as the ARP request is successfully queued for transmission.
  151. Arguments:
  152. Link - Supplies a pointer to the link to send the request down.
  153. LinkAddress - Supplies the source address of the request.
  154. QueryAddress - Supplies the network address to ask about.
  155. Return Value:
  156. STATUS_SUCCESS if the request was successfully sent off.
  157. STATUS_INSUFFICIENT_RESOURCES if the transmission buffer couldn't be
  158. allocated.
  159. Other errors on other failures.
  160. --*/
  161. {
  162. PARP_PACKET ArpPacket;
  163. PUCHAR CurrentPointer;
  164. ULONG Flags;
  165. BOOL LockHeld;
  166. PNET_PACKET_BUFFER NetPacket;
  167. NET_PACKET_LIST NetPacketList;
  168. PNET_DATA_LINK_SEND Send;
  169. KSTATUS Status;
  170. ASSERT(KeGetRunLevel() == RunLevelLow);
  171. NET_INITIALIZE_PACKET_LIST(&NetPacketList);
  172. LockHeld = FALSE;
  173. //
  174. // Allocate a buffer to send down to the network card.
  175. //
  176. Flags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
  177. NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS |
  178. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  179. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  180. ArpPacket = NULL;
  181. Status = NetAllocateBuffer(0,
  182. ARP_ETHERNET_IP4_SIZE,
  183. 0,
  184. Link,
  185. Flags,
  186. &NetPacket);
  187. if (!KSUCCESS(Status)) {
  188. goto ArpSendRequestEnd;
  189. }
  190. NET_ADD_PACKET_TO_LIST(NetPacket, &NetPacketList);
  191. ArpPacket = NetPacket->Buffer + NetPacket->DataOffset;
  192. ArpPacket->HardwareType = CPU_TO_NETWORK16(ARP_HARDWARE_TYPE_ETHERNET);
  193. ASSERT(QueryAddress->Domain == NetDomainIp4);
  194. ArpPacket->ProtocolType = CPU_TO_NETWORK16(IP4_PROTOCOL_NUMBER);
  195. ArpPacket->ProtocolAddressLength = IP4_ADDRESS_SIZE;
  196. ArpPacket->HardwareAddressLength = ETHERNET_ADDRESS_SIZE;
  197. ArpPacket->Operation = CPU_TO_NETWORK16(ARP_OPERATION_REQUEST);
  198. //
  199. // Copy the sender's hardware address.
  200. //
  201. CurrentPointer = (PUCHAR)(ArpPacket + 1);
  202. RtlCopyMemory(CurrentPointer,
  203. &(LinkAddress->PhysicalAddress.Address),
  204. ETHERNET_ADDRESS_SIZE);
  205. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  206. //
  207. // Make sure the link is still configured before copying its network
  208. // addresses. This assumes that the physical address does not change for
  209. // the lifetime of a link address entry, configured or not.
  210. //
  211. KeAcquireQueuedLock(Link->QueuedLock);
  212. LockHeld = TRUE;
  213. if (LinkAddress->Configured == FALSE) {
  214. Status = STATUS_NO_NETWORK_CONNECTION;
  215. goto ArpSendRequestEnd;
  216. }
  217. //
  218. // Copy the sender's network address.
  219. //
  220. ASSERT(LinkAddress->Address.Domain == NetDomainIp4);
  221. RtlCopyMemory(CurrentPointer,
  222. &(LinkAddress->Address.Address),
  223. IP4_ADDRESS_SIZE);
  224. CurrentPointer += IP4_ADDRESS_SIZE;
  225. KeReleaseQueuedLock(Link->QueuedLock);
  226. LockHeld = FALSE;
  227. //
  228. // Zero out the target hardware address.
  229. //
  230. RtlZeroMemory(CurrentPointer, ETHERNET_ADDRESS_SIZE);
  231. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  232. //
  233. // Copy the target network address.
  234. //
  235. RtlCopyMemory(CurrentPointer, &(QueryAddress->Address), IP4_ADDRESS_SIZE);
  236. CurrentPointer += IP4_ADDRESS_SIZE;
  237. ASSERT(((UINTN)CurrentPointer - (UINTN)ArpPacket) == ARP_ETHERNET_IP4_SIZE);
  238. //
  239. // Debug print the request.
  240. //
  241. if (NetArpDebug != FALSE) {
  242. RtlDebugPrint("ARP TX: Who has ");
  243. NetDebugPrintAddress(QueryAddress);
  244. RtlDebugPrint("? Tell ");
  245. NetDebugPrintAddress(&(LinkAddress->PhysicalAddress));
  246. RtlDebugPrint("\n");
  247. }
  248. //
  249. // Send the request off to the link.
  250. //
  251. Send = Link->DataLinkEntry->Interface.Send;
  252. Status = Send(Link->DataLinkContext,
  253. &NetPacketList,
  254. &(LinkAddress->PhysicalAddress),
  255. NULL,
  256. ARP_PROTOCOL_NUMBER);
  257. if (!KSUCCESS(Status)) {
  258. goto ArpSendRequestEnd;
  259. }
  260. ArpSendRequestEnd:
  261. if (LockHeld != FALSE) {
  262. KeReleaseQueuedLock(Link->QueuedLock);
  263. }
  264. if (!KSUCCESS(Status)) {
  265. NetDestroyBufferList(&NetPacketList);
  266. }
  267. return Status;
  268. }
  269. //
  270. // --------------------------------------------------------- Internal Functions
  271. //
  272. KSTATUS
  273. NetpArpInitializeLink (
  274. PNET_LINK Link
  275. )
  276. /*++
  277. Routine Description:
  278. This routine initializes any pieces of information needed by the network
  279. layer for a new link.
  280. Arguments:
  281. Link - Supplies a pointer to the new link.
  282. Return Value:
  283. Status code.
  284. --*/
  285. {
  286. return STATUS_SUCCESS;
  287. }
  288. VOID
  289. NetpArpDestroyLink (
  290. PNET_LINK Link
  291. )
  292. /*++
  293. Routine Description:
  294. This routine allows the network layer to tear down any state before a link
  295. is destroyed.
  296. Arguments:
  297. Link - Supplies a pointer to the dying link.
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. return;
  303. }
  304. VOID
  305. NetpArpProcessReceivedData (
  306. PNET_LINK Link,
  307. PNET_PACKET_BUFFER Packet
  308. )
  309. /*++
  310. Routine Description:
  311. This routine is called to process a received packet.
  312. Arguments:
  313. Link - Supplies a pointer to the link that received the packet.
  314. Packet - Supplies a pointer to a structure describing the incoming packet.
  315. This structure may be used as a scratch space while this routine
  316. executes and the packet travels up the stack, but will not be accessed
  317. after this routine returns.
  318. Return Value:
  319. None. When the function returns, the memory associated with the packet may
  320. be reclaimed and reused.
  321. --*/
  322. {
  323. PARP_PACKET ArpPacket;
  324. PUCHAR CurrentPointer;
  325. PNET_LINK_ADDRESS_ENTRY LinkAddressEntry;
  326. USHORT Operation;
  327. ULONG PacketSize;
  328. NETWORK_ADDRESS SenderNetworkAddress;
  329. NETWORK_ADDRESS SenderPhysicalAddress;
  330. KSTATUS Status;
  331. NETWORK_ADDRESS TargetNetworkAddress;
  332. NETWORK_ADDRESS TargetPhysicalAddress;
  333. //
  334. // Skip packets that are too small.
  335. //
  336. ArpPacket = (PARP_PACKET)(Packet->Buffer + Packet->DataOffset);
  337. PacketSize = Packet->FooterOffset - Packet->DataOffset;
  338. if ((PacketSize < sizeof(ARP_PACKET)) ||
  339. (PacketSize <
  340. (sizeof(ARP_PACKET) + (2 * ArpPacket->ProtocolAddressLength) +
  341. (2 * ArpPacket->HardwareAddressLength)))) {
  342. return;
  343. }
  344. //
  345. // Skip packets that are not Ethernet + IPv4.
  346. //
  347. if ((NETWORK_TO_CPU16(ArpPacket->HardwareType) !=
  348. ARP_HARDWARE_TYPE_ETHERNET) ||
  349. (ArpPacket->HardwareAddressLength != ETHERNET_ADDRESS_SIZE)) {
  350. return;
  351. }
  352. if ((NETWORK_TO_CPU16(ArpPacket->ProtocolType) != IP4_PROTOCOL_NUMBER) ||
  353. (ArpPacket->ProtocolAddressLength != IP4_ADDRESS_SIZE)) {
  354. return;
  355. }
  356. //
  357. // Grab the sender and target network and physical addresses.
  358. //
  359. RtlZeroMemory(&SenderNetworkAddress, sizeof(NETWORK_ADDRESS));
  360. RtlZeroMemory(&SenderPhysicalAddress, sizeof(NETWORK_ADDRESS));
  361. RtlZeroMemory(&TargetNetworkAddress, sizeof(NETWORK_ADDRESS));
  362. RtlZeroMemory(&TargetPhysicalAddress, sizeof(NETWORK_ADDRESS));
  363. SenderPhysicalAddress.Domain = Link->DataLinkEntry->Domain;
  364. CurrentPointer = (PUCHAR)(ArpPacket + 1);
  365. RtlCopyMemory(&(SenderPhysicalAddress.Address),
  366. CurrentPointer,
  367. ETHERNET_ADDRESS_SIZE);
  368. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  369. SenderNetworkAddress.Domain = NetDomainIp4;
  370. RtlCopyMemory(&(SenderNetworkAddress.Address),
  371. CurrentPointer,
  372. IP4_ADDRESS_SIZE);
  373. CurrentPointer += IP4_ADDRESS_SIZE;
  374. TargetPhysicalAddress.Domain = Link->DataLinkEntry->Domain;
  375. RtlCopyMemory(&(TargetPhysicalAddress.Address),
  376. CurrentPointer,
  377. ETHERNET_ADDRESS_SIZE);
  378. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  379. TargetNetworkAddress.Domain = NetDomainIp4;
  380. RtlCopyMemory(&(TargetNetworkAddress.Address),
  381. CurrentPointer,
  382. IP4_ADDRESS_SIZE);
  383. Operation = NETWORK_TO_CPU16(ArpPacket->Operation);
  384. //
  385. // Handle request packets.
  386. //
  387. if (Operation == ARP_OPERATION_REQUEST) {
  388. if (NetArpDebug != FALSE) {
  389. RtlDebugPrint("ARP RX: Who has ");
  390. NetDebugPrintAddress(&TargetNetworkAddress);
  391. RtlDebugPrint("? Tell ");
  392. NetDebugPrintAddress(&SenderNetworkAddress);
  393. RtlDebugPrint(" (");
  394. NetDebugPrintAddress(&SenderPhysicalAddress);
  395. RtlDebugPrint(")\n");
  396. }
  397. Status = NetFindEntryForAddress(Link,
  398. &TargetNetworkAddress,
  399. FALSE,
  400. &LinkAddressEntry);
  401. if (!KSUCCESS(Status)) {
  402. return;
  403. }
  404. //
  405. // Requests themselves are translations. Remember this translation.
  406. //
  407. NetAddNetworkAddressTranslation(Link,
  408. &SenderNetworkAddress,
  409. &SenderPhysicalAddress);
  410. NetpArpSendReply(Link,
  411. LinkAddressEntry,
  412. &SenderNetworkAddress,
  413. &SenderPhysicalAddress);
  414. return;
  415. } else if (Operation != ARP_OPERATION_REPLY) {
  416. return;
  417. }
  418. //
  419. // Debug print the response.
  420. //
  421. if (NetArpDebug != FALSE) {
  422. RtlDebugPrint("ARP RX: ");
  423. NetDebugPrintAddress(&SenderNetworkAddress);
  424. RtlDebugPrint(" is at ");
  425. NetDebugPrintAddress(&SenderPhysicalAddress);
  426. RtlDebugPrint("\n");
  427. }
  428. //
  429. // Add the translation entry.
  430. //
  431. NetAddNetworkAddressTranslation(Link,
  432. &SenderNetworkAddress,
  433. &SenderPhysicalAddress);
  434. return;
  435. }
  436. ULONG
  437. NetpArpPrintAddress (
  438. PNETWORK_ADDRESS Address,
  439. PSTR Buffer,
  440. ULONG BufferLength
  441. )
  442. /*++
  443. Routine Description:
  444. This routine is called to convert a network address into a string, or
  445. determine the length of the buffer needed to convert an address into a
  446. string.
  447. Arguments:
  448. Address - Supplies an optional pointer to a network address to convert to
  449. a string.
  450. Buffer - Supplies an optional pointer where the string representation of
  451. the address will be returned.
  452. BufferLength - Supplies the length of the supplied buffer, in bytes.
  453. Return Value:
  454. Returns the maximum length of any address if no network address is
  455. supplied.
  456. Returns the actual length of the network address string if a network address
  457. was supplied, including the null terminator.
  458. --*/
  459. {
  460. //
  461. // There is no such thing as an ARP address. Everything is broadcast.
  462. //
  463. return 0;
  464. }
  465. KSTATUS
  466. NetpArpSendReply (
  467. PNET_LINK Link,
  468. PNET_LINK_ADDRESS_ENTRY LinkAddress,
  469. PNETWORK_ADDRESS DestinationNetworkAddress,
  470. PNETWORK_ADDRESS DestinationPhysicalAddress
  471. )
  472. /*++
  473. Routine Description:
  474. This routine allocates, assembles, and sends an ARP reply to communicate
  475. the physical address of one of the network addresses owned by this machine.
  476. This routine returns as soon as the ARP request is successfully queued for
  477. transmission.
  478. Arguments:
  479. Link - Supplies a pointer to the link to send the reply down.
  480. LinkAddress - Supplies the source address of the reply.
  481. DestinationNetworkAddress - Supplies a pointer to the network address to
  482. send the response to.
  483. DestinationPhysicalAddress - Supplies a pointer to the physical address to
  484. send the response to.
  485. Return Value:
  486. STATUS_SUCCESS if the request was successfully sent off.
  487. STATUS_INSUFFICIENT_RESOURCES if the transmission buffer couldn't be
  488. allocated.
  489. Other errors on other failures.
  490. --*/
  491. {
  492. PARP_PACKET ArpPacket;
  493. PUCHAR CurrentPointer;
  494. ULONG Flags;
  495. BOOL LockHeld;
  496. PNET_PACKET_BUFFER NetPacket;
  497. NET_PACKET_LIST NetPacketList;
  498. NETWORK_ADDRESS NetworkAddress;
  499. PNET_DATA_LINK_SEND Send;
  500. KSTATUS Status;
  501. LockHeld = FALSE;
  502. NET_INITIALIZE_PACKET_LIST(&NetPacketList);
  503. //
  504. // Allocate a buffer to send down to the network card.
  505. //
  506. Flags = NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_HEADERS |
  507. NET_ALLOCATE_BUFFER_FLAG_ADD_DEVICE_LINK_FOOTERS |
  508. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_HEADERS |
  509. NET_ALLOCATE_BUFFER_FLAG_ADD_DATA_LINK_FOOTERS;
  510. ArpPacket = NULL;
  511. Status = NetAllocateBuffer(0,
  512. ARP_ETHERNET_IP4_SIZE,
  513. 0,
  514. Link,
  515. Flags,
  516. &NetPacket);
  517. if (!KSUCCESS(Status)) {
  518. goto ArpSendReplyEnd;
  519. }
  520. NET_ADD_PACKET_TO_LIST(NetPacket, &NetPacketList);
  521. ArpPacket = NetPacket->Buffer + NetPacket->DataOffset;
  522. ArpPacket->HardwareType = CPU_TO_NETWORK16(ARP_HARDWARE_TYPE_ETHERNET);
  523. ASSERT(DestinationNetworkAddress->Domain == NetDomainIp4);
  524. ASSERT(DestinationPhysicalAddress->Domain == Link->DataLinkEntry->Domain);
  525. ArpPacket->ProtocolType = CPU_TO_NETWORK16(IP4_PROTOCOL_NUMBER);
  526. ArpPacket->ProtocolAddressLength = 4;
  527. ArpPacket->HardwareAddressLength = ETHERNET_ADDRESS_SIZE;
  528. ArpPacket->Operation = CPU_TO_NETWORK16(ARP_OPERATION_REPLY);
  529. //
  530. // Copy the sender's hardware address.
  531. //
  532. CurrentPointer = (PUCHAR)(ArpPacket + 1);
  533. RtlCopyMemory(CurrentPointer,
  534. &(LinkAddress->PhysicalAddress.Address),
  535. ETHERNET_ADDRESS_SIZE);
  536. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  537. //
  538. // Make sure the link is still configured before copying its network
  539. // addresses. This assumes that the physical address does not change for
  540. // the lifetime of a link address entry, configured or not.
  541. //
  542. KeAcquireQueuedLock(Link->QueuedLock);
  543. LockHeld = TRUE;
  544. if (LinkAddress->Configured == FALSE) {
  545. Status = STATUS_NO_NETWORK_CONNECTION;
  546. goto ArpSendReplyEnd;
  547. }
  548. //
  549. // Store the network address if debugging is enabled.
  550. //
  551. if (NetArpDebug != FALSE) {
  552. RtlCopyMemory(&NetworkAddress,
  553. &(LinkAddress->Address),
  554. sizeof(NETWORK_ADDRESS));
  555. }
  556. //
  557. // Copy the sender's network address.
  558. //
  559. ASSERT(LinkAddress->Address.Domain == NetDomainIp4);
  560. RtlCopyMemory(CurrentPointer,
  561. &(LinkAddress->Address.Address),
  562. IP4_ADDRESS_SIZE);
  563. CurrentPointer += IP4_ADDRESS_SIZE;
  564. KeReleaseQueuedLock(Link->QueuedLock);
  565. LockHeld = FALSE;
  566. //
  567. // Copy the target hardware address.
  568. //
  569. RtlCopyMemory(CurrentPointer,
  570. DestinationPhysicalAddress->Address,
  571. ETHERNET_ADDRESS_SIZE);
  572. CurrentPointer += ETHERNET_ADDRESS_SIZE;
  573. //
  574. // Copy the target network address.
  575. //
  576. RtlCopyMemory(CurrentPointer,
  577. DestinationNetworkAddress->Address,
  578. IP4_ADDRESS_SIZE);
  579. CurrentPointer += IP4_ADDRESS_SIZE;
  580. ASSERT(((UINTN)CurrentPointer - (UINTN)ArpPacket) == ARP_ETHERNET_IP4_SIZE);
  581. //
  582. // Debug print the request.
  583. //
  584. if (NetArpDebug != FALSE) {
  585. RtlDebugPrint("ARP TX: ");
  586. NetDebugPrintAddress(&NetworkAddress);
  587. RtlDebugPrint(" is at ");
  588. NetDebugPrintAddress(&(LinkAddress->PhysicalAddress));
  589. RtlDebugPrint(" (sent to ");
  590. NetDebugPrintAddress(DestinationNetworkAddress);
  591. RtlDebugPrint(" ");
  592. NetDebugPrintAddress(DestinationPhysicalAddress);
  593. RtlDebugPrint(")\n");
  594. }
  595. //
  596. // Send the request off to the link.
  597. //
  598. Send = Link->DataLinkEntry->Interface.Send;
  599. Status = Send(Link->DataLinkContext,
  600. &NetPacketList,
  601. &(LinkAddress->PhysicalAddress),
  602. DestinationPhysicalAddress,
  603. ARP_PROTOCOL_NUMBER);
  604. if (!KSUCCESS(Status)) {
  605. goto ArpSendReplyEnd;
  606. }
  607. ArpSendReplyEnd:
  608. if (LockHeld != FALSE) {
  609. KeReleaseQueuedLock(Link->QueuedLock);
  610. }
  611. if (!KSUCCESS(Status)) {
  612. NetDestroyBufferList(&NetPacketList);
  613. }
  614. return Status;
  615. }