96962d59fec9e637483b31ec07904cd8a4e8b6c4
[reactos.git] / reactos / drivers / net / tcpip / tcpip / address.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/address.c
5 * PURPOSE: Routines for handling addresses
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10 #include <tcpip.h>
11 #include <address.h>
12 #include <pool.h>
13 #include <ip.h>
14
15 #ifdef DBG
16
17 CHAR A2SStr[128];
18
19 PCHAR A2S(
20 PIP_ADDRESS Address)
21 /*
22 * FUNCTION: Convert an IP address to a string (for debugging)
23 * ARGUMENTS:
24 * Address = Pointer to an IP address structure
25 * RETURNS:
26 * Pointer to buffer with string representation of IP address
27 */
28 {
29 ULONG ip;
30 CHAR b[10];
31 PCHAR p;
32
33 p = A2SStr;
34
35 if (!Address) {
36 TI_DbgPrint(MIN_TRACE, ("NULL address given.\n"));
37 strcpy(p, "(NULL)");
38 return p;
39 }
40
41 switch (Address->Type) {
42 case IP_ADDRESS_V4:
43 ip = DN2H(Address->Address.IPv4Address);
44 sprintf(p, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
45 break;
46
47 case IP_ADDRESS_V6:
48 /* FIXME: IPv6 is not supported */
49 strcpy(p, "(IPv6 address not supported)");
50 break;
51 }
52 return p;
53 }
54
55 #endif /* DBG */
56
57
58 VOID IPAddressFree(
59 PVOID Object)
60 /*
61 * FUNCTION: Frees an IP_ADDRESS object
62 * ARGUMENTS:
63 * Object = Pointer to an IP address structure
64 * RETURNS:
65 * Nothing
66 */
67 {
68 ExFreePool(Object);
69 }
70
71
72 BOOLEAN AddrIsUnspecified(
73 PIP_ADDRESS Address)
74 /*
75 * FUNCTION: Return wether IP address is an unspecified address
76 * ARGUMENTS:
77 * Address = Pointer to an IP address structure
78 * RETURNS:
79 * TRUE if the IP address is an unspecified address, FALSE if not
80 */
81 {
82 switch (Address->Type) {
83 case IP_ADDRESS_V4:
84 return (Address->Address.IPv4Address == 0);
85
86 case IP_ADDRESS_V6:
87 /* FIXME: IPv6 is not supported */
88 default:
89 return FALSE;
90 }
91 }
92
93
94 /*
95 * FUNCTION: Extract IP address from TDI address structure
96 * ARGUMENTS:
97 * AddrList = Pointer to transport address list to extract from
98 * Address = Address of a pointer to where an IP address is stored
99 * Port = Pointer to where port number is stored
100 * Cache = Address of pointer to a cached address (updated on return)
101 * RETURNS:
102 * Status of operation
103 */
104 NTSTATUS AddrGetAddress(
105 PTRANSPORT_ADDRESS AddrList,
106 PIP_ADDRESS *Address,
107 PUSHORT Port,
108 PIP_ADDRESS *Cache)
109 {
110 PTA_ADDRESS CurAddr;
111 INT i;
112
113 /* We can only use IP addresses. Search the list until we find one */
114 CurAddr = AddrList->Address;
115
116 for (i = 0; i < AddrList->TAAddressCount; i++) {
117 switch (CurAddr->AddressType) {
118 case TDI_ADDRESS_TYPE_IP:
119 if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
120 /* This is an IPv4 address */
121 PIP_ADDRESS IPAddress;
122 PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
123
124 *Port = ValidAddr->sin_port;
125
126 if ((Cache) && (*Cache)) {
127 if (((*Cache)->Type == IP_ADDRESS_V4) &&
128 ((*Cache)->Address.IPv4Address == ValidAddr->in_addr)) {
129 *Address = *Cache;
130 return STATUS_SUCCESS;
131 } else {
132 /* Release the cached address as we cannot use it this time */
133 DereferenceObject(*Cache);
134 *Cache = NULL;
135 }
136 }
137
138 IPAddress = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS));
139 if (IPAddress) {
140 AddrInitIPv4(IPAddress, ValidAddr->in_addr);
141 *Address = IPAddress;
142
143 /* Update address cache */
144 if (Cache) {
145 *Cache = IPAddress;
146 ReferenceObject(*Cache);
147 }
148 return STATUS_SUCCESS;
149 } else
150 return STATUS_INSUFFICIENT_RESOURCES;
151 } else
152 return STATUS_INVALID_ADDRESS;
153 default:
154 /* This is an unsupported address type.
155 Skip it and go to the next in the list */
156 CurAddr = (PTA_ADDRESS)((ULONG_PTR)CurAddr->Address + CurAddr->AddressLength);
157 }
158 }
159
160 return STATUS_INVALID_ADDRESS;
161 }
162
163
164 /*
165 * FUNCTION: Extract IP address from TDI address structure
166 * ARGUMENTS:
167 * TdiAddress = Pointer to transport address list to extract from
168 * Address = Address of a pointer to where an IP address is stored
169 * Port = Pointer to where port number is stored
170 * RETURNS:
171 * Status of operation
172 */
173 NTSTATUS AddrBuildAddress(
174 PTA_ADDRESS TdiAddress,
175 PIP_ADDRESS *Address,
176 PUSHORT Port)
177 {
178 PTDI_ADDRESS_IP ValidAddr;
179 PIP_ADDRESS IPAddress;
180
181 if (TdiAddress->AddressType != TDI_ADDRESS_TYPE_IP)
182 return STATUS_INVALID_ADDRESS;
183
184 if (TdiAddress->AddressLength != TDI_ADDRESS_LENGTH_IP)
185 return STATUS_INVALID_ADDRESS;
186
187 ValidAddr = (PTDI_ADDRESS_IP)TdiAddress->Address;
188
189 IPAddress = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS));
190 if (!IPAddress)
191 return STATUS_INSUFFICIENT_RESOURCES;
192
193 AddrInitIPv4(IPAddress, ValidAddr->in_addr);
194 *Address = IPAddress;
195 *Port = ValidAddr->sin_port;
196
197 return STATUS_SUCCESS;
198 }
199
200
201 /*
202 * FUNCTION: Returns wether two addresses are equal
203 * ARGUMENTS:
204 * Address1 = Pointer to first address
205 * Address2 = Pointer to last address
206 * RETURNS:
207 * TRUE if Address1 = Address2, FALSE if not
208 */
209 BOOLEAN AddrIsEqual(
210 PIP_ADDRESS Address1,
211 PIP_ADDRESS Address2)
212 {
213 if (Address1->Type != Address2->Type)
214 return FALSE;
215
216 switch (Address1->Type) {
217 case IP_ADDRESS_V4:
218 return (Address1->Address.IPv4Address == Address2->Address.IPv4Address);
219
220 case IP_ADDRESS_V6:
221 return (RtlCompareMemory(&Address1->Address, &Address2->Address,
222 sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS));
223 break;
224 }
225
226 return FALSE;
227 }
228
229
230 /*
231 * FUNCTION: Returns wether Address1 is less than Address2
232 * ARGUMENTS:
233 * Address1 = Pointer to first address
234 * Address2 = Pointer to last address
235 * RETURNS:
236 * -1 if Address1 < Address2, 1 if Address1 > Address2,
237 * or 0 if they are equal
238 */
239 INT AddrCompare(
240 PIP_ADDRESS Address1,
241 PIP_ADDRESS Address2)
242 {
243 switch (Address1->Type) {
244 case IP_ADDRESS_V4: {
245 ULONG Addr1, Addr2;
246 if (Address2->Type == IP_ADDRESS_V4) {
247 Addr1 = DN2H(Address1->Address.IPv4Address);
248 Addr2 = DN2H(Address2->Address.IPv4Address);
249 if (Addr1 < Addr2)
250 return -1;
251 else
252 if (Addr1 == Addr2)
253 return 0;
254 else
255 return 1;
256 } else
257 /* FIXME: Support IPv6 */
258 return -1;
259
260 case IP_ADDRESS_V6:
261 /* FIXME: Support IPv6 */
262 break;
263 }
264 }
265
266 return FALSE;
267 }
268
269
270 /*
271 * FUNCTION: Returns wether two addresses are equal with IPv4 as input
272 * ARGUMENTS:
273 * Address1 = Pointer to first address
274 * Address2 = Pointer to last address
275 * RETURNS:
276 * TRUE if Address1 = Address2, FALSE if not
277 */
278 BOOLEAN AddrIsEqualIPv4(
279 PIP_ADDRESS Address1,
280 IPv4_RAW_ADDRESS Address2)
281 {
282 if (Address1->Type == IP_ADDRESS_V4)
283 return (Address1->Address.IPv4Address == Address2);
284
285 return FALSE;
286 }
287
288
289 /*
290 * FUNCTION: Build an IPv4 style address
291 * ARGUMENTS:
292 * Address = Raw IPv4 address
293 * RETURNS:
294 * Pointer to IP address structure, NULL if there was not enough free
295 * non-paged memory
296 */
297 PIP_ADDRESS AddrBuildIPv4(
298 IPv4_RAW_ADDRESS Address)
299 {
300 PIP_ADDRESS IPAddress;
301
302 IPAddress = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS));
303 if (IPAddress) {
304 IPAddress->RefCount = 1;
305 IPAddress->Type = IP_ADDRESS_V4;
306 IPAddress->Address.IPv4Address = Address;
307 IPAddress->Free = IPAddressFree;
308 }
309
310 return IPAddress;
311 }
312
313
314 /*
315 * FUNCTION: Locates and returns an address entry using IPv4 adress as argument
316 * ARGUMENTS:
317 * Address = Raw IPv4 address
318 * RETURNS:
319 * Pointer to address entry if found, NULL if not found
320 * NOTES:
321 * Only unicast addresses are considered.
322 * If found, the address is referenced
323 */
324 PADDRESS_ENTRY AddrLocateADEv4(
325 IPv4_RAW_ADDRESS Address)
326 {
327 IP_ADDRESS Addr;
328
329 AddrInitIPv4(&Addr, Address);
330
331 return IPLocateADE(&Addr, ADE_UNICAST);
332 }
333
334
335 /*
336 * FUNCTION: Searches through address file entries to find the first match
337 * ARGUMENTS:
338 * Address = IP address
339 * Port = Port number
340 * Protocol = Protocol number
341 * SearchContext = Pointer to search context
342 * RETURNS:
343 * Pointer to address file, NULL if none was found
344 */
345 PADDRESS_FILE AddrSearchFirst(
346 PIP_ADDRESS Address,
347 USHORT Port,
348 USHORT Protocol,
349 PAF_SEARCH SearchContext)
350 {
351 SearchContext->Address = Address;
352 SearchContext->Port = Port;
353 SearchContext->Next = AddressFileListHead.Flink;
354 SearchContext->Protocol = Protocol;
355
356 return AddrSearchNext(SearchContext);
357 }
358
359
360 /*
361 * FUNCTION: Searches through address file entries to find next match
362 * ARGUMENTS:
363 * SearchContext = Pointer to search context
364 * RETURNS:
365 * Pointer to address file, NULL if none was found
366 */
367 PADDRESS_FILE AddrSearchNext(
368 PAF_SEARCH SearchContext)
369 {
370 PLIST_ENTRY CurrentEntry;
371 PIP_ADDRESS IPAddress;
372 KIRQL OldIrql;
373 PADDRESS_FILE Current = NULL;
374 BOOLEAN Found = FALSE;
375
376 if (IsListEmpty(SearchContext->Next))
377 return NULL;
378
379 CurrentEntry = SearchContext->Next;
380
381 KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
382
383 while (CurrentEntry != &AddressFileListHead) {
384 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
385
386 IPAddress = Current->ADE->Address;
387
388 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
389 WN2H(Current->Port),
390 Current->Protocol,
391 A2S(IPAddress),
392 WN2H(SearchContext->Port),
393 SearchContext->Protocol,
394 A2S(SearchContext->Address)));
395
396 /* See if this address matches the search criteria */
397 if (((Current->Port == SearchContext->Port) &&
398 (Current->Protocol == SearchContext->Protocol) &&
399 (AddrIsEqual(IPAddress, SearchContext->Address))) ||
400 (AddrIsUnspecified(IPAddress))) {
401 /* We've found a match */
402 Found = TRUE;
403 break;
404 }
405 CurrentEntry = CurrentEntry->Flink;
406 }
407
408 KeReleaseSpinLock(&AddressFileListLock, OldIrql);
409
410 if (Found) {
411 SearchContext->Next = CurrentEntry->Flink;
412 return Current;
413 } else
414 return NULL;
415 }
416
417 ULONG inet_addr(PCSTR AddrString)
418 /*
419 * Convert an ansi string dotted-quad address to a ulong
420 * NOTES:
421 * - this isn't quite like the real inet_addr() - * it doesn't
422 * handle "10.1" and similar - but it's good enough.
423 * - Returns in *host* byte order, unlike real inet_addr()
424 */
425 {
426 ULONG Octets[4] = {0,0,0,0};
427 ULONG i = 0;
428
429 if(!AddrString)
430 return -1;
431
432 while(*AddrString)
433 {
434 CHAR c = *AddrString;
435 AddrString++;
436
437 if(c == '.')
438 {
439 i++;
440 continue;
441 }
442
443 if(c < '0' || c > '9')
444 return -1;
445
446 Octets[i] *= 10;
447 Octets[i] += (c - '0');
448
449 if(Octets[i] > 255)
450 return -1;
451 }
452
453 return (Octets[3] << 24) + (Octets[2] << 16) + (Octets[1] << 8) + Octets[0];
454 }
455
456 /* EOF */