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
13 PNDIS_PACKET
PrepareARPPacket(
17 UCHAR LinkAddressLength
,
18 UCHAR ProtoAddressLength
,
19 PVOID SenderLinkAddress
,
20 PVOID SenderProtoAddress
,
21 PVOID TargetLinkAddress
,
22 PVOID TargetProtoAddress
,
25 * FUNCTION: Prepares an ARP packet
27 * HardwareType = Hardware type (in network byte order)
28 * ProtocolType = Protocol type (in network byte order)
29 * LinkAddressLength = Length of link address fields
30 * ProtoAddressLength = Length of protocol address fields
31 * SenderLinkAddress = Sender's link address
32 * SenderProtoAddress = Sender's protocol address
33 * TargetLinkAddress = Target's link address (NULL if don't care)
34 * TargetProtoAddress = Target's protocol address
35 * Opcode = ARP opcode (in network byte order)
37 * Pointer to NDIS packet, NULL if there is not enough free resources
40 PNDIS_PACKET NdisPacket
;
41 NDIS_STATUS NdisStatus
;
46 TI_DbgPrint(DEBUG_ARP
, ("Called.\n"));
48 /* Prepare ARP packet */
49 Size
= sizeof(ARP_HEADER
) +
50 2 * LinkAddressLength
+ /* Hardware address length */
51 2 * ProtoAddressLength
; /* Protocol address length */
52 Size
= MAX(Size
, IF
->MinFrameSize
- IF
->HeaderSize
);
54 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
, Size
);
55 if( !NT_SUCCESS(NdisStatus
) ) return NULL
;
57 GetDataPtr( NdisPacket
, 0, (PCHAR
*)&DataBuffer
, (PUINT
)&Contig
);
60 RtlZeroMemory(DataBuffer
, Size
);
61 Header
= (PARP_HEADER
)((ULONG_PTR
)DataBuffer
);
62 Header
->HWType
= HardwareType
;
63 Header
->ProtoType
= ProtocolType
;
64 Header
->HWAddrLen
= LinkAddressLength
;
65 Header
->ProtoAddrLen
= ProtoAddressLength
;
66 Header
->Opcode
= Opcode
; /* Already swapped */
67 DataBuffer
= (PVOID
)((ULONG_PTR
)Header
+ sizeof(ARP_HEADER
));
69 /* Our hardware address */
70 RtlCopyMemory(DataBuffer
, SenderLinkAddress
, LinkAddressLength
);
71 DataBuffer
= (PVOID
)((ULONG_PTR
)DataBuffer
+ LinkAddressLength
);
73 /* Our protocol address */
74 RtlCopyMemory(DataBuffer
, SenderProtoAddress
, ProtoAddressLength
);
76 if (TargetLinkAddress
) {
77 DataBuffer
= (PVOID
)((ULONG_PTR
)DataBuffer
+ ProtoAddressLength
);
78 /* Target hardware address */
79 RtlCopyMemory(DataBuffer
, TargetLinkAddress
, LinkAddressLength
);
80 DataBuffer
= (PVOID
)((ULONG_PTR
)DataBuffer
+ LinkAddressLength
);
82 /* Don't care about target hardware address */
83 DataBuffer
= (PVOID
)((ULONG_PTR
)DataBuffer
+ ProtoAddressLength
+ LinkAddressLength
);
85 /* Target protocol address */
86 RtlCopyMemory(DataBuffer
, TargetProtoAddress
, ProtoAddressLength
);
92 VOID
ARPTransmitComplete(
94 PNDIS_PACKET NdisPacket
,
95 NDIS_STATUS NdisStatus
)
97 * FUNCTION: ARP request transmit completion handler
99 * Context = Pointer to context information (IP_INTERFACE)
100 * Packet = Pointer to NDIS packet that was sent
101 * NdisStatus = NDIS status of operation
103 * This routine is called when an ARP request has been sent
106 TI_DbgPrint(DEBUG_ARP
, ("Called.\n"));
107 FreeNdisPacket(NdisPacket
);
111 BOOLEAN
ARPTransmit(PIP_ADDRESS Address
, PVOID LinkAddress
,
112 PIP_INTERFACE Interface
)
114 * FUNCTION: Creates an ARP request and transmits it on a network
116 * Address = Pointer to IP address to resolve
118 * TRUE if the request was successfully sent, FALSE if not
121 PNDIS_PACKET NdisPacket
;
125 TI_DbgPrint(DEBUG_ARP
, ("Called.\n"));
127 /* If Address is NULL then the caller wants an
128 * gratuitous ARP packet sent */
130 Address
= &Interface
->Unicast
;
132 switch (Address
->Type
) {
134 ProtoType
= (USHORT
)ETYPE_IPv4
; /* IPv4 */
135 ProtoAddrLen
= 4; /* Length of IPv4 address */
138 ProtoType
= (USHORT
)ETYPE_IPv6
; /* IPv6 */
139 ProtoAddrLen
= 16; /* Length of IPv6 address */
142 TI_DbgPrint(DEBUG_ARP
,("Bad Address Type %x\n", Address
->Type
));
144 /* Should not happen */
148 NdisPacket
= PrepareARPPacket(
150 WN2H(0x0001), /* FIXME: Ethernet only */
151 ProtoType
, /* Protocol type */
152 (UCHAR
)Interface
->AddressLength
, /* Hardware address length */
153 (UCHAR
)ProtoAddrLen
, /* Protocol address length */
154 Interface
->Address
, /* Sender's (local) hardware address */
155 &Interface
->Unicast
.Address
.IPv4Address
,/* Sender's (local) protocol address */
156 LinkAddress
, /* Target's (remote) hardware address */
157 &Address
->Address
.IPv4Address
, /* Target's (remote) protocol address */
158 ARP_OPCODE_REQUEST
); /* ARP request */
160 if( !NdisPacket
) return FALSE
;
162 ASSERT_KM_POINTER(NdisPacket
);
163 ASSERT_KM_POINTER(PC(NdisPacket
));
164 PC(NdisPacket
)->DLComplete
= ARPTransmitComplete
;
166 TI_DbgPrint(DEBUG_ARP
,("Sending ARP Packet\n"));
168 (*Interface
->Transmit
)(Interface
->Context
, NdisPacket
,
169 0, NULL
, LAN_PROTO_ARP
);
179 * FUNCTION: Receives an ARP packet
181 * Context = Pointer to context information (IP_INTERFACE)
182 * Packet = Pointer to packet
186 IP_ADDRESS SrcAddress
;
187 IP_ADDRESS DstAddress
;
188 PCHAR SenderHWAddress
, SenderProtoAddress
, TargetProtoAddress
;
189 PNEIGHBOR_CACHE_ENTRY NCE
;
190 PNDIS_PACKET NdisPacket
;
191 PIP_INTERFACE Interface
= (PIP_INTERFACE
)Context
;
192 ULONG BytesCopied
, DataSize
;
197 TI_DbgPrint(DEBUG_ARP
, ("Called.\n"));
199 Packet
->Header
= ExAllocatePoolWithTag(PagedPool
,
204 TI_DbgPrint(DEBUG_ARP
, ("Unable to allocate header buffer\n"));
205 Packet
->Free(Packet
);
208 Packet
->MappedHeader
= FALSE
;
210 BytesCopied
= CopyPacketToBuffer((PCHAR
)Packet
->Header
,
214 if (BytesCopied
!= sizeof(ARP_HEADER
))
216 TI_DbgPrint(DEBUG_ARP
, ("Unable to copy in header buffer\n"));
217 Packet
->Free(Packet
);
221 Header
= (PARP_HEADER
)Packet
->Header
;
223 /* FIXME: Ethernet only */
224 if (WN2H(Header
->HWType
) != 1) {
225 TI_DbgPrint(DEBUG_ARP
, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header
->HWType
)));
226 Packet
->Free(Packet
);
230 /* Check protocol type */
231 if (Header
->ProtoType
!= ETYPE_IPv4
) {
232 TI_DbgPrint(DEBUG_ARP
, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header
->ProtoType
)));
233 Packet
->Free(Packet
);
237 DataSize
= (2 * Header
->HWAddrLen
) + (2 * Header
->ProtoAddrLen
);
238 DataBuffer
= ExAllocatePool(PagedPool
,
242 TI_DbgPrint(DEBUG_ARP
, ("Unable to allocate data buffer\n"));
243 Packet
->Free(Packet
);
247 BytesCopied
= CopyPacketToBuffer(DataBuffer
,
249 Packet
->Position
+ sizeof(ARP_HEADER
),
251 if (BytesCopied
!= DataSize
)
253 TI_DbgPrint(DEBUG_ARP
, ("Unable to copy in data buffer\n"));
254 ExFreePool(DataBuffer
);
255 Packet
->Free(Packet
);
259 SenderHWAddress
= (PVOID
)(DataBuffer
);
260 SenderProtoAddress
= (PVOID
)(SenderHWAddress
+ Header
->HWAddrLen
);
261 TargetProtoAddress
= (PVOID
)(SenderProtoAddress
+ Header
->ProtoAddrLen
+ Header
->HWAddrLen
);
263 AddrInitIPv4(&DstAddress
, *((PULONG
)TargetProtoAddress
));
264 if (!AddrIsEqual(&DstAddress
, &Interface
->Unicast
))
266 ExFreePool(DataBuffer
);
267 Packet
->Free(Packet
);
271 AddrInitIPv4(&SrcAddress
, *((PULONG
)SenderProtoAddress
));
273 /* Check if we know the sender */
274 NCE
= NBLocateNeighbor(&SrcAddress
, Interface
);
276 /* We know the sender. Update the hardware address
277 and state in our neighbor address cache */
278 NBUpdateNeighbor(NCE
, SenderHWAddress
, 0);
280 /* The packet had our protocol address as target. The sender
281 may want to communicate with us soon, so add his address
282 to our address cache */
283 NBAddNeighbor(Interface
, &SrcAddress
, SenderHWAddress
,
284 Header
->HWAddrLen
, 0, ARP_COMPLETE_TIMEOUT
);
287 if (Header
->Opcode
!= ARP_OPCODE_REQUEST
)
289 ExFreePool(DataBuffer
);
290 Packet
->Free(Packet
);
294 /* This is a request for our address. Swap the addresses and
295 send an ARP reply back to the sender */
296 NdisPacket
= PrepareARPPacket(
298 Header
->HWType
, /* Hardware type */
299 Header
->ProtoType
, /* Protocol type */
300 (UCHAR
)Interface
->AddressLength
, /* Hardware address length */
301 (UCHAR
)Header
->ProtoAddrLen
, /* Protocol address length */
302 Interface
->Address
, /* Sender's (local) hardware address */
303 &Interface
->Unicast
.Address
.IPv4Address
,/* Sender's (local) protocol address */
304 SenderHWAddress
, /* Target's (remote) hardware address */
305 SenderProtoAddress
, /* Target's (remote) protocol address */
306 ARP_OPCODE_REPLY
); /* ARP reply */
308 PC(NdisPacket
)->DLComplete
= ARPTransmitComplete
;
309 (*Interface
->Transmit
)(Interface
->Context
,
316 ExFreePool(DataBuffer
);
317 Packet
->Free(Packet
);