e4c8ee8d10b6f21c4abef06431173a86c1d63370
[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
59 RtlZeroMemory(DataBuffer, Size);
60 Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);
61 Header->HWType = HardwareType;
62 Header->ProtoType = ProtocolType;
63 Header->HWAddrLen = LinkAddressLength;
64 Header->ProtoAddrLen = ProtoAddressLength;
65 Header->Opcode = Opcode; /* Already swapped */
66 DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
67
68 /* Our hardware address */
69 RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);
70 DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength);
71
72 /* Our protocol address */
73 RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
74
75 if (TargetLinkAddress) {
76 DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength);
77 /* Target hardware address */
78 RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);
79 DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength);
80 } else
81 /* Don't care about target hardware address */
82 DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength + LinkAddressLength);
83
84 /* Target protocol address */
85 RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);
86
87 return NdisPacket;
88 }
89
90
91 VOID ARPTransmitComplete(
92 PVOID Context,
93 PNDIS_PACKET NdisPacket,
94 NDIS_STATUS NdisStatus)
95 /*
96 * FUNCTION: ARP request transmit completion handler
97 * ARGUMENTS:
98 * Context = Pointer to context information (IP_INTERFACE)
99 * Packet = Pointer to NDIS packet that was sent
100 * NdisStatus = NDIS status of operation
101 * NOTES:
102 * This routine is called when an ARP request has been sent
103 */
104 {
105 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
106 FreeNdisPacket(NdisPacket);
107 }
108
109
110 BOOLEAN ARPTransmit(
111 PIP_ADDRESS Address,
112 PNET_TABLE_ENTRY NTE)
113 /*
114 * FUNCTION: Creates an ARP request and transmits it on a network
115 * ARGUMENTS:
116 * Address = Pointer to IP address to resolve
117 * NTE = Pointer to net table entru to use for transmitting request
118 * RETURNS:
119 * TRUE if the request was successfully sent, FALSE if not
120 */
121 {
122 PIP_INTERFACE Interface;
123 PNDIS_PACKET NdisPacket;
124 UCHAR ProtoAddrLen;
125 USHORT ProtoType;
126
127 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
128
129 Interface = NTE->Interface;
130
131 switch (Address->Type) {
132 case IP_ADDRESS_V4:
133 ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */
134 ProtoAddrLen = 4; /* Length of IPv4 address */
135 break;
136 case IP_ADDRESS_V6:
137 ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */
138 ProtoAddrLen = 16; /* Length of IPv6 address */
139 break;
140 default:
141 TI_DbgPrint(DEBUG_ARP,("Bad Address Type %x\n", Address->Type));
142 KeBugCheck(0);
143 /* Should not happen */
144 return FALSE;
145 }
146
147 NdisPacket = PrepareARPPacket(
148 WN2H(0x0001), /* FIXME: Ethernet only */
149 ProtoType, /* Protocol type */
150 (UCHAR)Interface->AddressLength, /* Hardware address length */
151 (UCHAR)ProtoAddrLen, /* Protocol address length */
152 Interface->Address, /* Sender's (local) hardware address */
153 &NTE->Address->Address, /* Sender's (local) protocol address */
154 NULL, /* Don't care */
155 &Address->Address, /* Target's (remote) protocol address */
156 ARP_OPCODE_REQUEST); /* ARP request */
157
158 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
159
160 TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
161
162 (*Interface->Transmit)(Interface->Context, NdisPacket,
163 MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
164
165 return TRUE;
166 }
167
168
169 VOID ARPReceive(
170 PVOID Context,
171 PIP_PACKET Packet)
172 /*
173 * FUNCTION: Receives an ARP packet
174 * ARGUMENTS:
175 * Context = Pointer to context information (IP_INTERFACE)
176 * Packet = Pointer to packet
177 */
178 {
179 PARP_HEADER Header;
180 PIP_ADDRESS Address;
181 PVOID SenderHWAddress;
182 PVOID SenderProtoAddress;
183 PVOID TargetProtoAddress;
184 PADDRESS_ENTRY ADE;
185 PNEIGHBOR_CACHE_ENTRY NCE;
186 PNDIS_PACKET NdisPacket;
187 PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
188
189 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
190
191 Header = (PARP_HEADER)Packet->Header;
192
193 /* FIXME: Ethernet only */
194 if (WN2H(Header->HWType) != 1) {
195 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType)));
196 return;
197 }
198
199 /* Check protocol type */
200 if (Header->ProtoType != ETYPE_IPv4) {
201 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
202 return;
203 }
204
205 SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
206 SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
207
208 /* Check if we have the target protocol address */
209
210 TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
211 Header->ProtoAddrLen + Header->HWAddrLen);
212
213 Address = AddrBuildIPv4(*((PULONG)TargetProtoAddress));
214 ADE = IPLocateADE(Address, ADE_UNICAST);
215 if (!ADE) {
216 TI_DbgPrint(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress)));
217 return;
218 }
219
220 /* Check if we know the sender */
221
222 AddrInitIPv4(Address, *((PULONG)SenderProtoAddress));
223 NCE = NBLocateNeighbor(Address);
224 if (NCE) {
225 /* We know the sender. Update the hardware address
226 and state in our neighbor address cache */
227 NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
228 } else {
229 /* The packet had our protocol address as target. The sender
230 may want to communicate with us soon, so add his address
231 to our address cache */
232 NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,
233 Header->HWAddrLen, NUD_REACHABLE);
234 }
235
236 if (Header->Opcode != ARP_OPCODE_REQUEST)
237 return;
238
239 /* This is a request for our address. Swap the addresses and
240 send an ARP reply back to the sender */
241 NdisPacket = PrepareARPPacket(
242 Header->HWType, /* Hardware type */
243 Header->ProtoType, /* Protocol type */
244 (UCHAR)Interface->AddressLength, /* Hardware address length */
245 (UCHAR)Header->ProtoAddrLen, /* Protocol address length */
246 Interface->Address, /* Sender's (local) hardware address */
247 &ADE->Address.Address, /* Sender's (local) protocol address */
248 SenderHWAddress, /* Target's (remote) hardware address */
249 SenderProtoAddress, /* Target's (remote) protocol address */
250 ARP_OPCODE_REPLY); /* ARP reply */
251 if (NdisPacket) {
252 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
253 (*Interface->Transmit)(Interface->Context,
254 NdisPacket,
255 MaxLLHeaderSize,
256 SenderHWAddress,
257 LAN_PROTO_ARP);
258 }
259 }
260
261 /* EOF */