8e5984750f631c76977cd3c3fa4e809a31fc11ff
[reactos.git] / reactos / dll / win32 / iphlpapi / address.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/iphlpapi/address.c
5 * PURPOSE: iphlpapi implementation - Adapter Address APIs
6 * PROGRAMMERS: Jérôme Gardou (jerome.gardou@reactos.org)
7 */
8
9 #include "iphlpapi_private.h"
10
11 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
12 #ifdef GetAdaptersAddressesV2
13 /* Helper for GetAdaptersAddresses:
14 * Retrieves the list of network adapters from tcpip.sys */
15 static
16 NTSTATUS
17 GetInterfacesList(
18 _In_ HANDLE TcpFile,
19 _Out_ TDIEntityID **EntityList,
20 _Out_ ULONG* InterfaceCount)
21 {
22
23 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
24 IO_STATUS_BLOCK StatusBlock;
25 NTSTATUS Status;
26 ULONG_PTR BufferSize;
27
28 ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
29 TcpQueryInfo.ID.toi_class = INFO_CLASS_GENERIC;
30 TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
31 TcpQueryInfo.ID.toi_id = ENTITY_LIST_ID;
32 TcpQueryInfo.ID.toi_entity.tei_entity = GENERIC_ENTITY;
33 TcpQueryInfo.ID.toi_entity.tei_instance = 0;
34
35 Status = NtDeviceIoControlFile(
36 TcpFile,
37 NULL,
38 NULL,
39 NULL,
40 &StatusBlock,
41 IOCTL_TCP_QUERY_INFORMATION_EX,
42 &TcpQueryInfo,
43 sizeof(TcpQueryInfo),
44 NULL,
45 0);
46 if (Status == STATUS_PENDING)
47 {
48 /* So we have to wait a bit */
49 Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
50 if (NT_SUCCESS(Status))
51 Status = StatusBlock.Status;
52 }
53
54 if (!NT_SUCCESS(Status))
55 return Status;
56
57 BufferSize = StatusBlock.Information;
58 *EntityList = HeapAlloc(GetProcessHeap(), 0, BufferSize);
59 if (!*EntityList)
60 return STATUS_NO_MEMORY;
61
62 /* Do the real call */
63 Status = NtDeviceIoControlFile(
64 TcpFile,
65 NULL,
66 NULL,
67 NULL,
68 &StatusBlock,
69 IOCTL_TCP_QUERY_INFORMATION_EX,
70 &TcpQueryInfo,
71 sizeof(TcpQueryInfo),
72 *EntityList,
73 BufferSize);
74 if (Status == STATUS_PENDING)
75 {
76 /* So we have to wait a bit */
77 Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
78 if (NT_SUCCESS(Status))
79 Status = StatusBlock.Status;
80 }
81
82 if (!NT_SUCCESS(Status))
83 {
84 HeapFree(GetProcessHeap(), 0, *EntityList);
85 return Status;
86 }
87
88 *InterfaceCount = BufferSize / sizeof(TDIEntityID);
89 return Status;
90 }
91
92 static
93 NTSTATUS
94 GetSnmpInfo(
95 _In_ HANDLE TcpFile,
96 _In_ TDIEntityID InterfaceID,
97 _Out_ IPSNMPInfo* Info)
98 {
99 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
100 IO_STATUS_BLOCK StatusBlock;
101 NTSTATUS Status;
102
103 ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
104 TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
105 TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
106 TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID;
107 TcpQueryInfo.ID.toi_entity = InterfaceID;
108
109 Status = NtDeviceIoControlFile(
110 TcpFile,
111 NULL,
112 NULL,
113 NULL,
114 &StatusBlock,
115 IOCTL_TCP_QUERY_INFORMATION_EX,
116 &TcpQueryInfo,
117 sizeof(TcpQueryInfo),
118 Info,
119 sizeof(*Info));
120 if (Status == STATUS_PENDING)
121 {
122 /* So we have to wait a bit */
123 Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
124 if (NT_SUCCESS(Status))
125 Status = StatusBlock.Status;
126 }
127
128 return Status;
129 }
130
131 static
132 NTSTATUS
133 GetAddrEntries(
134 _In_ HANDLE TcpFile,
135 _In_ TDIEntityID InterfaceID,
136 _Out_ IPAddrEntry* Entries,
137 _In_ ULONG NumEntries)
138 {
139 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
140 IO_STATUS_BLOCK StatusBlock;
141 NTSTATUS Status;
142
143 ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
144 TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
145 TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
146 TcpQueryInfo.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
147 TcpQueryInfo.ID.toi_entity = InterfaceID;
148
149 Status = NtDeviceIoControlFile(
150 TcpFile,
151 NULL,
152 NULL,
153 NULL,
154 &StatusBlock,
155 IOCTL_TCP_QUERY_INFORMATION_EX,
156 &TcpQueryInfo,
157 sizeof(TcpQueryInfo),
158 Entries,
159 NumEntries * sizeof(Entries[0]));
160 if (Status == STATUS_PENDING)
161 {
162 /* So we have to wait a bit */
163 Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
164 if (NT_SUCCESS(Status))
165 Status = StatusBlock.Status;
166 }
167
168 return Status;
169 }
170
171 /*
172 * Fills the IFEntry buffer from tcpip.sys.
173 * The buffer size MUST be FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1]).
174 * See MSDN IFEntry struct definition if you don't believe me. ;-)
175 */
176 static
177 NTSTATUS
178 GetInterfaceEntry(
179 _In_ HANDLE TcpFile,
180 _In_ TDIEntityID InterfaceID,
181 _Out_ IFEntry* Entry)
182 {
183 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo;
184 IO_STATUS_BLOCK StatusBlock;
185 NTSTATUS Status;
186
187 ZeroMemory(&TcpQueryInfo, sizeof(TcpQueryInfo));
188 TcpQueryInfo.ID.toi_class = INFO_CLASS_PROTOCOL;
189 TcpQueryInfo.ID.toi_type = INFO_TYPE_PROVIDER;
190 TcpQueryInfo.ID.toi_id = IP_MIB_STATS_ID;
191 TcpQueryInfo.ID.toi_entity = InterfaceID;
192
193 Status = NtDeviceIoControlFile(
194 TcpFile,
195 NULL,
196 NULL,
197 NULL,
198 &StatusBlock,
199 IOCTL_TCP_QUERY_INFORMATION_EX,
200 &TcpQueryInfo,
201 sizeof(TcpQueryInfo),
202 Entry,
203 FIELD_OFFSET(IFEntry, if_descr[MAX_ADAPTER_DESCRIPTION_LENGTH + 1]));
204 if (Status == STATUS_PENDING)
205 {
206 /* So we have to wait a bit */
207 Status = NtWaitForSingleObject(TcpFile, FALSE, NULL);
208 if (NT_SUCCESS(Status))
209 Status = StatusBlock.Status;
210 }
211
212 return Status;
213 }
214
215 /* Helpers to get the list of DNS for an interface */
216 static
217 VOID
218 EnumerateServerNameSize(
219 _In_ PWCHAR Interface,
220 _In_ PWCHAR NameServer,
221 _Inout_ PVOID Data)
222 {
223 ULONG* BufferSize = Data;
224
225 /* This is just sizing here */
226 UNREFERENCED_PARAMETER(Interface);
227 UNREFERENCED_PARAMETER(NameServer);
228
229 *BufferSize += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR);
230 }
231
232 static
233 VOID
234 EnumerateServerName(
235 _In_ PWCHAR Interface,
236 _In_ PWCHAR NameServer,
237 _Inout_ PVOID Data)
238 {
239 PIP_ADAPTER_DNS_SERVER_ADDRESS** Ptr = Data;
240 PIP_ADAPTER_DNS_SERVER_ADDRESS ServerAddress = **Ptr;
241
242 UNREFERENCED_PARAMETER(Interface);
243
244 ServerAddress->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
245 ServerAddress->Address.lpSockaddr = (PVOID)(ServerAddress + 1);
246 ServerAddress->Address.iSockaddrLength = sizeof(SOCKADDR);
247
248
249 /* Get the address from the server name string */
250 //FIXME: Only ipv4 for now...
251 if (WSAStringToAddressW(
252 NameServer,
253 AF_INET,
254 NULL,
255 ServerAddress->Address.lpSockaddr,
256 &ServerAddress->Address.iSockaddrLength))
257 {
258 /* Pass along, name conversion failed */
259 ERR("%S is not a valid IP address\n", NameServer);
260 return;
261 }
262
263 /* Go to next item */
264 ServerAddress->Next = (PVOID)(ServerAddress->Address.lpSockaddr + 1);
265 *Ptr = &ServerAddress->Next;
266 }
267
268 DWORD
269 WINAPI
270 DECLSPEC_HOTPATCH
271 GetAdaptersAddresses(
272 _In_ ULONG Family,
273 _In_ ULONG Flags,
274 _In_ PVOID Reserved,
275 _Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses,
276 _Inout_ PULONG pOutBufLen)
277 {
278 NTSTATUS Status;
279 HANDLE TcpFile;
280 TDIEntityID* InterfacesList;
281 ULONG InterfacesCount;
282 ULONG AdaptersCount = 0;
283 ULONG i;
284 ULONG TotalSize = 0, RemainingSize;
285 BYTE* Ptr = (BYTE*)pAdapterAddresses;
286 DWORD MIN_SIZE = 15 * 1024;
287 PIP_ADAPTER_ADDRESSES PreviousAA = NULL;
288
289 FIXME("GetAdaptersAddresses - Semi Stub: Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p.\n",
290 Family, Flags, Reserved, pAdapterAddresses, pOutBufLen);
291
292 if (!pOutBufLen)
293 return ERROR_INVALID_PARAMETER;
294
295 // FIXME: the exact needed size should be computed first, BEFORE doing any write to the output buffer.
296 // As suggested by MSDN, require a 15 KB buffer, which allows to React properly to length checks.
297 if(!Ptr || *pOutBufLen < MIN_SIZE)
298 {
299 *pOutBufLen = MIN_SIZE;
300 return ERROR_BUFFER_OVERFLOW;
301 }
302
303 switch(Family)
304 {
305 case AF_INET:
306 break;
307 case AF_INET6:
308 /* One day maybe... */
309 FIXME("IPv6 is not supported in ReactOS!\n");
310 /* We got nothing to say in this case */
311 return ERROR_NO_DATA;
312 break;
313 case AF_UNSPEC:
314 WARN("IPv6 addresses ignored, IPv4 only\n");
315 Family = AF_INET;
316 break;
317 default:
318 ERR("Invalid family 0x%x\n", Family);
319 return ERROR_INVALID_PARAMETER;
320 break;
321 }
322
323 RemainingSize = *pOutBufLen;
324 if (Ptr)
325 ZeroMemory(Ptr, RemainingSize);
326
327 /* open the tcpip driver */
328 Status = openTcpFile(&TcpFile, FILE_READ_DATA);
329 if (!NT_SUCCESS(Status))
330 {
331 ERR("Could not open handle to tcpip.sys. Status %08x\n", Status);
332 return RtlNtStatusToDosError(Status);
333 }
334
335 /* Get the interfaces list */
336 Status = GetInterfacesList(TcpFile, &InterfacesList, &InterfacesCount);
337 if (!NT_SUCCESS(Status))
338 {
339 ERR("Could not get adapters list. Status %08x\n", Status);
340 NtClose(TcpFile);
341 return RtlNtStatusToDosError(Status);
342 }
343
344 /* Let's see if we got any adapter. */
345 for (i = 0; i < InterfacesCount; i++)
346 {
347 PIP_ADAPTER_ADDRESSES CurrentAA = (PIP_ADAPTER_ADDRESSES)Ptr;
348 ULONG CurrentAASize = 0;
349
350 if (InterfacesList[i].tei_entity == IF_ENTITY)
351 {
352 BYTE EntryBuffer[FIELD_OFFSET(IFEntry, if_descr) +
353 RTL_FIELD_SIZE(IFEntry, if_descr[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH + 1)];
354 IFEntry* Entry = (IFEntry*)EntryBuffer;
355
356 /* Remember we got one */
357 AdaptersCount++;
358
359 /* Set the pointer to this instance in the previous one*/
360 if(PreviousAA)
361 PreviousAA->Next = CurrentAA;
362
363 /* Of course we need some space for the base structure. */
364 CurrentAASize = sizeof(IP_ADAPTER_ADDRESSES);
365
366 /* Get the entry */
367 Status = GetInterfaceEntry(TcpFile, InterfacesList[i], Entry);
368 if (!NT_SUCCESS(Status))
369 goto Error;
370
371 TRACE("Got entity %*s, index %u.\n",
372 Entry->if_descrlen, &Entry->if_descr[0], Entry->if_index);
373
374 /* Add the adapter name */
375 CurrentAASize += Entry->if_descrlen + sizeof(CHAR);
376
377 /* Add the DNS suffix */
378 CurrentAASize += sizeof(WCHAR);
379
380 /* Add the description. */
381 CurrentAASize += sizeof(WCHAR);
382
383 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
384 {
385 /* Just an empty string for now. */
386 FIXME("Should get adapter friendly name.\n");
387 CurrentAASize += sizeof(WCHAR);
388 }
389
390 if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
391 {
392 /* Enumerate the name servers */
393 HKEY InterfaceKey;
394 CHAR KeyName[256];
395
396 snprintf(KeyName, 256,
397 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
398 Entry->if_descrlen, &Entry->if_descr[0]);
399
400 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS)
401 {
402 ERR("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
403 Flags |= GAA_FLAG_SKIP_DNS_SERVER;
404 }
405 else
406 {
407 EnumNameServers(InterfaceKey, NULL, &CurrentAASize, EnumerateServerNameSize);
408 RegCloseKey(InterfaceKey);
409 }
410 }
411
412 /* This is part of what we will need */
413 TotalSize += CurrentAASize;
414
415 /* Fill in the data */
416 if ((CurrentAA) && (RemainingSize >= CurrentAASize))
417 {
418 CurrentAA->Length = sizeof(IP_ADAPTER_ADDRESSES);
419 CurrentAA->IfIndex = Entry->if_index;
420 CopyMemory(CurrentAA->PhysicalAddress, Entry->if_physaddr, Entry->if_physaddrlen);
421 CurrentAA->PhysicalAddressLength = Entry->if_physaddrlen;
422 CurrentAA->Flags = 0; // FIXME!
423 CurrentAA->Mtu = Entry->if_mtu;
424 CurrentAA->IfType = Entry->if_type;
425 if(Entry->if_operstatus >= IF_OPER_STATUS_CONNECTING)
426 CurrentAA->OperStatus = IfOperStatusUp;
427 else
428 CurrentAA->OperStatus = IfOperStatusDown;
429
430 /* Next items */
431 Ptr = (BYTE*)(CurrentAA + 1);
432
433 /* Now fill in the name */
434 CopyMemory(Ptr, &Entry->if_descr[0], Entry->if_descrlen);
435 CurrentAA->AdapterName = (PCHAR)Ptr;
436 CurrentAA->AdapterName[Entry->if_descrlen] = '\0';
437 /* Next items */
438 Ptr = (BYTE*)(CurrentAA->AdapterName + Entry->if_descrlen + 1);
439
440 /* The DNS suffix */
441 CurrentAA->DnsSuffix = (PWCHAR)Ptr;
442 CurrentAA->DnsSuffix[0] = L'\0';
443 /* Next items */
444 Ptr = (BYTE*)(CurrentAA->DnsSuffix + 1);
445
446 /* The description */
447 CurrentAA->Description = (PWCHAR)Ptr;
448 CurrentAA->Description[0] = L'\0';
449 /* Next items */
450 Ptr = (BYTE*)(CurrentAA->Description + 1);
451
452 /* The friendly name */
453 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
454 {
455 CurrentAA->FriendlyName = (PWCHAR)Ptr;
456 CurrentAA->FriendlyName[0] = L'\0';
457 /* Next items */
458 Ptr = (BYTE*)(CurrentAA->FriendlyName + 1);
459 }
460
461 /* The DNS Servers */
462 if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER))
463 {
464 /* Enumerate the name servers */
465 HKEY InterfaceKey;
466 CHAR KeyName[256];
467
468 snprintf(KeyName, 256,
469 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
470 Entry->if_descrlen, &Entry->if_descr[0]);
471
472 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &InterfaceKey) != ERROR_SUCCESS)
473 {
474 ERR("Failed opening interface key for interface %*s\n", Entry->if_descrlen, &Entry->if_descr[0]);
475 }
476 else
477 {
478 PIP_ADAPTER_DNS_SERVER_ADDRESS* ServerAddressPtr;
479
480 CurrentAA->FirstDnsServerAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)Ptr;
481 ServerAddressPtr = &CurrentAA->FirstDnsServerAddress;
482
483 EnumNameServers(InterfaceKey, NULL, &ServerAddressPtr, EnumerateServerName);
484 RegCloseKey(InterfaceKey);
485
486 /* Set the last entry in the list as having NULL next member */
487 Ptr = (BYTE*)*ServerAddressPtr;
488 *ServerAddressPtr = NULL;
489 }
490 }
491
492 /* We're done for this interface */
493 PreviousAA = CurrentAA;
494 RemainingSize -= CurrentAASize;
495 }
496 }
497 }
498
499 if (AdaptersCount == 0)
500 {
501 /* Uh? Not even localhost ?! */
502 ERR("No Adapters found!\n");
503 *pOutBufLen = 0;
504 return ERROR_NO_DATA;
505 }
506
507 /* See if we have anything to add */
508 // FIXME: Anycast and multicast
509 if ((Flags & (GAA_FLAG_SKIP_UNICAST | GAA_FLAG_INCLUDE_PREFIX)) == GAA_FLAG_SKIP_UNICAST)
510 goto Success;
511
512 /* Now fill in the addresses */
513 for (i = 0; i < InterfacesCount; i++)
514 {
515 /* Look for network layers */
516 if ((InterfacesList[i].tei_entity == CL_NL_ENTITY)
517 || (InterfacesList[i].tei_entity == CO_NL_ENTITY))
518 {
519 IPSNMPInfo SnmpInfo;
520 PIP_ADAPTER_ADDRESSES CurrentAA = NULL;
521 IPAddrEntry* AddrEntries;
522 ULONG j;
523
524 /* Get its SNMP info */
525 Status = GetSnmpInfo(TcpFile, InterfacesList[i], &SnmpInfo);
526 if (!NT_SUCCESS(Status))
527 goto Error;
528
529 if (SnmpInfo.ipsi_numaddr == 0)
530 continue;
531
532 /* Allocate the address entry array and get them */
533 AddrEntries = HeapAlloc(GetProcessHeap(),
534 HEAP_ZERO_MEMORY,
535 SnmpInfo.ipsi_numaddr * sizeof(AddrEntries[0]));
536 if (!AddrEntries)
537 {
538 Status = STATUS_NO_MEMORY;
539 goto Error;
540 }
541 Status = GetAddrEntries(TcpFile, InterfacesList[i], AddrEntries, SnmpInfo.ipsi_numaddr);
542 if (!NT_SUCCESS(Status))
543 {
544 HeapFree(GetProcessHeap(), 0, AddrEntries);
545 goto Error;
546 }
547
548 for (j = 0; j < SnmpInfo.ipsi_numaddr; j++)
549 {
550 /* Find the adapters struct for this address. */
551 if (pAdapterAddresses)
552 {
553 CurrentAA = pAdapterAddresses;
554 while (CurrentAA)
555 {
556 if (CurrentAA->IfIndex == AddrEntries[j].iae_index)
557 break;
558
559 CurrentAA = CurrentAA->Next;
560 }
561
562 if (!CurrentAA)
563 {
564 ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries[j].iae_index);
565 /* Go to the next address */
566 continue;
567 }
568 }
569
570 ERR("address is 0x%08x, mask is 0x%08x\n", AddrEntries[j].iae_addr, AddrEntries[j].iae_mask);
571
572 //FIXME: For now reactos only supports unicast addresses
573 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
574 {
575 ULONG Size = sizeof(IP_ADAPTER_UNICAST_ADDRESS) + sizeof(SOCKADDR);
576
577 if (Ptr && (RemainingSize >= Size))
578 {
579 PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress = (PIP_ADAPTER_UNICAST_ADDRESS)Ptr;
580
581 /* Fill in the structure */
582 UnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
583 UnicastAddress->Next = CurrentAA->FirstUnicastAddress;
584
585 // FIXME: Put meaningful value here
586 UnicastAddress->Flags = 0;
587 UnicastAddress->PrefixOrigin = IpPrefixOriginOther;
588 UnicastAddress->SuffixOrigin = IpSuffixOriginOther;
589 UnicastAddress->DadState = IpDadStatePreferred;
590 UnicastAddress->ValidLifetime = 0xFFFFFFFF;
591 UnicastAddress->PreferredLifetime = 0xFFFFFFFF;
592
593 /* Set the address */
594 //FIXME: ipv4 only (again...)
595 UnicastAddress->Address.lpSockaddr = (LPSOCKADDR)(UnicastAddress + 1);
596 UnicastAddress->Address.iSockaddrLength = sizeof(AddrEntries[j].iae_addr);
597 UnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
598 memcpy(UnicastAddress->Address.lpSockaddr->sa_data, &AddrEntries[j].iae_addr, sizeof(AddrEntries[j].iae_addr));
599
600 CurrentAA->FirstUnicastAddress = UnicastAddress;
601 Ptr += Size;
602 RemainingSize -= Size;
603 }
604
605 TotalSize += Size;
606 }
607
608 if (Flags & GAA_FLAG_INCLUDE_PREFIX)
609 {
610 ULONG Size = sizeof(IP_ADAPTER_PREFIX) + sizeof(SOCKADDR);
611
612 if (Ptr && (RemainingSize >= Size))
613 {
614 PIP_ADAPTER_PREFIX Prefix = (PIP_ADAPTER_PREFIX)Ptr;
615
616 /* Fill in the structure */
617 Prefix->Length = sizeof(IP_ADAPTER_PREFIX);
618 Prefix->Next = CurrentAA->FirstPrefix;
619
620 /* Set the address */
621 //FIXME: ipv4 only (again...)
622 Prefix->Address.lpSockaddr = (LPSOCKADDR)(Prefix + 1);
623 Prefix->Address.iSockaddrLength = sizeof(AddrEntries[j].iae_mask);
624 Prefix->Address.lpSockaddr->sa_family = AF_INET;
625 memcpy(Prefix->Address.lpSockaddr->sa_data, &AddrEntries[j].iae_mask, sizeof(AddrEntries[j].iae_mask));
626
627 /* Compute the prefix size */
628 _BitScanReverse(&Prefix->PrefixLength, AddrEntries[j].iae_mask);
629
630 CurrentAA->FirstPrefix = Prefix;
631 Ptr += Size;
632 RemainingSize -= Size;
633 }
634
635 TotalSize += Size;
636 }
637 }
638
639 HeapFree(GetProcessHeap(), 0, AddrEntries);
640 }
641 }
642
643 Success:
644 /* We're done */
645 HeapFree(GetProcessHeap(), 0, InterfacesList);
646 NtClose(TcpFile);
647 *pOutBufLen = TotalSize;
648 TRACE("TotalSize: %x\n", *pOutBufLen);
649 return ERROR_SUCCESS;
650
651 Error:
652 ERR("Failed! Status 0x%08x\n", Status);
653 *pOutBufLen = 0;
654 HeapFree(GetProcessHeap(), 0, InterfacesList);
655 NtClose(TcpFile);
656 return RtlNtStatusToDosError(Status);
657 }
658 #endif