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
);
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
;
287 FIXME("GetAdaptersAddresses - Semi Stub: Family %u, Flags 0x%08x, Reserved %p, pAdapterAddress %p, pOutBufLen %p.\n",
288 Family
, Flags
, Reserved
, pAdapterAddresses
, pOutBufLen
);
291 return ERROR_INVALID_PARAMETER
;
293 if ((Family
== AF_INET6
) || (Family
== AF_UNSPEC
))
295 /* One day maybe... */
296 FIXME("IPv6 is not supported in ReactOS!\n");
297 if (Family
== AF_INET6
)
299 /* We got nothing to say in this case */
300 return ERROR_NO_DATA
;
304 RemainingSize
= *pOutBufLen
;
306 ZeroMemory(Ptr
, RemainingSize
);
308 /* open the tcpip driver */
309 Status
= openTcpFile(&TcpFile
);
310 if (!NT_SUCCESS(Status
))
312 ERR("Could not open handle to tcpip.sys. Status %08x\n", Status
);
313 return RtlNtStatusToDosError(Status
);
316 /* Get the interfaces list */
317 Status
= GetInterfacesList(TcpFile
, &InterfacesList
, &InterfacesCount
);
318 if (!NT_SUCCESS(Status
))
320 ERR("Could not get adapters list. Status %08x\n", Status
);
322 return RtlNtStatusToDosError(Status
);
325 /* Let's see if we got any adapter. */
326 for (i
= 0; i
< InterfacesCount
; i
++)
328 PIP_ADAPTER_ADDRESSES CurrentAA
= (PIP_ADAPTER_ADDRESSES
)Ptr
, PreviousAA
= NULL
;
329 ULONG CurrentAASize
= 0;
331 if (InterfacesList
[i
].tei_entity
== IF_ENTITY
)
333 BYTE EntryBuffer
[FIELD_OFFSET(IFEntry
, if_descr
) +
334 RTL_FIELD_SIZE(IFEntry
, if_descr
[0]) * (MAX_ADAPTER_DESCRIPTION_LENGTH
+ 1)];
335 IFEntry
* Entry
= (IFEntry
*)EntryBuffer
;
337 /* Remember we got one */
340 /* Of course we need some space for the base structure. */
341 CurrentAASize
= sizeof(IP_ADAPTER_ADDRESSES
);
344 Status
= GetInterfaceEntry(TcpFile
, InterfacesList
[i
], Entry
);
345 if (!NT_SUCCESS(Status
))
348 TRACE("Got entity %*s, index %u.\n",
349 Entry
->if_descrlen
, &Entry
->if_descr
[0], Entry
->if_index
);
351 /* Add the adapter name */
352 CurrentAASize
+= Entry
->if_descrlen
+ sizeof(CHAR
);
354 /* Add the DNS suffix */
355 CurrentAASize
+= sizeof(WCHAR
);
357 /* Add the description. */
358 CurrentAASize
+= sizeof(WCHAR
);
360 if (!(Flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
362 /* Just an empty string for now. */
363 FIXME("Should get adapter friendly name.\n");
364 CurrentAASize
+= sizeof(WCHAR
);
367 if (!(Flags
& GAA_FLAG_SKIP_DNS_SERVER
))
369 /* Enumerate the name servers */
373 snprintf(KeyName
, 256,
374 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
375 Entry
->if_descrlen
, &Entry
->if_descr
[0]);
377 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, KeyName
, 0, KEY_READ
, &InterfaceKey
) != ERROR_SUCCESS
)
379 ERR("Failed opening interface key for interface %*s\n", Entry
->if_descrlen
, &Entry
->if_descr
[0]);
380 Flags
|= GAA_FLAG_SKIP_DNS_SERVER
;
384 EnumNameServers(InterfaceKey
, NULL
, &CurrentAASize
, EnumerateServerNameSize
);
385 RegCloseKey(InterfaceKey
);
389 /* This is part of what we will need */
390 TotalSize
+= CurrentAASize
;
392 /* Fill in the data */
393 if ((CurrentAA
) && (RemainingSize
>= CurrentAASize
))
395 CurrentAA
->Length
= sizeof(IP_ADAPTER_ADDRESSES
);
396 CurrentAA
->IfIndex
= Entry
->if_index
;
397 CopyMemory(CurrentAA
->PhysicalAddress
, Entry
->if_physaddr
, Entry
->if_physaddrlen
);
398 CurrentAA
->PhysicalAddressLength
= Entry
->if_physaddrlen
;
399 CurrentAA
->Flags
= 0; // FIXME!
400 CurrentAA
->Mtu
= Entry
->if_mtu
;
401 CurrentAA
->IfType
= Entry
->if_type
;
402 CurrentAA
->OperStatus
= Entry
->if_operstatus
;
403 CurrentAA
->Next
= PreviousAA
;
405 Ptr
= (BYTE
*)(CurrentAA
+ 1);
407 /* Now fill in the name */
408 CopyMemory(Ptr
, &Entry
->if_descr
[0], Entry
->if_descrlen
);
409 CurrentAA
->AdapterName
= (PCHAR
)Ptr
;
410 CurrentAA
->AdapterName
[Entry
->if_descrlen
] = '\0';
412 Ptr
= (BYTE
*)(CurrentAA
->AdapterName
+ Entry
->if_descrlen
+ 1);
415 CurrentAA
->DnsSuffix
= (PWCHAR
)Ptr
;
416 CurrentAA
->DnsSuffix
[0] = L
'\0';
418 Ptr
= (BYTE
*)(CurrentAA
->DnsSuffix
+ 1);
420 /* The description */
421 CurrentAA
->Description
= (PWCHAR
)Ptr
;
422 CurrentAA
->Description
[0] = L
'\0';
424 Ptr
= (BYTE
*)(CurrentAA
->Description
+ 1);
426 /* The friendly name */
427 if (!(Flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
429 CurrentAA
->FriendlyName
= (PWCHAR
)Ptr
;
430 CurrentAA
->FriendlyName
[0] = L
'\0';
432 Ptr
= (BYTE
*)(CurrentAA
->FriendlyName
+ 1);
435 /* The DNS Servers */
436 if (!(Flags
& GAA_FLAG_SKIP_DNS_SERVER
))
438 /* Enumerate the name servers */
442 snprintf(KeyName
, 256,
443 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
444 Entry
->if_descrlen
, &Entry
->if_descr
[0]);
446 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, KeyName
, 0, KEY_READ
, &InterfaceKey
) != ERROR_SUCCESS
)
448 ERR("Failed opening interface key for interface %*s\n", Entry
->if_descrlen
, &Entry
->if_descr
[0]);
452 PIP_ADAPTER_DNS_SERVER_ADDRESS
* ServerAddressPtr
;
454 CurrentAA
->FirstDnsServerAddress
= (PIP_ADAPTER_DNS_SERVER_ADDRESS
)Ptr
;
455 ServerAddressPtr
= &CurrentAA
->FirstDnsServerAddress
;
457 EnumNameServers(InterfaceKey
, NULL
, &ServerAddressPtr
, EnumerateServerName
);
458 RegCloseKey(InterfaceKey
);
460 /* Set the last entry in the list as having NULL next member */
461 Ptr
= (BYTE
*)*ServerAddressPtr
;
462 *ServerAddressPtr
= NULL
;
466 /* We're done for this interface */
467 PreviousAA
= CurrentAA
;
468 RemainingSize
-= CurrentAASize
;
473 if (AdaptersCount
== 0)
475 /* Uh? Not even localhost ?! */
476 ERR("No Adapters found!\n");
478 return ERROR_NO_DATA
;
481 /* See if we have anything to add */
482 // FIXME: Anycast and multicast
483 if ((Flags
& (GAA_FLAG_SKIP_UNICAST
| GAA_FLAG_INCLUDE_PREFIX
)) == GAA_FLAG_SKIP_UNICAST
)
486 /* Now fill in the addresses */
487 for (i
= 0; i
< InterfacesCount
; i
++)
489 /* Look for network layers */
490 if ((InterfacesList
[i
].tei_entity
== CL_NL_ENTITY
)
491 || (InterfacesList
[i
].tei_entity
== CO_NL_ENTITY
))
494 PIP_ADAPTER_ADDRESSES CurrentAA
= NULL
;
495 IPAddrEntry
* AddrEntries
;
498 /* Get its SNMP info */
499 Status
= GetSnmpInfo(TcpFile
, InterfacesList
[i
], &SnmpInfo
);
500 if (!NT_SUCCESS(Status
))
503 if (SnmpInfo
.ipsi_numaddr
== 0)
506 /* Allocate the address entry array and get them */
507 AddrEntries
= HeapAlloc(GetProcessHeap(),
509 SnmpInfo
.ipsi_numaddr
* sizeof(AddrEntries
[0]));
512 Status
= STATUS_NO_MEMORY
;
515 Status
= GetAddrEntries(TcpFile
, InterfacesList
[i
], AddrEntries
, SnmpInfo
.ipsi_numaddr
);
516 if (!NT_SUCCESS(Status
))
518 HeapFree(GetProcessHeap(), 0, AddrEntries
);
522 for (j
= 0; j
< SnmpInfo
.ipsi_numaddr
; j
++)
524 /* Find the adapters struct for this address. */
525 if (pAdapterAddresses
)
527 CurrentAA
= pAdapterAddresses
;
530 if (CurrentAA
->IfIndex
== AddrEntries
[j
].iae_index
)
536 ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries
[j
].iae_index
);
537 /* Go to the next address */
542 ERR("address is 0x%08x, mask is 0x%08x\n", AddrEntries
[j
].iae_addr
, AddrEntries
[j
].iae_mask
);
544 //FIXME: For now reactos only supports unicast addresses
545 if (!(Flags
& GAA_FLAG_SKIP_UNICAST
))
547 ULONG Size
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
) + sizeof(SOCKADDR
);
549 if (Ptr
&& (RemainingSize
>= Size
))
551 PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress
= (PIP_ADAPTER_UNICAST_ADDRESS
)Ptr
;
553 /* Fill in the structure */
554 UnicastAddress
->Length
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
);
555 UnicastAddress
->Next
= CurrentAA
->FirstUnicastAddress
;
557 // FIXME: Put meaningful value here
558 UnicastAddress
->Flags
= 0;
559 UnicastAddress
->PrefixOrigin
= IpPrefixOriginOther
;
560 UnicastAddress
->SuffixOrigin
= IpSuffixOriginOther
;
561 UnicastAddress
->DadState
= IpDadStatePreferred
;
562 UnicastAddress
->ValidLifetime
= 0xFFFFFFFF;
563 UnicastAddress
->PreferredLifetime
= 0xFFFFFFFF;
565 /* Set the address */
566 //FIXME: ipv4 only (again...)
567 UnicastAddress
->Address
.lpSockaddr
= (LPSOCKADDR
)(UnicastAddress
+ 1);
568 UnicastAddress
->Address
.iSockaddrLength
= sizeof(AddrEntries
[j
].iae_addr
);
569 UnicastAddress
->Address
.lpSockaddr
->sa_family
= AF_INET
;
570 memcpy(UnicastAddress
->Address
.lpSockaddr
->sa_data
, &AddrEntries
[j
].iae_addr
, sizeof(AddrEntries
[j
].iae_addr
));
572 CurrentAA
->FirstUnicastAddress
= UnicastAddress
;
574 RemainingSize
-= Size
;
580 if (Flags
& GAA_FLAG_INCLUDE_PREFIX
)
582 ULONG Size
= sizeof(IP_ADAPTER_PREFIX
) + sizeof(SOCKADDR
);
584 if (Ptr
&& (RemainingSize
>= Size
))
586 PIP_ADAPTER_PREFIX Prefix
= (PIP_ADAPTER_PREFIX
)Ptr
;
588 /* Fill in the structure */
589 Prefix
->Length
= sizeof(IP_ADAPTER_PREFIX
);
590 Prefix
->Next
= CurrentAA
->FirstPrefix
;
592 /* Set the address */
593 //FIXME: ipv4 only (again...)
594 Prefix
->Address
.lpSockaddr
= (LPSOCKADDR
)(Prefix
+ 1);
595 Prefix
->Address
.iSockaddrLength
= sizeof(AddrEntries
[j
].iae_mask
);
596 Prefix
->Address
.lpSockaddr
->sa_family
= AF_INET
;
597 memcpy(Prefix
->Address
.lpSockaddr
->sa_data
, &AddrEntries
[j
].iae_mask
, sizeof(AddrEntries
[j
].iae_mask
));
599 /* Compute the prefix size */
600 _BitScanReverse(&Prefix
->PrefixLength
, AddrEntries
[j
].iae_mask
);
602 CurrentAA
->FirstPrefix
= Prefix
;
604 RemainingSize
-= Size
;
611 HeapFree(GetProcessHeap(), 0, AddrEntries
);
617 HeapFree(GetProcessHeap(), 0, InterfacesList
);
619 *pOutBufLen
= TotalSize
;
620 return ERROR_SUCCESS
;
623 ERR("Failed! Status 0x%08x\n", Status
);
625 HeapFree(GetProcessHeap(), 0, InterfacesList
);
627 return RtlNtStatusToDosError(Status
);