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)
9 #include "iphlpapi_private.h"
11 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
12 #ifdef GetAdaptersAddressesV2
13 /* Helper for GetAdaptersAddresses:
14 * Retrieves the list of network adapters from tcpip.sys */
19 _Out_ TDIEntityID
**EntityList
,
20 _Out_ ULONG
* InterfaceCount
)
23 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo
;
24 IO_STATUS_BLOCK StatusBlock
;
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;
35 Status
= NtDeviceIoControlFile(
41 IOCTL_TCP_QUERY_INFORMATION_EX
,
46 if (Status
== STATUS_PENDING
)
48 /* So we have to wait a bit */
49 Status
= NtWaitForSingleObject(TcpFile
, FALSE
, NULL
);
50 if (NT_SUCCESS(Status
))
51 Status
= StatusBlock
.Status
;
54 if (!NT_SUCCESS(Status
))
57 BufferSize
= StatusBlock
.Information
;
58 *EntityList
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
60 return STATUS_NO_MEMORY
;
62 /* Do the real call */
63 Status
= NtDeviceIoControlFile(
69 IOCTL_TCP_QUERY_INFORMATION_EX
,
74 if (Status
== STATUS_PENDING
)
76 /* So we have to wait a bit */
77 Status
= NtWaitForSingleObject(TcpFile
, FALSE
, NULL
);
78 if (NT_SUCCESS(Status
))
79 Status
= StatusBlock
.Status
;
82 if (!NT_SUCCESS(Status
))
84 HeapFree(GetProcessHeap(), 0, *EntityList
);
88 *InterfaceCount
= BufferSize
/ sizeof(TDIEntityID
);
96 _In_ TDIEntityID InterfaceID
,
97 _Out_ IPSNMPInfo
* Info
)
99 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo
;
100 IO_STATUS_BLOCK StatusBlock
;
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
;
109 Status
= NtDeviceIoControlFile(
115 IOCTL_TCP_QUERY_INFORMATION_EX
,
117 sizeof(TcpQueryInfo
),
120 if (Status
== STATUS_PENDING
)
122 /* So we have to wait a bit */
123 Status
= NtWaitForSingleObject(TcpFile
, FALSE
, NULL
);
124 if (NT_SUCCESS(Status
))
125 Status
= StatusBlock
.Status
;
135 _In_ TDIEntityID InterfaceID
,
136 _Out_ IPAddrEntry
* Entries
,
137 _In_ ULONG NumEntries
)
139 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo
;
140 IO_STATUS_BLOCK StatusBlock
;
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
;
149 Status
= NtDeviceIoControlFile(
155 IOCTL_TCP_QUERY_INFORMATION_EX
,
157 sizeof(TcpQueryInfo
),
159 NumEntries
* sizeof(Entries
[0]));
160 if (Status
== STATUS_PENDING
)
162 /* So we have to wait a bit */
163 Status
= NtWaitForSingleObject(TcpFile
, FALSE
, NULL
);
164 if (NT_SUCCESS(Status
))
165 Status
= StatusBlock
.Status
;
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. ;-)
180 _In_ TDIEntityID InterfaceID
,
181 _Out_ IFEntry
* Entry
)
183 TCP_REQUEST_QUERY_INFORMATION_EX TcpQueryInfo
;
184 IO_STATUS_BLOCK StatusBlock
;
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
;
193 Status
= NtDeviceIoControlFile(
199 IOCTL_TCP_QUERY_INFORMATION_EX
,
201 sizeof(TcpQueryInfo
),
203 FIELD_OFFSET(IFEntry
, if_descr
[MAX_ADAPTER_DESCRIPTION_LENGTH
+ 1]));
204 if (Status
== STATUS_PENDING
)
206 /* So we have to wait a bit */
207 Status
= NtWaitForSingleObject(TcpFile
, FALSE
, NULL
);
208 if (NT_SUCCESS(Status
))
209 Status
= StatusBlock
.Status
;
215 /* Helpers to get the list of DNS for an interface */
218 EnumerateServerNameSize(
219 _In_ PWCHAR Interface
,
220 _In_ PWCHAR NameServer
,
223 ULONG
* BufferSize
= Data
;
225 /* This is just sizing here */
226 UNREFERENCED_PARAMETER(Interface
);
227 UNREFERENCED_PARAMETER(NameServer
);
229 *BufferSize
+= sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS
) + sizeof(SOCKADDR
);
235 _In_ PWCHAR Interface
,
236 _In_ PWCHAR NameServer
,
239 PIP_ADAPTER_DNS_SERVER_ADDRESS
** Ptr
= Data
;
240 PIP_ADAPTER_DNS_SERVER_ADDRESS ServerAddress
= **Ptr
;
242 UNREFERENCED_PARAMETER(Interface
);
244 ServerAddress
->Length
= sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS
);
245 ServerAddress
->Address
.lpSockaddr
= (PVOID
)(ServerAddress
+ 1);
246 ServerAddress
->Address
.iSockaddrLength
= sizeof(SOCKADDR
);
249 /* Get the address from the server name string */
250 //FIXME: Only ipv4 for now...
251 if (WSAStringToAddressW(
255 ServerAddress
->Address
.lpSockaddr
,
256 &ServerAddress
->Address
.iSockaddrLength
))
258 /* Pass along, name conversion failed */
259 ERR("%S is not a valid IP address\n", NameServer
);
263 /* Go to next item */
264 ServerAddress
->Next
= (PVOID
)(ServerAddress
->Address
.lpSockaddr
+ 1);
265 *Ptr
= &ServerAddress
->Next
;
271 GetAdaptersAddresses(
275 _Inout_ PIP_ADAPTER_ADDRESSES pAdapterAddresses
,
276 _Inout_ PULONG pOutBufLen
)
280 TDIEntityID
* InterfacesList
;
281 ULONG InterfacesCount
;
282 ULONG AdaptersCount
= 0;
284 ULONG TotalSize
= 0, RemainingSize
;
285 BYTE
* Ptr
= (BYTE
*)pAdapterAddresses
;
286 DWORD MIN_SIZE
= 15 * 1024;
287 PIP_ADAPTER_ADDRESSES PreviousAA
= NULL
;
289 FIXME("GetAdaptersAddresses - Semi Stub: Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p.\n",
290 Family
, Flags
, Reserved
, pAdapterAddresses
, pOutBufLen
);
293 return ERROR_INVALID_PARAMETER
;
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
)
299 *pOutBufLen
= MIN_SIZE
;
300 return ERROR_BUFFER_OVERFLOW
;
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
;
314 WARN("IPv6 addresses ignored, IPv4 only\n");
318 ERR("Invalid family 0x%x\n", Family
);
319 return ERROR_INVALID_PARAMETER
;
323 RemainingSize
= *pOutBufLen
;
325 ZeroMemory(Ptr
, RemainingSize
);
327 /* open the tcpip driver */
328 Status
= openTcpFile(&TcpFile
, FILE_READ_DATA
);
329 if (!NT_SUCCESS(Status
))
331 ERR("Could not open handle to tcpip.sys. Status %08x\n", Status
);
332 return RtlNtStatusToDosError(Status
);
335 /* Get the interfaces list */
336 Status
= GetInterfacesList(TcpFile
, &InterfacesList
, &InterfacesCount
);
337 if (!NT_SUCCESS(Status
))
339 ERR("Could not get adapters list. Status %08x\n", Status
);
341 return RtlNtStatusToDosError(Status
);
344 /* Let's see if we got any adapter. */
345 for (i
= 0; i
< InterfacesCount
; i
++)
347 PIP_ADAPTER_ADDRESSES CurrentAA
= (PIP_ADAPTER_ADDRESSES
)Ptr
;
348 ULONG CurrentAASize
= 0;
350 if (InterfacesList
[i
].tei_entity
== IF_ENTITY
)
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
;
356 /* Remember we got one */
359 /* Set the pointer to this instance in the previous one*/
361 PreviousAA
->Next
= CurrentAA
;
363 /* Of course we need some space for the base structure. */
364 CurrentAASize
= sizeof(IP_ADAPTER_ADDRESSES
);
367 Status
= GetInterfaceEntry(TcpFile
, InterfacesList
[i
], Entry
);
368 if (!NT_SUCCESS(Status
))
371 TRACE("Got entity %*s, index %u.\n",
372 Entry
->if_descrlen
, &Entry
->if_descr
[0], Entry
->if_index
);
374 /* Add the adapter name */
375 CurrentAASize
+= Entry
->if_descrlen
+ sizeof(CHAR
);
377 /* Add the DNS suffix */
378 CurrentAASize
+= sizeof(WCHAR
);
380 /* Add the description. */
381 CurrentAASize
+= sizeof(WCHAR
);
383 if (!(Flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
385 /* Just an empty string for now. */
386 FIXME("Should get adapter friendly name.\n");
387 CurrentAASize
+= sizeof(WCHAR
);
390 if (!(Flags
& GAA_FLAG_SKIP_DNS_SERVER
))
392 /* Enumerate the name servers */
396 snprintf(KeyName
, 256,
397 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
398 Entry
->if_descrlen
, &Entry
->if_descr
[0]);
400 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, KeyName
, 0, KEY_READ
, &InterfaceKey
) != ERROR_SUCCESS
)
402 ERR("Failed opening interface key for interface %*s\n", Entry
->if_descrlen
, &Entry
->if_descr
[0]);
403 Flags
|= GAA_FLAG_SKIP_DNS_SERVER
;
407 EnumNameServers(InterfaceKey
, NULL
, &CurrentAASize
, EnumerateServerNameSize
);
408 RegCloseKey(InterfaceKey
);
412 /* This is part of what we will need */
413 TotalSize
+= CurrentAASize
;
415 /* Fill in the data */
416 if ((CurrentAA
) && (RemainingSize
>= CurrentAASize
))
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
;
428 CurrentAA
->OperStatus
= IfOperStatusDown
;
431 Ptr
= (BYTE
*)(CurrentAA
+ 1);
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';
438 Ptr
= (BYTE
*)(CurrentAA
->AdapterName
+ Entry
->if_descrlen
+ 1);
441 CurrentAA
->DnsSuffix
= (PWCHAR
)Ptr
;
442 CurrentAA
->DnsSuffix
[0] = L
'\0';
444 Ptr
= (BYTE
*)(CurrentAA
->DnsSuffix
+ 1);
446 /* The description */
447 CurrentAA
->Description
= (PWCHAR
)Ptr
;
448 CurrentAA
->Description
[0] = L
'\0';
450 Ptr
= (BYTE
*)(CurrentAA
->Description
+ 1);
452 /* The friendly name */
453 if (!(Flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
455 CurrentAA
->FriendlyName
= (PWCHAR
)Ptr
;
456 CurrentAA
->FriendlyName
[0] = L
'\0';
458 Ptr
= (BYTE
*)(CurrentAA
->FriendlyName
+ 1);
461 /* The DNS Servers */
462 if (!(Flags
& GAA_FLAG_SKIP_DNS_SERVER
))
464 /* Enumerate the name servers */
468 snprintf(KeyName
, 256,
469 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
470 Entry
->if_descrlen
, &Entry
->if_descr
[0]);
472 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, KeyName
, 0, KEY_READ
, &InterfaceKey
) != ERROR_SUCCESS
)
474 ERR("Failed opening interface key for interface %*s\n", Entry
->if_descrlen
, &Entry
->if_descr
[0]);
478 PIP_ADAPTER_DNS_SERVER_ADDRESS
* ServerAddressPtr
;
480 CurrentAA
->FirstDnsServerAddress
= (PIP_ADAPTER_DNS_SERVER_ADDRESS
)Ptr
;
481 ServerAddressPtr
= &CurrentAA
->FirstDnsServerAddress
;
483 EnumNameServers(InterfaceKey
, NULL
, &ServerAddressPtr
, EnumerateServerName
);
484 RegCloseKey(InterfaceKey
);
486 /* Set the last entry in the list as having NULL next member */
487 Ptr
= (BYTE
*)*ServerAddressPtr
;
488 *ServerAddressPtr
= NULL
;
492 /* We're done for this interface */
493 PreviousAA
= CurrentAA
;
494 RemainingSize
-= CurrentAASize
;
499 if (AdaptersCount
== 0)
501 /* Uh? Not even localhost ?! */
502 ERR("No Adapters found!\n");
504 return ERROR_NO_DATA
;
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
)
512 /* Now fill in the addresses */
513 for (i
= 0; i
< InterfacesCount
; i
++)
515 /* Look for network layers */
516 if ((InterfacesList
[i
].tei_entity
== CL_NL_ENTITY
)
517 || (InterfacesList
[i
].tei_entity
== CO_NL_ENTITY
))
520 PIP_ADAPTER_ADDRESSES CurrentAA
= NULL
;
521 IPAddrEntry
* AddrEntries
;
524 /* Get its SNMP info */
525 Status
= GetSnmpInfo(TcpFile
, InterfacesList
[i
], &SnmpInfo
);
526 if (!NT_SUCCESS(Status
))
529 if (SnmpInfo
.ipsi_numaddr
== 0)
532 /* Allocate the address entry array and get them */
533 AddrEntries
= HeapAlloc(GetProcessHeap(),
535 SnmpInfo
.ipsi_numaddr
* sizeof(AddrEntries
[0]));
538 Status
= STATUS_NO_MEMORY
;
541 Status
= GetAddrEntries(TcpFile
, InterfacesList
[i
], AddrEntries
, SnmpInfo
.ipsi_numaddr
);
542 if (!NT_SUCCESS(Status
))
544 HeapFree(GetProcessHeap(), 0, AddrEntries
);
548 for (j
= 0; j
< SnmpInfo
.ipsi_numaddr
; j
++)
550 /* Find the adapters struct for this address. */
551 if (pAdapterAddresses
)
553 CurrentAA
= pAdapterAddresses
;
556 if (CurrentAA
->IfIndex
== AddrEntries
[j
].iae_index
)
559 CurrentAA
= CurrentAA
->Next
;
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 */
570 ERR("address is 0x%08x, mask is 0x%08x\n", AddrEntries
[j
].iae_addr
, AddrEntries
[j
].iae_mask
);
572 //FIXME: For now reactos only supports unicast addresses
573 if (!(Flags
& GAA_FLAG_SKIP_UNICAST
))
575 ULONG Size
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
) + sizeof(SOCKADDR
);
577 if (Ptr
&& (RemainingSize
>= Size
))
579 PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress
= (PIP_ADAPTER_UNICAST_ADDRESS
)Ptr
;
581 /* Fill in the structure */
582 UnicastAddress
->Length
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
);
583 UnicastAddress
->Next
= CurrentAA
->FirstUnicastAddress
;
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;
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
));
600 CurrentAA
->FirstUnicastAddress
= UnicastAddress
;
602 RemainingSize
-= Size
;
608 if (Flags
& GAA_FLAG_INCLUDE_PREFIX
)
610 ULONG Size
= sizeof(IP_ADAPTER_PREFIX
) + sizeof(SOCKADDR
);
612 if (Ptr
&& (RemainingSize
>= Size
))
614 PIP_ADAPTER_PREFIX Prefix
= (PIP_ADAPTER_PREFIX
)Ptr
;
616 /* Fill in the structure */
617 Prefix
->Length
= sizeof(IP_ADAPTER_PREFIX
);
618 Prefix
->Next
= CurrentAA
->FirstPrefix
;
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
));
627 /* Compute the prefix size */
628 _BitScanReverse(&Prefix
->PrefixLength
, AddrEntries
[j
].iae_mask
);
630 CurrentAA
->FirstPrefix
= Prefix
;
632 RemainingSize
-= Size
;
639 HeapFree(GetProcessHeap(), 0, AddrEntries
);
645 HeapFree(GetProcessHeap(), 0, InterfacesList
);
647 *pOutBufLen
= TotalSize
;
648 TRACE("TotalSize: %x\n", *pOutBufLen
);
649 return ERROR_SUCCESS
;
652 ERR("Failed! Status 0x%08x\n", Status
);
654 HeapFree(GetProcessHeap(), 0, InterfacesList
);
656 return RtlNtStatusToDosError(Status
);