e97c2015be05639375e0ba8c68a0526d9ec82fb9
[reactos.git] / reactos / drivers / lib / ip / network / arp.c
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
13 PNDIS_PACKET PrepareARPPacket(
14 USHORT HardwareType,
15 USHORT ProtocolType,
16 UCHAR LinkAddressLength,
17 UCHAR ProtoAddressLength,
18 PVOID SenderLinkAddress,
19 PVOID SenderProtoAddress,
20 PVOID TargetLinkAddress,
21 PVOID TargetProtoAddress,
22 USHORT Opcode)
23 /*
24 * FUNCTION: Prepares an ARP packet
25 * ARGUMENTS:
26 * HardwareType = Hardware type (in network byte order)
27 * ProtocolType = Protocol type (in network byte order)
28 * LinkAddressLength = Length of link address fields
29 * ProtoAddressLength = Length of protocol address fields
30 * SenderLinkAddress = Sender's link address
31 * SenderProtoAddress = Sender's protocol address
32 * TargetLinkAddress = Target's link address (NULL if don't care)
33 * TargetProtoAddress = Target's protocol address
34 * Opcode = ARP opcode (in network byte order)
35 * RETURNS:
36 * Pointer to NDIS packet, NULL if there is not enough free resources
37 */
38 {
39 PNDIS_PACKET NdisPacket;
40 NDIS_STATUS NdisStatus;
41 PARP_HEADER Header;
42 PVOID DataBuffer;
43 ULONG Size, Contig;
44
45 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
46
47 /* Prepare ARP packet */
48 Size = MaxLLHeaderSize +
49 sizeof(ARP_HEADER) +
50 2 * LinkAddressLength + /* Hardware address length */
51 2 * ProtoAddressLength; /* Protocol address length */
52 Size = MAX(Size, MinLLFrameSize);
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 + MaxLLHeaderSize);
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
92 VOID ARPTransmitComplete(
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
111 BOOLEAN ARPTransmit(
112 PIP_ADDRESS Address,
113 PNET_TABLE_ENTRY NTE)
114 /*
115 * FUNCTION: Creates an ARP request and transmits it on a network
116 * ARGUMENTS:
117 * Address = Pointer to IP address to resolve
118 * NTE = Pointer to net table entru to use for transmitting request
119 * RETURNS:
120 * TRUE if the request was successfully sent, FALSE if not
121 */
122 {
123 PIP_INTERFACE Interface;
124 PNDIS_PACKET NdisPacket;
125 UCHAR ProtoAddrLen;
126 USHORT ProtoType;
127
128 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
129
130 Interface = NTE->Interface;
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 KeBugCheck(0);
144 /* Should not happen */
145 return FALSE;
146 }
147
148 NdisPacket = PrepareARPPacket(
149 WN2H(0x0001), /* FIXME: Ethernet only */
150 ProtoType, /* Protocol type */
151 (UCHAR)Interface->AddressLength, /* Hardware address length */
152 (UCHAR)ProtoAddrLen, /* Protocol address length */
153 Interface->Address, /* Sender's (local) hardware address */
154 &NTE->Address->Address, /* Sender's (local) protocol address */
155 NULL, /* Don't care */
156 &Address->Address, /* Target's (remote) protocol address */
157 ARP_OPCODE_REQUEST); /* ARP request */
158
159 ASSERT_KM_POINTER(NdisPacket);
160 ASSERT_KM_POINTER(PC(NdisPacket));
161 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
162
163 TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
164
165 (*Interface->Transmit)(Interface->Context, NdisPacket,
166 MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
167
168 return TRUE;
169 }
170
171
172 VOID ARPReceive(
173 PVOID Context,
174 PIP_PACKET Packet)
175 /*
176 * FUNCTION: Receives an ARP packet
177 * ARGUMENTS:
178 * Context = Pointer to context information (IP_INTERFACE)
179 * Packet = Pointer to packet
180 */
181 {
182 PARP_HEADER Header;
183 PIP_ADDRESS Address;
184 PVOID SenderHWAddress;
185 PVOID SenderProtoAddress;
186 PVOID TargetProtoAddress;
187 PADDRESS_ENTRY ADE;
188 PNEIGHBOR_CACHE_ENTRY NCE;
189 PNDIS_PACKET NdisPacket;
190 PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
191
192 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
193
194 Header = (PARP_HEADER)Packet->Header;
195
196 /* FIXME: Ethernet only */
197 if (WN2H(Header->HWType) != 1) {
198 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType)));
199 return;
200 }
201
202 /* Check protocol type */
203 if (Header->ProtoType != ETYPE_IPv4) {
204 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
205 return;
206 }
207
208 SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
209 SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
210
211 /* Check if we have the target protocol address */
212
213 TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
214 Header->ProtoAddrLen + Header->HWAddrLen);
215
216 Address = AddrBuildIPv4(*((PULONG)TargetProtoAddress));
217 ADE = IPLocateADE(Address, ADE_UNICAST);
218 if (!ADE) {
219 TI_DbgPrint(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress)));
220 return;
221 }
222
223 /* Check if we know the sender */
224
225 AddrInitIPv4(Address, *((PULONG)SenderProtoAddress));
226 NCE = NBLocateNeighbor(Address);
227 if (NCE) {
228 /* We know the sender. Update the hardware address
229 and state in our neighbor address cache */
230 NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
231 } else {
232 /* The packet had our protocol address as target. The sender
233 may want to communicate with us soon, so add his address
234 to our address cache */
235 NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,
236 Header->HWAddrLen, NUD_REACHABLE);
237 }
238
239 if (Header->Opcode != ARP_OPCODE_REQUEST)
240 return;
241
242 /* This is a request for our address. Swap the addresses and
243 send an ARP reply back to the sender */
244 NdisPacket = PrepareARPPacket(
245 Header->HWType, /* Hardware type */
246 Header->ProtoType, /* Protocol type */
247 (UCHAR)Interface->AddressLength, /* Hardware address length */
248 (UCHAR)Header->ProtoAddrLen, /* Protocol address length */
249 Interface->Address, /* Sender's (local) hardware address */
250 &ADE->Address.Address, /* Sender's (local) protocol address */
251 SenderHWAddress, /* Target's (remote) hardware address */
252 SenderProtoAddress, /* Target's (remote) protocol address */
253 ARP_OPCODE_REPLY); /* ARP reply */
254 if (NdisPacket) {
255 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
256 (*Interface->Transmit)(Interface->Context,
257 NdisPacket,
258 MaxLLHeaderSize,
259 SenderHWAddress,
260 LAN_PROTO_ARP);
261 }
262 }
263
264 /* EOF */