ReactOS  0.4.13-dev-259-g5ca9c9c
arp.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS TCP/IP protocol driver
4  * FILE: datalink/arp.c
5  * PURPOSE: Address Resolution Protocol routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  * CSH 01/08-2000 Created
9  */
10 
11 #include "precomp.h"
12 
14  PIP_INTERFACE IF,
15  USHORT HardwareType,
16  USHORT ProtocolType,
17  UCHAR LinkAddressLength,
18  UCHAR ProtoAddressLength,
19  PVOID SenderLinkAddress,
20  PVOID SenderProtoAddress,
21  PVOID TargetLinkAddress,
22  PVOID TargetProtoAddress,
23  USHORT Opcode)
24 /*
25  * FUNCTION: Prepares an ARP packet
26  * ARGUMENTS:
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)
36  * RETURNS:
37  * Pointer to NDIS packet, NULL if there is not enough free resources
38  */
39 {
40  PNDIS_PACKET NdisPacket;
41  NDIS_STATUS NdisStatus;
43  PVOID DataBuffer;
44  ULONG Size, Contig;
45 
46  TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
47 
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);
53 
54  NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
55  if( !NT_SUCCESS(NdisStatus) ) return NULL;
56 
57  GetDataPtr( NdisPacket, 0, (PCHAR *)&DataBuffer, (PUINT)&Contig );
58  ASSERT(DataBuffer);
59 
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));
68 
69  /* Our hardware address */
70  RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);
71  DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength);
72 
73  /* Our protocol address */
74  RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
75 
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);
81  } else
82  /* Don't care about target hardware address */
83  DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength + LinkAddressLength);
84 
85  /* Target protocol address */
86  RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);
87 
88  return NdisPacket;
89 }
90 
91 
93  PVOID Context,
94  PNDIS_PACKET NdisPacket,
95  NDIS_STATUS NdisStatus)
96 /*
97  * FUNCTION: ARP request transmit completion handler
98  * ARGUMENTS:
99  * Context = Pointer to context information (IP_INTERFACE)
100  * Packet = Pointer to NDIS packet that was sent
101  * NdisStatus = NDIS status of operation
102  * NOTES:
103  * This routine is called when an ARP request has been sent
104  */
105 {
106  TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
107  FreeNdisPacket(NdisPacket);
108 }
109 
110 
113 /*
114  * FUNCTION: Creates an ARP request and transmits it on a network
115  * ARGUMENTS:
116  * Address = Pointer to IP address to resolve
117  * RETURNS:
118  * TRUE if the request was successfully sent, FALSE if not
119  */
120 {
121  PNDIS_PACKET NdisPacket;
122  UCHAR ProtoAddrLen;
124 
125  TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
126 
127  /* If Address is NULL then the caller wants an
128  * gratuitous ARP packet sent */
129  if (!Address)
130  Address = &Interface->Unicast;
131 
132  switch (Address->Type) {
133  case IP_ADDRESS_V4:
134  ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */
135  ProtoAddrLen = 4; /* Length of IPv4 address */
136  break;
137  case IP_ADDRESS_V6:
138  ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */
139  ProtoAddrLen = 16; /* Length of IPv6 address */
140  break;
141  default:
142  TI_DbgPrint(DEBUG_ARP,("Bad Address Type %x\n", Address->Type));
143  DbgBreakPoint();
144  /* Should not happen */
145  return FALSE;
146  }
147 
148  NdisPacket = PrepareARPPacket(
149  Interface,
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 */
159 
160  if( !NdisPacket ) return FALSE;
161 
162  ASSERT_KM_POINTER(NdisPacket);
163  ASSERT_KM_POINTER(PC(NdisPacket));
164  PC(NdisPacket)->DLComplete = ARPTransmitComplete;
165 
166  TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
167 
168  (*Interface->Transmit)(Interface->Context, NdisPacket,
169  0, NULL, LAN_PROTO_ARP);
170 
171  return TRUE;
172 }
173 
174 
176  PVOID Context,
178 /*
179  * FUNCTION: Receives an ARP packet
180  * ARGUMENTS:
181  * Context = Pointer to context information (IP_INTERFACE)
182  * Packet = Pointer to packet
183  */
184 {
186  IP_ADDRESS SrcAddress;
187  IP_ADDRESS DstAddress;
188  PCHAR SenderHWAddress, SenderProtoAddress, TargetProtoAddress;
190  PNDIS_PACKET NdisPacket;
193  PCHAR DataBuffer;
194 
195  PAGED_CODE();
196 
197  TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
198 
200  sizeof(ARP_HEADER),
202  if (!Packet->Header)
203  {
204  TI_DbgPrint(DEBUG_ARP, ("Unable to allocate header buffer\n"));
205  Packet->Free(Packet);
206  return;
207  }
208  Packet->MappedHeader = FALSE;
209 
211  Packet->NdisPacket,
212  Packet->Position,
213  sizeof(ARP_HEADER));
214  if (BytesCopied != sizeof(ARP_HEADER))
215  {
216  TI_DbgPrint(DEBUG_ARP, ("Unable to copy in header buffer\n"));
217  Packet->Free(Packet);
218  return;
219  }
220 
221  Header = (PARP_HEADER)Packet->Header;
222 
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);
227  return;
228  }
229 
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);
234  return;
235  }
236 
237  DataSize = (2 * Header->HWAddrLen) + (2 * Header->ProtoAddrLen);
238  DataBuffer = ExAllocatePool(PagedPool,
239  DataSize);
240  if (!DataBuffer)
241  {
242  TI_DbgPrint(DEBUG_ARP, ("Unable to allocate data buffer\n"));
243  Packet->Free(Packet);
244  return;
245  }
246 
247  BytesCopied = CopyPacketToBuffer(DataBuffer,
248  Packet->NdisPacket,
249  Packet->Position + sizeof(ARP_HEADER),
250  DataSize);
251  if (BytesCopied != DataSize)
252  {
253  TI_DbgPrint(DEBUG_ARP, ("Unable to copy in data buffer\n"));
254  ExFreePool(DataBuffer);
255  Packet->Free(Packet);
256  return;
257  }
258 
259  SenderHWAddress = (PVOID)(DataBuffer);
260  SenderProtoAddress = (PVOID)(SenderHWAddress + Header->HWAddrLen);
261  TargetProtoAddress = (PVOID)(SenderProtoAddress + Header->ProtoAddrLen + Header->HWAddrLen);
262 
263  AddrInitIPv4(&DstAddress, *((PULONG)TargetProtoAddress));
264  if (!AddrIsEqual(&DstAddress, &Interface->Unicast))
265  {
266  ExFreePool(DataBuffer);
267  Packet->Free(Packet);
268  return;
269  }
270 
271  AddrInitIPv4(&SrcAddress, *((PULONG)SenderProtoAddress));
272 
273  /* Check if we know the sender */
274  NCE = NBLocateNeighbor(&SrcAddress, Interface);
275  if (NCE) {
276  /* We know the sender. Update the hardware address
277  and state in our neighbor address cache */
278  NBUpdateNeighbor(NCE, SenderHWAddress, 0);
279  } else {
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);
285  }
286 
287  if (Header->Opcode != ARP_OPCODE_REQUEST)
288  {
289  ExFreePool(DataBuffer);
290  Packet->Free(Packet);
291  return;
292  }
293 
294  /* This is a request for our address. Swap the addresses and
295  send an ARP reply back to the sender */
296  NdisPacket = PrepareARPPacket(
297  Interface,
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 */
307  if (NdisPacket) {
308  PC(NdisPacket)->DLComplete = ARPTransmitComplete;
309  (*Interface->Transmit)(Interface->Context,
310  NdisPacket,
311  0,
312  SenderHWAddress,
313  LAN_PROTO_ARP);
314  }
315 
316  ExFreePool(DataBuffer);
317  Packet->Free(Packet);
318 }
319 
320 /* EOF */
signed char * PCHAR
Definition: retypes.h:7
#define TI_DbgPrint(_t_, _x_)
Definition: debug.h:45
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
_In_ PVOID _In_ ULONG Opcode
Definition: hubbusif.h:330
PNDIS_PACKET PrepareARPPacket(PIP_INTERFACE IF, USHORT HardwareType, USHORT ProtocolType, UCHAR LinkAddressLength, UCHAR ProtoAddressLength, PVOID SenderLinkAddress, PVOID SenderProtoAddress, PVOID TargetLinkAddress, PVOID TargetProtoAddress, USHORT Opcode)
Definition: arp.c:13
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1548
Definition: neighbor.h:28
void GetDataPtr(PNDIS_PACKET Packet, UINT Offset, PCHAR *DataOut, PUINT Size)
Definition: routines.c:65
#define ETYPE_IPv6
Definition: lan.h:122
struct _IP_INTERFACE * PIP_INTERFACE
struct ARP_HEADER ARP_HEADER
#define FreeNdisPacket(x)
Definition: memtrack.h:8
PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(PIP_ADDRESS Address, PIP_INTERFACE Interface)
Definition: neighbor.c:417
void DbgBreakPoint()
Definition: mach.c:558
UINT MinFrameSize
Definition: ip.h:156
#define PAGED_CODE()
Definition: video.h:57
VOID ARPReceive(PVOID Context, PIP_PACKET Packet)
Definition: arp.c:175
int NDIS_STATUS
Definition: ntddndis.h:445
VOID ARPTransmitComplete(PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus)
Definition: arp.c:92
uint32_t ULONG_PTR
Definition: typedefs.h:63
Definition: ip.h:23
ProtoType
Definition: netstat.c:29
#define IP_ADDRESS_V4
Definition: ip.h:32
Definition: Header.h:8
#define AllocatePacketWithBuffer(x, y, z)
Definition: memtrack.h:7
unsigned char BOOLEAN
_In_ UINT _In_ UINT _In_ PNDIS_PACKET _In_ UINT _Out_ PUINT BytesCopied
Definition: ndis.h:3167
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
#define LAN_PROTO_ARP
Definition: lan.h:128
#define PC(Packet)
Definition: ip.h:106
void * PVOID
Definition: retypes.h:9
#define IP_ADDRESS_V6
Definition: ip.h:33
BOOLEAN ARPTransmit(PIP_ADDRESS Address, PVOID LinkAddress, PIP_INTERFACE Interface)
Definition: arp.c:111
VOID NBUpdateNeighbor(PNEIGHBOR_CACHE_ENTRY NCE, PVOID LinkAddress, UCHAR State)
Definition: neighbor.c:346
IN PVOID IN PVOID IN USHORT IN USHORT IN PINTERFACE Interface
Definition: pci.h:359
#define ARP_COMPLETE_TIMEOUT
Definition: neighbor.h:52
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define AddrInitIPv4(IPAddress, RawAddress)
Definition: address.h:16
#define ETYPE_IPv4
Definition: lan.h:121
#define WN2H(w)
Definition: addrconv.c:35
#define ASSERT_KM_POINTER(_x)
Definition: debug.h:74
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
BOOLEAN AddrIsEqual(PIP_ADDRESS Address1, PIP_ADDRESS Address2)
Definition: address.c:221
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(PIP_INTERFACE Interface, PIP_ADDRESS Address, PVOID LinkAddress, UINT LinkAddressLength, UCHAR Type, UINT EventTimer)
Definition: neighbor.c:273
#define ARP_OPCODE_REPLY
Definition: arp.h:24
T MAX(T a, T b)
Definition: polytest.cpp:85
Definition: arp.h:10
unsigned short USHORT
Definition: pedump.c:61
UINT CopyPacketToBuffer(PUCHAR DstData, PNDIS_PACKET SrcPacket, UINT SrcOffset, UINT Length)
Definition: buffer.c:170
#define ARP_OPCODE_REQUEST
Definition: arp.h:23
UINT HeaderSize
Definition: ip.h:155
unsigned int * PULONG
Definition: retypes.h:1
#define DEBUG_ARP
Definition: debug.h:25
struct ARP_HEADER * PARP_HEADER
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
Definition: ip.h:77
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
#define PACKET_BUFFER_TAG
Definition: tags.h:27
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
unsigned int * PUINT
Definition: ndis.h:50