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 EnumNameServers(InterfaceKey
, NULL
, &CurrentAASize
, EnumerateServerNameSize
);
403 RegCloseKey(InterfaceKey
);
407 /* This is part of what we will need */
408 TotalSize
+= CurrentAASize
;
410 /* Fill in the data */
411 if ((CurrentAA
) && (RemainingSize
>= CurrentAASize
))
413 CurrentAA
->Length
= sizeof(IP_ADAPTER_ADDRESSES
);
414 CurrentAA
->IfIndex
= Entry
->if_index
;
415 CopyMemory(CurrentAA
->PhysicalAddress
, Entry
->if_physaddr
, Entry
->if_physaddrlen
);
416 CurrentAA
->PhysicalAddressLength
= Entry
->if_physaddrlen
;
417 CurrentAA
->Flags
= 0; // FIXME!
418 CurrentAA
->Mtu
= Entry
->if_mtu
;
419 CurrentAA
->IfType
= Entry
->if_type
;
420 if(Entry
->if_operstatus
>= IF_OPER_STATUS_CONNECTING
)
421 CurrentAA
->OperStatus
= IfOperStatusUp
;
423 CurrentAA
->OperStatus
= IfOperStatusDown
;
426 Ptr
= (BYTE
*)(CurrentAA
+ 1);
428 /* Now fill in the name */
429 CopyMemory(Ptr
, &Entry
->if_descr
[0], Entry
->if_descrlen
);
430 CurrentAA
->AdapterName
= (PCHAR
)Ptr
;
431 CurrentAA
->AdapterName
[Entry
->if_descrlen
] = '\0';
433 Ptr
= (BYTE
*)(CurrentAA
->AdapterName
+ Entry
->if_descrlen
+ 1);
436 CurrentAA
->DnsSuffix
= (PWCHAR
)Ptr
;
437 CurrentAA
->DnsSuffix
[0] = L
'\0';
439 Ptr
= (BYTE
*)(CurrentAA
->DnsSuffix
+ 1);
441 /* The description */
442 CurrentAA
->Description
= (PWCHAR
)Ptr
;
443 CurrentAA
->Description
[0] = L
'\0';
445 Ptr
= (BYTE
*)(CurrentAA
->Description
+ 1);
447 /* The friendly name */
448 if (!(Flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
450 CurrentAA
->FriendlyName
= (PWCHAR
)Ptr
;
451 CurrentAA
->FriendlyName
[0] = L
'\0';
453 Ptr
= (BYTE
*)(CurrentAA
->FriendlyName
+ 1);
456 /* The DNS Servers */
457 if (!(Flags
& GAA_FLAG_SKIP_DNS_SERVER
))
459 /* Enumerate the name servers */
463 snprintf(KeyName
, 256,
464 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%*s",
465 Entry
->if_descrlen
, &Entry
->if_descr
[0]);
467 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
, KeyName
, 0, KEY_READ
, &InterfaceKey
) != ERROR_SUCCESS
)
469 TRACE("Failed opening interface key for interface %*s\n", Entry
->if_descrlen
, &Entry
->if_descr
[0]);
473 PIP_ADAPTER_DNS_SERVER_ADDRESS
* ServerAddressPtr
;
475 CurrentAA
->FirstDnsServerAddress
= (PIP_ADAPTER_DNS_SERVER_ADDRESS
)Ptr
;
476 ServerAddressPtr
= &CurrentAA
->FirstDnsServerAddress
;
478 EnumNameServers(InterfaceKey
, NULL
, &ServerAddressPtr
, EnumerateServerName
);
479 RegCloseKey(InterfaceKey
);
481 /* Set the last entry in the list as having NULL next member */
482 Ptr
= (BYTE
*)*ServerAddressPtr
;
483 *ServerAddressPtr
= NULL
;
487 /* We're done for this interface */
488 PreviousAA
= CurrentAA
;
489 RemainingSize
-= CurrentAASize
;
494 if (AdaptersCount
== 0)
496 /* Uh? Not even localhost ?! */
497 ERR("No Adapters found!\n");
499 return ERROR_NO_DATA
;
502 /* See if we have anything to add */
503 // FIXME: Anycast and multicast
504 if ((Flags
& (GAA_FLAG_SKIP_UNICAST
| GAA_FLAG_INCLUDE_PREFIX
)) == GAA_FLAG_SKIP_UNICAST
)
507 /* Now fill in the addresses */
508 for (i
= 0; i
< InterfacesCount
; i
++)
510 /* Look for network layers */
511 if ((InterfacesList
[i
].tei_entity
== CL_NL_ENTITY
)
512 || (InterfacesList
[i
].tei_entity
== CO_NL_ENTITY
))
515 PIP_ADAPTER_ADDRESSES CurrentAA
= NULL
;
516 IPAddrEntry
* AddrEntries
;
519 /* Get its SNMP info */
520 Status
= GetSnmpInfo(TcpFile
, InterfacesList
[i
], &SnmpInfo
);
521 if (!NT_SUCCESS(Status
))
524 if (SnmpInfo
.ipsi_numaddr
== 0)
527 /* Allocate the address entry array and get them */
528 AddrEntries
= HeapAlloc(GetProcessHeap(),
530 SnmpInfo
.ipsi_numaddr
* sizeof(AddrEntries
[0]));
533 Status
= STATUS_NO_MEMORY
;
536 Status
= GetAddrEntries(TcpFile
, InterfacesList
[i
], AddrEntries
, SnmpInfo
.ipsi_numaddr
);
537 if (!NT_SUCCESS(Status
))
539 HeapFree(GetProcessHeap(), 0, AddrEntries
);
543 for (j
= 0; j
< SnmpInfo
.ipsi_numaddr
; j
++)
545 /* Find the adapters struct for this address. */
546 if (pAdapterAddresses
)
548 CurrentAA
= pAdapterAddresses
;
551 if (CurrentAA
->IfIndex
== AddrEntries
[j
].iae_index
)
554 CurrentAA
= CurrentAA
->Next
;
559 ERR("Got address for interface %u but no adapter was found for it.\n", AddrEntries
[j
].iae_index
);
560 /* Go to the next address */
565 TRACE("address is 0x%08x, mask is 0x%08x\n", AddrEntries
[j
].iae_addr
, AddrEntries
[j
].iae_mask
);
567 //FIXME: For now reactos only supports unicast addresses
568 if (!(Flags
& GAA_FLAG_SKIP_UNICAST
))
570 ULONG Size
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
) + sizeof(SOCKADDR
);
572 if (Ptr
&& (RemainingSize
>= Size
))
574 PIP_ADAPTER_UNICAST_ADDRESS UnicastAddress
= (PIP_ADAPTER_UNICAST_ADDRESS
)Ptr
;
576 /* Fill in the structure */
577 UnicastAddress
->Length
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
);
578 UnicastAddress
->Next
= CurrentAA
->FirstUnicastAddress
;
580 // FIXME: Put meaningful value here
581 UnicastAddress
->Flags
= 0;
582 UnicastAddress
->PrefixOrigin
= IpPrefixOriginOther
;
583 UnicastAddress
->SuffixOrigin
= IpSuffixOriginOther
;
584 UnicastAddress
->DadState
= IpDadStatePreferred
;
585 UnicastAddress
->ValidLifetime
= 0xFFFFFFFF;
586 UnicastAddress
->PreferredLifetime
= 0xFFFFFFFF;
588 /* Set the address */
589 //FIXME: ipv4 only (again...)
590 UnicastAddress
->Address
.lpSockaddr
= (LPSOCKADDR
)(UnicastAddress
+ 1);
591 UnicastAddress
->Address
.iSockaddrLength
= sizeof(SOCKADDR
);
592 UnicastAddress
->Address
.lpSockaddr
->sa_family
= AF_INET
;
593 ((LPSOCKADDR_IN
)UnicastAddress
->Address
.lpSockaddr
)->sin_port
= 0;
594 memcpy(&((LPSOCKADDR_IN
)UnicastAddress
->Address
.lpSockaddr
)->sin_addr
, &AddrEntries
[j
].iae_addr
, sizeof(AddrEntries
[j
].iae_addr
));
596 CurrentAA
->FirstUnicastAddress
= UnicastAddress
;
598 RemainingSize
-= Size
;
604 if (Flags
& GAA_FLAG_INCLUDE_PREFIX
)
606 ULONG Size
= sizeof(IP_ADAPTER_PREFIX
) + sizeof(SOCKADDR
);
608 if (Ptr
&& (RemainingSize
>= Size
))
610 PIP_ADAPTER_PREFIX Prefix
= (PIP_ADAPTER_PREFIX
)Ptr
;
612 /* Fill in the structure */
613 Prefix
->Length
= sizeof(IP_ADAPTER_PREFIX
);
614 Prefix
->Next
= CurrentAA
->FirstPrefix
;
616 /* Set the address */
617 //FIXME: ipv4 only (again...)
618 Prefix
->Address
.lpSockaddr
= (LPSOCKADDR
)(Prefix
+ 1);
619 Prefix
->Address
.iSockaddrLength
= sizeof(AddrEntries
[j
].iae_mask
);
620 Prefix
->Address
.lpSockaddr
->sa_family
= AF_INET
;
621 memcpy(Prefix
->Address
.lpSockaddr
->sa_data
, &AddrEntries
[j
].iae_mask
, sizeof(AddrEntries
[j
].iae_mask
));
623 /* Compute the prefix size */
624 _BitScanReverse(&Prefix
->PrefixLength
, AddrEntries
[j
].iae_mask
);
626 CurrentAA
->FirstPrefix
= Prefix
;
628 RemainingSize
-= Size
;
635 HeapFree(GetProcessHeap(), 0, AddrEntries
);
641 HeapFree(GetProcessHeap(), 0, InterfacesList
);
643 *pOutBufLen
= TotalSize
;
644 TRACE("TotalSize: %x\n", *pOutBufLen
);
645 return ERROR_SUCCESS
;
648 ERR("Failed! Status 0x%08x\n", Status
);
650 HeapFree(GetProcessHeap(), 0, InterfacesList
);
652 return RtlNtStatusToDosError(Status
);