- Removed prefix.c and the prefix list. Adapter and route netmasks are now
[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(PIP_ADDRESS Address, PIP_INTERFACE Interface)
112 /*
113 * FUNCTION: Creates an ARP request and transmits it on a network
114 * ARGUMENTS:
115 * Address = Pointer to IP address to resolve
116 * RETURNS:
117 * TRUE if the request was successfully sent, FALSE if not
118 */
119 {
120 PNDIS_PACKET NdisPacket;
121 UCHAR ProtoAddrLen;
122 USHORT ProtoType;
123
124 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
125
126 switch (Address->Type) {
127 case IP_ADDRESS_V4:
128 ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */
129 ProtoAddrLen = 4; /* Length of IPv4 address */
130 break;
131 case IP_ADDRESS_V6:
132 ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */
133 ProtoAddrLen = 16; /* Length of IPv6 address */
134 break;
135 default:
136 TI_DbgPrint(DEBUG_ARP,("Bad Address Type %x\n", Address->Type));
137 KeBugCheck(0);
138 /* Should not happen */
139 return FALSE;
140 }
141
142 NdisPacket = PrepareARPPacket(
143 WN2H(0x0001), /* FIXME: Ethernet only */
144 ProtoType, /* Protocol type */
145 (UCHAR)Interface->AddressLength, /* Hardware address length */
146 (UCHAR)ProtoAddrLen, /* Protocol address length */
147 Interface->Address, /* Sender's (local) hardware address */
148 &Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */
149 NULL, /* Don't care */
150 &Address->Address, /* Target's (remote) protocol address */
151 ARP_OPCODE_REQUEST); /* ARP request */
152
153 ASSERT_KM_POINTER(NdisPacket);
154 ASSERT_KM_POINTER(PC(NdisPacket));
155 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
156
157 TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
158
159 (*Interface->Transmit)(Interface->Context, NdisPacket,
160 MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
161
162 return TRUE;
163 }
164
165
166 VOID ARPReceive(
167 PVOID Context,
168 PIP_PACKET Packet)
169 /*
170 * FUNCTION: Receives an ARP packet
171 * ARGUMENTS:
172 * Context = Pointer to context information (IP_INTERFACE)
173 * Packet = Pointer to packet
174 */
175 {
176 PARP_HEADER Header;
177 IP_ADDRESS Address;
178 PVOID SenderHWAddress;
179 PVOID SenderProtoAddress;
180 PVOID TargetProtoAddress;
181 PNEIGHBOR_CACHE_ENTRY NCE;
182 PNDIS_PACKET NdisPacket;
183 PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
184
185 TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
186
187 Header = (PARP_HEADER)Packet->Header;
188
189 /* FIXME: Ethernet only */
190 if (WN2H(Header->HWType) != 1) {
191 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType)));
192 return;
193 }
194
195 /* Check protocol type */
196 if (Header->ProtoType != ETYPE_IPv4) {
197 TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
198 return;
199 }
200
201 SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
202 SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
203
204 /* Check if we have the target protocol address */
205
206 TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
207 Header->ProtoAddrLen + Header->HWAddrLen);
208
209 if( !AddrLocateADEv4( *((PIPv4_RAW_ADDRESS)TargetProtoAddress),
210 &Address) ) {
211 TI_DbgPrint(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress)));
212 return;
213 }
214
215 /* Check if we know the sender */
216
217 AddrInitIPv4(&Address, *((PULONG)SenderProtoAddress));
218 NCE = NBLocateNeighbor(&Address);
219 if (NCE) {
220 /* We know the sender. Update the hardware address
221 and state in our neighbor address cache */
222 NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
223 } else {
224 /* The packet had our protocol address as target. The sender
225 may want to communicate with us soon, so add his address
226 to our address cache */
227 NCE = NBAddNeighbor(Interface, &Address, SenderHWAddress,
228 Header->HWAddrLen, NUD_REACHABLE);
229 }
230
231 if (Header->Opcode != ARP_OPCODE_REQUEST)
232 return;
233
234 /* This is a request for our address. Swap the addresses and
235 send an ARP reply back to the sender */
236 NdisPacket = PrepareARPPacket(
237 Header->HWType, /* Hardware type */
238 Header->ProtoType, /* Protocol type */
239 (UCHAR)Interface->AddressLength, /* Hardware address length */
240 (UCHAR)Header->ProtoAddrLen, /* Protocol address length */
241 Interface->Address, /* Sender's (local) hardware address */
242 &Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */
243 SenderHWAddress, /* Target's (remote) hardware address */
244 SenderProtoAddress, /* Target's (remote) protocol address */
245 ARP_OPCODE_REPLY); /* ARP reply */
246 if (NdisPacket) {
247 PC(NdisPacket)->DLComplete = ARPTransmitComplete;
248 (*Interface->Transmit)(Interface->Context,
249 NdisPacket,
250 MaxLLHeaderSize,
251 SenderHWAddress,
252 LAN_PROTO_ARP);
253 }
254 }
255
256 /* EOF */