2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Address Resolution Protocol routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
19 PNDIS_PACKET PrepareARPPacket(
22 UCHAR LinkAddressLength,
23 UCHAR ProtoAddressLength,
24 PVOID SenderLinkAddress,
25 PVOID SenderProtoAddress,
26 PVOID TargetLinkAddress,
27 PVOID TargetProtoAddress,
30 * FUNCTION: Prepares an ARP packet
32 * HardwareType = Hardware type (in network byte order)
33 * ProtocolType = Protocol type (in network byte order)
34 * LinkAddressLength = Length of link address fields
35 * ProtoAddressLength = Length of protocol address fields
36 * SenderLinkAddress = Sender's link address
37 * SenderProtoAddress = Sender's protocol address
38 * TargetLinkAddress = Target's link address (NULL if don't care)
39 * TargetProtoAddress = Target's protocol address
40 * Opcode = ARP opcode (in network byte order)
42 * Pointer to NDIS packet, NULL if there is not enough free resources
45 PNDIS_PACKET NdisPacket;
46 PNDIS_BUFFER NdisBuffer;
47 NDIS_STATUS NdisStatus;
52 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
54 /* Prepare ARP packet */
55 Size = MaxLLHeaderSize + sizeof(ARP_HEADER) +
56 2 * LinkAddressLength + /* Hardware address length */
57 2 * ProtoAddressLength; /* Protocol address length */
58 Size = MAX(Size, MinLLFrameSize);
60 DataBuffer = ExAllocatePool(NonPagedPool, Size);
64 /* Allocate NDIS packet */
65 NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
66 if (NdisStatus != NDIS_STATUS_SUCCESS) {
67 ExFreePool(DataBuffer);
71 /* Allocate NDIS buffer for maximum link level header and ARP packet */
72 NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,
74 if (NdisStatus != NDIS_STATUS_SUCCESS) {
75 NdisFreePacket(NdisPacket);
76 ExFreePool(DataBuffer);
80 /* Link NDIS buffer into packet */
81 NdisChainBufferAtFront(NdisPacket, NdisBuffer);
82 RtlZeroMemory(DataBuffer, Size);
83 Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);
84 Header->HWType = HardwareType;
85 Header->ProtoType = ProtocolType;
86 Header->HWAddrLen = LinkAddressLength;
87 Header->ProtoAddrLen = ProtoAddressLength;
88 Header->Opcode = Opcode; /* Already swapped */
89 DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
91 /* Our hardware address */
92 RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);
93 (ULONG_PTR)DataBuffer += LinkAddressLength;
95 /* Our protocol address */
96 RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
98 if (TargetLinkAddress) {
99 (ULONG_PTR)DataBuffer += ProtoAddressLength;
100 /* Target hardware address */
101 RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);
102 (ULONG_PTR)DataBuffer += LinkAddressLength;
104 /* Don't care about target hardware address */
105 (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength);
107 /* Target protocol address */
108 RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);
114 VOID ARPTransmitComplete(
116 PNDIS_PACKET NdisPacket,
117 NDIS_STATUS NdisStatus)
119 * FUNCTION: ARP request transmit completion handler
121 * Context = Pointer to context information (IP_INTERFACE)
122 * Packet = Pointer to NDIS packet that was sent
123 * NdisStatus = NDIS status of operation
125 * This routine is called when an ARP request has been sent
128 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
130 FreeNdisPacket(NdisPacket);
136 PNET_TABLE_ENTRY NTE)
138 * FUNCTION: Creates an ARP request and transmits it on a network
140 * Address = Pointer to IP address to resolve
141 * NTE = Pointer to net table entru to use for transmitting request
143 * TRUE if the request was successfully sent, FALSE if not
146 PIP_INTERFACE Interface;
147 PNDIS_PACKET NdisPacket;
151 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
153 Interface = NTE->Interface;
155 switch (Address->Type) {
157 ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */
158 ProtoAddrLen = 4; /* Length of IPv4 address */
161 ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */
162 ProtoAddrLen = 16; /* Length of IPv6 address */
165 /* Should not happen */
169 NdisPacket = PrepareARPPacket(
170 WN2H(0x0001), /* FIXME: Ethernet only */
171 ProtoType, /* Protocol type */
172 (UCHAR)Interface->AddressLength, /* Hardware address length */
173 (UCHAR)ProtoAddrLen, /* Protocol address length */
174 Interface->Address, /* Sender's (local) hardware address */
175 &NTE->Address->Address, /* Sender's (local) protocol address */
176 NULL, /* Don't care */
177 &Address->Address, /* Target's (remote) protocol address */
178 ARP_OPCODE_REQUEST); /* ARP request */
180 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
182 (*Interface->Transmit)(Interface->Context, NdisPacket,
183 MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
193 * FUNCTION: Receives an ARP packet
195 * Context = Pointer to context information (IP_INTERFACE)
196 * Packet = Pointer to packet
201 PVOID SenderHWAddress;
202 PVOID SenderProtoAddress;
203 PVOID TargetProtoAddress;
205 PNEIGHBOR_CACHE_ENTRY NCE;
206 PNDIS_PACKET NdisPacket;
207 PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
209 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
211 Header = (PARP_HEADER)Packet->Header;
213 /* FIXME: Ethernet only */
214 if (WN2H(Header->HWType) != 1) {
215 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType)));
219 /* Check protocol type */
220 if (Header->ProtoType != ETYPE_IPv4) {
221 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
225 SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
226 SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
228 /* Check if we have the target protocol address */
230 TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
231 Header->ProtoAddrLen + Header->HWAddrLen);
233 Address = AddrBuildIPv4(*((PULONG)TargetProtoAddress));
234 ADE = IPLocateADE(Address, ADE_UNICAST);
236 TI_DbgPrint(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress)));
240 /* Check if we know the sender */
242 AddrInitIPv4(Address, *((PULONG)SenderProtoAddress));
243 NCE = NBLocateNeighbor(Address);
245 DereferenceObject(Address);
246 /* We know the sender. Update the hardware address
247 and state in our neighbor address cache */
248 NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
250 /* The packet had our protocol address as target. The sender
251 may want to communicate with us soon, so add his address
252 to our address cache */
253 NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,
254 Header->HWAddrLen, NUD_REACHABLE);
257 DereferenceObject(NCE)
259 if (Header->Opcode != ARP_OPCODE_REQUEST)
262 /* This is a request for our address. Swap the addresses and
263 send an ARP reply back to the sender */
264 NdisPacket = PrepareARPPacket(
265 Header->HWType, /* Hardware type */
266 Header->ProtoType, /* Protocol type */
267 (UCHAR)Interface->AddressLength, /* Hardware address length */
268 (UCHAR)Header->ProtoAddrLen, /* Protocol address length */
269 Interface->Address, /* Sender's (local) hardware address */
270 &ADE->Address->Address, /* Sender's (local) protocol address */
271 SenderHWAddress, /* Target's (remote) hardware address */
272 SenderProtoAddress, /* Target's (remote) protocol address */
273 ARP_OPCODE_REPLY); /* ARP reply */
275 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
276 (*Interface->Transmit)(Interface->Context,