2 * iphlpapi dll implementation
4 * Copyright (C) 2003,2006 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <sys/types.h>
27 #ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
33 #ifdef HAVE_ARPA_NAMESER_H
34 # include <arpa/nameser.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
60 #define IF_NAMESIZE 16
64 #define INADDR_NONE ~0UL
67 /******************************************************************
68 * AddIPAddress (IPHLPAPI.@)
70 * Add an IP address to an adapter.
73 * Address [In] IP address to add to the adapter
74 * IpMask [In] subnet mask for the IP address
75 * IfIndex [In] adapter index to add the address
76 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
77 * NTEInstance [Out] NTE instance for the IP address
81 * Failure: error code from winerror.h
84 * Stub. Currently returns ERROR_NOT_SUPPORTED.
86 DWORD WINAPI
AddIPAddress(IPAddr Address
, IPMask IpMask
, DWORD IfIndex
, PULONG NTEContext
, PULONG NTEInstance
)
89 return ERROR_NOT_SUPPORTED
;
93 /******************************************************************
94 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
96 * Get table of local interfaces.
97 * Like GetIfTable(), but allocate the returned table from heap.
100 * ppIfTable [Out] pointer into which the MIB_IFTABLE is
101 * allocated and returned.
102 * bOrder [In] whether to sort the table
103 * heap [In] heap from which the table is allocated
104 * flags [In] flags to HeapAlloc
107 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
108 * GetIfTable() returns otherwise.
110 DWORD WINAPI
AllocateAndGetIfTableFromStack(PMIB_IFTABLE
*ppIfTable
,
111 BOOL bOrder
, HANDLE heap
, DWORD flags
)
115 TRACE("ppIfTable %p, bOrder %d, heap %p, flags 0x%08x\n", ppIfTable
,
116 bOrder
, heap
, flags
);
118 ret
= ERROR_INVALID_PARAMETER
;
122 ret
= GetIfTable(*ppIfTable
, &dwSize
, bOrder
);
123 if (ret
== ERROR_INSUFFICIENT_BUFFER
) {
124 *ppIfTable
= HeapAlloc(heap
, flags
, dwSize
);
125 ret
= GetIfTable(*ppIfTable
, &dwSize
, bOrder
);
128 TRACE("returning %d\n", ret
);
133 static int IpAddrTableSorter(const void *a
, const void *b
)
138 ret
= ((const MIB_IPADDRROW
*)a
)->dwAddr
- ((const MIB_IPADDRROW
*)b
)->dwAddr
;
145 /******************************************************************
146 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
148 * Get interface-to-IP address mapping table.
149 * Like GetIpAddrTable(), but allocate the returned table from heap.
152 * ppIpAddrTable [Out] pointer into which the MIB_IPADDRTABLE is
153 * allocated and returned.
154 * bOrder [In] whether to sort the table
155 * heap [In] heap from which the table is allocated
156 * flags [In] flags to HeapAlloc
159 * ERROR_INVALID_PARAMETER if ppIpAddrTable is NULL, other error codes on
160 * failure, NO_ERROR on success.
162 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE
*ppIpAddrTable
,
163 BOOL bOrder
, HANDLE heap
, DWORD flags
)
167 TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
168 ppIpAddrTable
, bOrder
, heap
, flags
);
169 ret
= getIPAddrTable(ppIpAddrTable
, heap
, flags
);
171 qsort((*ppIpAddrTable
)->table
, (*ppIpAddrTable
)->dwNumEntries
,
172 sizeof(MIB_IPADDRROW
), IpAddrTableSorter
);
173 TRACE("returning %d\n", ret
);
178 /******************************************************************
179 * CancelIPChangeNotify (IPHLPAPI.@)
181 * Cancel a previous notification created by NotifyAddrChange or
185 * overlapped [In] overlapped structure that notifies the caller
192 * Stub, returns FALSE.
194 BOOL WINAPI
CancelIPChangeNotify(LPOVERLAPPED overlapped
)
196 FIXME("(overlapped %p): stub\n", overlapped
);
201 /******************************************************************
202 * CancelMibChangeNotify2 (IPHLPAPI.@)
204 DWORD WINAPI
CancelMibChangeNotify2(HANDLE handle
)
206 FIXME("(handle %p): stub\n", handle
);
211 /******************************************************************
212 * CreateIpForwardEntry (IPHLPAPI.@)
214 * Create a route in the local computer's IP table.
217 * pRoute [In] new route information
221 * Failure: error code from winerror.h
224 * Stub, always returns NO_ERROR.
226 DWORD WINAPI
CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
228 FIXME("(pRoute %p): stub\n", pRoute
);
229 /* could use SIOCADDRT, not sure I want to */
234 /******************************************************************
235 * CreateIpNetEntry (IPHLPAPI.@)
237 * Create entry in the ARP table.
240 * pArpEntry [In] new ARP entry
244 * Failure: error code from winerror.h
247 * Stub, always returns NO_ERROR.
249 DWORD WINAPI
CreateIpNetEntry(PMIB_IPNETROW pArpEntry
)
251 FIXME("(pArpEntry %p)\n", pArpEntry
);
252 /* could use SIOCSARP on systems that support it, not sure I want to */
257 /******************************************************************
258 * CreateProxyArpEntry (IPHLPAPI.@)
260 * Create a Proxy ARP (PARP) entry for an IP address.
263 * dwAddress [In] IP address for which this computer acts as a proxy.
264 * dwMask [In] subnet mask for dwAddress
265 * dwIfIndex [In] interface index
269 * Failure: error code from winerror.h
272 * Stub, returns ERROR_NOT_SUPPORTED.
274 DWORD WINAPI
CreateProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
276 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
277 dwAddress
, dwMask
, dwIfIndex
);
278 return ERROR_NOT_SUPPORTED
;
282 /******************************************************************
283 * CreateSortedAddressPairs (IPHLPAPI.@)
285 DWORD WINAPI
CreateSortedAddressPairs(const PSOCKADDR_IN6 source
, DWORD sourcecount
,
286 const PSOCKADDR_IN6 destination
, DWORD destinationcount
,
288 PSOCKADDR_IN6_PAIR
*sortedaddr
, DWORD
*sortedcount
)
290 FIXME("(source %p, sourcecount %d, destination %p, destcount %d, sortoptions %x,"
291 " sortedaddr %p, sortedcount %p): stub\n", source
, sourcecount
, destination
,
292 destinationcount
, sortoptions
, sortedaddr
, sortedcount
);
294 if (source
|| sourcecount
|| !destination
|| !sortedaddr
|| !sortedcount
|| destinationcount
> 500)
295 return ERROR_INVALID_PARAMETER
;
297 /* Returning not supported tells the client we don't have IPv6 support
298 * so applications can fallback to IPv4.
300 return ERROR_NOT_SUPPORTED
;
304 /******************************************************************
305 * DeleteIPAddress (IPHLPAPI.@)
307 * Delete an IP address added with AddIPAddress().
310 * NTEContext [In] NTE context from AddIPAddress();
314 * Failure: error code from winerror.h
317 * Stub, returns ERROR_NOT_SUPPORTED.
319 DWORD WINAPI
DeleteIPAddress(ULONG NTEContext
)
321 FIXME("(NTEContext %d): stub\n", NTEContext
);
322 return ERROR_NOT_SUPPORTED
;
326 /******************************************************************
327 * DeleteIpForwardEntry (IPHLPAPI.@)
332 * pRoute [In] route to delete
336 * Failure: error code from winerror.h
339 * Stub, returns NO_ERROR.
341 DWORD WINAPI
DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
343 FIXME("(pRoute %p): stub\n", pRoute
);
344 /* could use SIOCDELRT, not sure I want to */
349 /******************************************************************
350 * DeleteIpNetEntry (IPHLPAPI.@)
352 * Delete an ARP entry.
355 * pArpEntry [In] ARP entry to delete
359 * Failure: error code from winerror.h
362 * Stub, returns NO_ERROR.
364 DWORD WINAPI
DeleteIpNetEntry(PMIB_IPNETROW pArpEntry
)
366 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
367 /* could use SIOCDARP on systems that support it, not sure I want to */
372 /******************************************************************
373 * DeleteProxyArpEntry (IPHLPAPI.@)
375 * Delete a Proxy ARP entry.
378 * dwAddress [In] IP address for which this computer acts as a proxy.
379 * dwMask [In] subnet mask for dwAddress
380 * dwIfIndex [In] interface index
384 * Failure: error code from winerror.h
387 * Stub, returns ERROR_NOT_SUPPORTED.
389 DWORD WINAPI
DeleteProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
391 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
392 dwAddress
, dwMask
, dwIfIndex
);
393 return ERROR_NOT_SUPPORTED
;
397 /******************************************************************
398 * EnableRouter (IPHLPAPI.@)
400 * Turn on ip forwarding.
404 * pOverlapped [In/Out] hEvent member should contain a valid handle.
407 * Success: ERROR_IO_PENDING
408 * Failure: error code from winerror.h
411 * Stub, returns ERROR_NOT_SUPPORTED.
413 DWORD WINAPI
EnableRouter(HANDLE
* pHandle
, OVERLAPPED
* pOverlapped
)
415 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle
, pOverlapped
);
416 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
417 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
419 return ERROR_NOT_SUPPORTED
;
423 /******************************************************************
424 * FlushIpNetTable (IPHLPAPI.@)
426 * Delete all ARP entries of an interface
429 * dwIfIndex [In] interface index
433 * Failure: error code from winerror.h
436 * Stub, returns ERROR_NOT_SUPPORTED.
438 DWORD WINAPI
FlushIpNetTable(DWORD dwIfIndex
)
440 FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex
);
441 /* this flushes the arp cache of the given index */
442 return ERROR_NOT_SUPPORTED
;
445 /******************************************************************
446 * FreeMibTable (IPHLPAPI.@)
448 * Free buffer allocated by network functions
451 * ptr [In] pointer to the buffer to free
454 void WINAPI
FreeMibTable(void *ptr
)
456 TRACE("(%p)\n", ptr
);
457 HeapFree(GetProcessHeap(), 0, ptr
);
460 /******************************************************************
461 * GetAdapterIndex (IPHLPAPI.@)
463 * Get interface index from its name.
466 * AdapterName [In] unicode string with the adapter name
467 * IfIndex [Out] returns found interface index
471 * Failure: error code from winerror.h
473 DWORD WINAPI
GetAdapterIndex(LPWSTR AdapterName
, PULONG IfIndex
)
475 char adapterName
[MAX_ADAPTER_NAME
];
479 TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName
, IfIndex
);
480 /* The adapter name is guaranteed not to have any unicode characters, so
481 * this translation is never lossy */
482 for (i
= 0; i
< sizeof(adapterName
) - 1 && AdapterName
[i
]; i
++)
483 adapterName
[i
] = (char)AdapterName
[i
];
484 adapterName
[i
] = '\0';
485 ret
= getInterfaceIndexByName(adapterName
, IfIndex
);
486 TRACE("returning %d\n", ret
);
491 /******************************************************************
492 * GetAdaptersInfo (IPHLPAPI.@)
494 * Get information about adapters.
497 * pAdapterInfo [Out] buffer for adapter infos
498 * pOutBufLen [In] length of output buffer
502 * Failure: error code from winerror.h
504 DWORD WINAPI
GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo
, PULONG pOutBufLen
)
508 TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo
, pOutBufLen
);
510 ret
= ERROR_INVALID_PARAMETER
;
512 DWORD numNonLoopbackInterfaces
= get_interface_indices( TRUE
, NULL
);
514 if (numNonLoopbackInterfaces
> 0) {
515 DWORD numIPAddresses
= getNumIPAddresses();
518 /* This may slightly overestimate the amount of space needed, because
519 * the IP addresses include the loopback address, but it's easier
520 * to make sure there's more than enough space than to make sure there's
521 * precisely enough space.
523 size
= sizeof(IP_ADAPTER_INFO
) * numNonLoopbackInterfaces
;
524 size
+= numIPAddresses
* sizeof(IP_ADDR_STRING
);
525 if (!pAdapterInfo
|| *pOutBufLen
< size
) {
527 ret
= ERROR_BUFFER_OVERFLOW
;
530 InterfaceIndexTable
*table
= NULL
;
531 PMIB_IPADDRTABLE ipAddrTable
= NULL
;
532 PMIB_IPFORWARDTABLE routeTable
= NULL
;
534 ret
= getIPAddrTable(&ipAddrTable
, GetProcessHeap(), 0);
536 ret
= AllocateAndGetIpForwardTableFromStack(&routeTable
, FALSE
, GetProcessHeap(), 0);
538 get_interface_indices( TRUE
, &table
);
540 size
= sizeof(IP_ADAPTER_INFO
) * table
->numIndexes
;
541 size
+= ipAddrTable
->dwNumEntries
* sizeof(IP_ADDR_STRING
);
542 if (*pOutBufLen
< size
) {
544 ret
= ERROR_INSUFFICIENT_BUFFER
;
549 BOOL winsEnabled
= FALSE
;
550 IP_ADDRESS_STRING primaryWINS
, secondaryWINS
;
551 PIP_ADDR_STRING nextIPAddr
= (PIP_ADDR_STRING
)((LPBYTE
)pAdapterInfo
552 + numNonLoopbackInterfaces
* sizeof(IP_ADAPTER_INFO
));
554 memset(pAdapterInfo
, 0, size
);
555 /* @@ Wine registry key: HKCU\Software\Wine\Network */
556 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Network",
557 &hKey
) == ERROR_SUCCESS
) {
558 DWORD size
= sizeof(primaryWINS
.String
);
561 RegQueryValueExA(hKey
, "WinsServer", NULL
, NULL
,
562 (LPBYTE
)primaryWINS
.String
, &size
);
563 addr
= inet_addr(primaryWINS
.String
);
564 if (addr
!= INADDR_NONE
&& addr
!= INADDR_ANY
)
566 size
= sizeof(secondaryWINS
.String
);
567 RegQueryValueExA(hKey
, "BackupWinsServer", NULL
, NULL
,
568 (LPBYTE
)secondaryWINS
.String
, &size
);
569 addr
= inet_addr(secondaryWINS
.String
);
570 if (addr
!= INADDR_NONE
&& addr
!= INADDR_ANY
)
574 for (ndx
= 0; ndx
< table
->numIndexes
; ndx
++) {
575 PIP_ADAPTER_INFO ptr
= &pAdapterInfo
[ndx
];
577 PIP_ADDR_STRING currentIPAddr
= &ptr
->IpAddressList
;
578 BOOL firstIPAddr
= TRUE
;
580 /* on Win98 this is left empty, but whatever */
581 getInterfaceNameByIndex(table
->indexes
[ndx
], ptr
->AdapterName
);
582 getInterfaceNameByIndex(table
->indexes
[ndx
], ptr
->Description
);
583 ptr
->AddressLength
= sizeof(ptr
->Address
);
584 getInterfacePhysicalByIndex(table
->indexes
[ndx
],
585 &ptr
->AddressLength
, ptr
->Address
, &ptr
->Type
);
586 ptr
->Index
= table
->indexes
[ndx
];
587 for (i
= 0; i
< ipAddrTable
->dwNumEntries
; i
++) {
588 if (ipAddrTable
->table
[i
].dwIndex
== ptr
->Index
) {
590 toIPAddressString(ipAddrTable
->table
[i
].dwAddr
,
591 ptr
->IpAddressList
.IpAddress
.String
);
592 toIPAddressString(ipAddrTable
->table
[i
].dwMask
,
593 ptr
->IpAddressList
.IpMask
.String
);
597 currentIPAddr
->Next
= nextIPAddr
;
598 currentIPAddr
= nextIPAddr
;
599 toIPAddressString(ipAddrTable
->table
[i
].dwAddr
,
600 currentIPAddr
->IpAddress
.String
);
601 toIPAddressString(ipAddrTable
->table
[i
].dwMask
,
602 currentIPAddr
->IpMask
.String
);
607 /* If no IP was found it probably means that the interface is not
608 * configured. In this case we have to return a zeroed IP and mask. */
610 strcpy(ptr
->IpAddressList
.IpAddress
.String
, "0.0.0.0");
611 strcpy(ptr
->IpAddressList
.IpMask
.String
, "0.0.0.0");
613 /* Find first router through this interface, which we'll assume
614 * is the default gateway for this adapter */
615 for (i
= 0; i
< routeTable
->dwNumEntries
; i
++)
616 if (routeTable
->table
[i
].dwForwardIfIndex
== ptr
->Index
617 && routeTable
->table
[i
].u1
.ForwardType
==
618 MIB_IPROUTE_TYPE_INDIRECT
)
620 toIPAddressString(routeTable
->table
[i
].dwForwardNextHop
,
621 ptr
->GatewayList
.IpAddress
.String
);
622 toIPAddressString(routeTable
->table
[i
].dwForwardMask
,
623 ptr
->GatewayList
.IpMask
.String
);
626 ptr
->HaveWins
= TRUE
;
627 memcpy(ptr
->PrimaryWinsServer
.IpAddress
.String
,
628 primaryWINS
.String
, sizeof(primaryWINS
.String
));
629 memcpy(ptr
->SecondaryWinsServer
.IpAddress
.String
,
630 secondaryWINS
.String
, sizeof(secondaryWINS
.String
));
632 if (ndx
< table
->numIndexes
- 1)
633 ptr
->Next
= &pAdapterInfo
[ndx
+ 1];
637 ptr
->DhcpEnabled
= TRUE
;
641 HeapFree(GetProcessHeap(), 0, table
);
644 ret
= ERROR_OUTOFMEMORY
;
645 HeapFree(GetProcessHeap(), 0, routeTable
);
646 HeapFree(GetProcessHeap(), 0, ipAddrTable
);
652 TRACE("returning %d\n", ret
);
656 static DWORD
typeFromMibType(DWORD mib_type
)
660 case MIB_IF_TYPE_ETHERNET
: return IF_TYPE_ETHERNET_CSMACD
;
661 case MIB_IF_TYPE_TOKENRING
: return IF_TYPE_ISO88025_TOKENRING
;
662 case MIB_IF_TYPE_PPP
: return IF_TYPE_PPP
;
663 case MIB_IF_TYPE_LOOPBACK
: return IF_TYPE_SOFTWARE_LOOPBACK
;
664 default: return IF_TYPE_OTHER
;
668 static NET_IF_CONNECTION_TYPE
connectionTypeFromMibType(DWORD mib_type
)
672 case MIB_IF_TYPE_PPP
: return NET_IF_CONNECTION_DEMAND
;
673 case MIB_IF_TYPE_SLIP
: return NET_IF_CONNECTION_DEMAND
;
674 default: return NET_IF_CONNECTION_DEDICATED
;
678 static ULONG
v4addressesFromIndex(IF_INDEX index
, DWORD
**addrs
, ULONG
*num_addrs
, DWORD
**masks
)
684 if ((ret
= getIPAddrTable(&at
, GetProcessHeap(), 0))) return ret
;
685 for (i
= 0; i
< at
->dwNumEntries
; i
++)
687 if (at
->table
[i
].dwIndex
== index
) (*num_addrs
)++;
689 if (!(*addrs
= HeapAlloc(GetProcessHeap(), 0, *num_addrs
* sizeof(DWORD
))))
691 HeapFree(GetProcessHeap(), 0, at
);
692 return ERROR_OUTOFMEMORY
;
694 if (!(*masks
= HeapAlloc(GetProcessHeap(), 0, *num_addrs
* sizeof(DWORD
))))
696 HeapFree(GetProcessHeap(), 0, *addrs
);
697 HeapFree(GetProcessHeap(), 0, at
);
698 return ERROR_OUTOFMEMORY
;
700 for (i
= 0, j
= 0; i
< at
->dwNumEntries
; i
++)
702 if (at
->table
[i
].dwIndex
== index
)
704 (*addrs
)[j
] = at
->table
[i
].dwAddr
;
705 (*masks
)[j
] = at
->table
[i
].dwMask
;
709 HeapFree(GetProcessHeap(), 0, at
);
710 return ERROR_SUCCESS
;
713 static char *debugstr_ipv4(const in_addr_t
*in_addr
, char *buf
)
718 for (addrp
= (const BYTE
*)in_addr
;
719 addrp
- (const BYTE
*)in_addr
< sizeof(*in_addr
);
722 if (addrp
== (const BYTE
*)in_addr
+ sizeof(*in_addr
) - 1)
723 sprintf(p
, "%d", *addrp
);
725 p
+= sprintf(p
, "%d.", *addrp
);
730 static char *debugstr_ipv6(const struct WS_sockaddr_in6
*sin
, char *buf
)
732 const IN6_ADDR
*addr
= &sin
->sin6_addr
;
735 BOOL in_zero
= FALSE
;
737 for (i
= 0; i
< 7; i
++)
739 if (!addr
->u
.Word
[i
])
751 p
+= sprintf(p
, "%x:", ntohs(addr
->u
.Word
[i
]));
755 sprintf(p
, "%x", ntohs(addr
->u
.Word
[7]));
759 static ULONG
count_v4_gateways(DWORD index
, PMIB_IPFORWARDTABLE routeTable
)
761 DWORD i
, num_gateways
= 0;
763 for (i
= 0; i
< routeTable
->dwNumEntries
; i
++)
765 if (routeTable
->table
[i
].dwForwardIfIndex
== index
&&
766 routeTable
->table
[i
].u1
.ForwardType
== MIB_IPROUTE_TYPE_INDIRECT
)
772 static PMIB_IPFORWARDROW
findIPv4Gateway(DWORD index
,
773 PMIB_IPFORWARDTABLE routeTable
)
776 PMIB_IPFORWARDROW row
= NULL
;
778 for (i
= 0; !row
&& i
< routeTable
->dwNumEntries
; i
++)
780 if (routeTable
->table
[i
].dwForwardIfIndex
== index
&&
781 routeTable
->table
[i
].u1
.ForwardType
== MIB_IPROUTE_TYPE_INDIRECT
)
782 row
= &routeTable
->table
[i
];
787 static void fill_unicast_addr_data(IP_ADAPTER_ADDRESSES
*aa
, IP_ADAPTER_UNICAST_ADDRESS
*ua
)
789 /* Actually this information should be read somewhere from the system
790 * but it doesn't matter much for the bugs found so far.
791 * This information is required for DirectPlay8 games. */
792 if (aa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
)
794 ua
->PrefixOrigin
= IpPrefixOriginDhcp
;
795 ua
->SuffixOrigin
= IpSuffixOriginDhcp
;
799 ua
->PrefixOrigin
= IpPrefixOriginManual
;
800 ua
->SuffixOrigin
= IpSuffixOriginManual
;
803 /* The address is not duplicated in the network */
804 ua
->DadState
= IpDadStatePreferred
;
806 /* Some address life time values, required even for non-dhcp addresses */
807 ua
->ValidLifetime
= 60000;
808 ua
->PreferredLifetime
= 60000;
809 ua
->LeaseLifetime
= 60000;
812 static ULONG
adapterAddressesFromIndex(ULONG family
, ULONG flags
, IF_INDEX index
,
813 IP_ADAPTER_ADDRESSES
*aa
, ULONG
*size
)
815 ULONG ret
= ERROR_SUCCESS
, i
, j
, num_v4addrs
= 0, num_v4_gateways
= 0, num_v6addrs
= 0, total_size
;
816 DWORD
*v4addrs
= NULL
, *v4masks
= NULL
;
817 SOCKET_ADDRESS
*v6addrs
= NULL
, *v6masks
= NULL
;
818 PMIB_IPFORWARDTABLE routeTable
= NULL
;
820 if (family
== WS_AF_INET
)
822 ret
= v4addressesFromIndex(index
, &v4addrs
, &num_v4addrs
, &v4masks
);
824 if (!ret
&& flags
& GAA_FLAG_INCLUDE_ALL_GATEWAYS
)
826 ret
= AllocateAndGetIpForwardTableFromStack(&routeTable
, FALSE
, GetProcessHeap(), 0);
827 if (!ret
) num_v4_gateways
= count_v4_gateways(index
, routeTable
);
830 else if (family
== WS_AF_INET6
)
832 ret
= v6addressesFromIndex(index
, &v6addrs
, &num_v6addrs
, &v6masks
);
834 else if (family
== WS_AF_UNSPEC
)
836 ret
= v4addressesFromIndex(index
, &v4addrs
, &num_v4addrs
, &v4masks
);
838 if (!ret
&& flags
& GAA_FLAG_INCLUDE_ALL_GATEWAYS
)
840 ret
= AllocateAndGetIpForwardTableFromStack(&routeTable
, FALSE
, GetProcessHeap(), 0);
841 if (!ret
) num_v4_gateways
= count_v4_gateways(index
, routeTable
);
843 if (!ret
) ret
= v6addressesFromIndex(index
, &v6addrs
, &num_v6addrs
, &v6masks
);
847 FIXME("address family %u unsupported\n", family
);
852 HeapFree(GetProcessHeap(), 0, v4addrs
);
853 HeapFree(GetProcessHeap(), 0, v4masks
);
854 HeapFree(GetProcessHeap(), 0, v6addrs
);
855 HeapFree(GetProcessHeap(), 0, v6masks
);
856 HeapFree(GetProcessHeap(), 0, routeTable
);
860 total_size
= sizeof(IP_ADAPTER_ADDRESSES
);
861 total_size
+= IF_NAMESIZE
;
862 total_size
+= IF_NAMESIZE
* sizeof(WCHAR
);
863 if (!(flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
864 total_size
+= IF_NAMESIZE
* sizeof(WCHAR
);
865 if (flags
& GAA_FLAG_INCLUDE_PREFIX
)
867 total_size
+= sizeof(IP_ADAPTER_PREFIX
) * num_v4addrs
;
868 total_size
+= sizeof(IP_ADAPTER_PREFIX
) * num_v6addrs
;
869 total_size
+= sizeof(struct sockaddr_in
) * num_v4addrs
;
870 for (i
= 0; i
< num_v6addrs
; i
++)
871 total_size
+= v6masks
[i
].iSockaddrLength
;
873 total_size
+= sizeof(IP_ADAPTER_UNICAST_ADDRESS
) * num_v4addrs
;
874 total_size
+= sizeof(struct sockaddr_in
) * num_v4addrs
;
875 total_size
+= (sizeof(IP_ADAPTER_GATEWAY_ADDRESS
) + sizeof(SOCKADDR_IN
)) * num_v4_gateways
;
876 total_size
+= sizeof(IP_ADAPTER_UNICAST_ADDRESS
) * num_v6addrs
;
877 total_size
+= sizeof(SOCKET_ADDRESS
) * num_v6addrs
;
878 for (i
= 0; i
< num_v6addrs
; i
++)
879 total_size
+= v6addrs
[i
].iSockaddrLength
;
881 if (aa
&& *size
>= total_size
)
883 char name
[IF_NAMESIZE
], *ptr
= (char *)aa
+ sizeof(IP_ADAPTER_ADDRESSES
), *src
;
886 INTERNAL_IF_OPER_STATUS status
;
888 memset(aa
, 0, sizeof(IP_ADAPTER_ADDRESSES
));
889 aa
->u
.s
.Length
= sizeof(IP_ADAPTER_ADDRESSES
);
890 aa
->u
.s
.IfIndex
= index
;
892 getInterfaceNameByIndex(index
, name
);
893 memcpy(ptr
, name
, IF_NAMESIZE
);
894 aa
->AdapterName
= ptr
;
896 if (!(flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
898 aa
->FriendlyName
= (WCHAR
*)ptr
;
899 for (src
= name
, dst
= (WCHAR
*)ptr
; *src
; src
++, dst
++)
904 aa
->Description
= (WCHAR
*)ptr
;
905 for (src
= name
, dst
= (WCHAR
*)ptr
; *src
; src
++, dst
++)
910 TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name
, num_v4addrs
,
913 buflen
= MAX_INTERFACE_PHYSADDR
;
914 getInterfacePhysicalByIndex(index
, &buflen
, aa
->PhysicalAddress
, &type
);
915 aa
->PhysicalAddressLength
= buflen
;
916 aa
->IfType
= typeFromMibType(type
);
917 aa
->ConnectionType
= connectionTypeFromMibType(type
);
921 PMIB_IPFORWARDROW adapterRow
;
923 if ((adapterRow
= findIPv4Gateway(index
, routeTable
)))
925 PIP_ADAPTER_GATEWAY_ADDRESS gw
;
928 gw
= (PIP_ADAPTER_GATEWAY_ADDRESS
)ptr
;
929 aa
->FirstGatewayAddress
= gw
;
931 gw
->u
.s
.Length
= sizeof(IP_ADAPTER_GATEWAY_ADDRESS
);
932 ptr
+= sizeof(IP_ADAPTER_GATEWAY_ADDRESS
);
933 sin
= (PSOCKADDR_IN
)ptr
;
934 sin
->sin_family
= AF_INET
;
936 memcpy(&sin
->sin_addr
, &adapterRow
->dwForwardNextHop
,
938 gw
->Address
.lpSockaddr
= (LPSOCKADDR
)sin
;
939 gw
->Address
.iSockaddrLength
= sizeof(SOCKADDR_IN
);
941 ptr
+= sizeof(SOCKADDR_IN
);
944 if (num_v4addrs
&& !(flags
& GAA_FLAG_SKIP_UNICAST
))
946 IP_ADAPTER_UNICAST_ADDRESS
*ua
;
947 struct WS_sockaddr_in
*sa
;
948 aa
->Flags
|= IP_ADAPTER_IPV4_ENABLED
;
949 ua
= aa
->FirstUnicastAddress
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
950 for (i
= 0; i
< num_v4addrs
; i
++)
954 memset(ua
, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS
));
955 ua
->u
.s
.Length
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
);
956 ua
->Address
.iSockaddrLength
= sizeof(struct sockaddr_in
);
957 ua
->Address
.lpSockaddr
= (SOCKADDR
*)((char *)ua
+ ua
->u
.s
.Length
);
959 sa
= (struct WS_sockaddr_in
*)ua
->Address
.lpSockaddr
;
960 sa
->sin_family
= WS_AF_INET
;
961 sa
->sin_addr
.S_un
.S_addr
= v4addrs
[i
];
963 TRACE("IPv4 %d/%d: %s\n", i
+ 1, num_v4addrs
,
964 debugstr_ipv4(&sa
->sin_addr
.S_un
.S_addr
, addr_buf
));
965 fill_unicast_addr_data(aa
, ua
);
967 ptr
+= ua
->u
.s
.Length
+ ua
->Address
.iSockaddrLength
;
968 if (i
< num_v4addrs
- 1)
970 ua
->Next
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
975 if (num_v6addrs
&& !(flags
& GAA_FLAG_SKIP_UNICAST
))
977 IP_ADAPTER_UNICAST_ADDRESS
*ua
;
978 struct WS_sockaddr_in6
*sa
;
980 aa
->Flags
|= IP_ADAPTER_IPV6_ENABLED
;
981 if (aa
->FirstUnicastAddress
)
983 for (ua
= aa
->FirstUnicastAddress
; ua
->Next
; ua
= ua
->Next
)
985 ua
->Next
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
986 ua
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
989 ua
= aa
->FirstUnicastAddress
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
990 for (i
= 0; i
< num_v6addrs
; i
++)
994 memset(ua
, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS
));
995 ua
->u
.s
.Length
= sizeof(IP_ADAPTER_UNICAST_ADDRESS
);
996 ua
->Address
.iSockaddrLength
= v6addrs
[i
].iSockaddrLength
;
997 ua
->Address
.lpSockaddr
= (SOCKADDR
*)((char *)ua
+ ua
->u
.s
.Length
);
999 sa
= (struct WS_sockaddr_in6
*)ua
->Address
.lpSockaddr
;
1000 memcpy(sa
, v6addrs
[i
].lpSockaddr
, sizeof(*sa
));
1001 TRACE("IPv6 %d/%d: %s\n", i
+ 1, num_v6addrs
,
1002 debugstr_ipv6(sa
, addr_buf
));
1003 fill_unicast_addr_data(aa
, ua
);
1005 ptr
+= ua
->u
.s
.Length
+ ua
->Address
.iSockaddrLength
;
1006 if (i
< num_v6addrs
- 1)
1008 ua
->Next
= (IP_ADAPTER_UNICAST_ADDRESS
*)ptr
;
1013 if (num_v4addrs
&& (flags
& GAA_FLAG_INCLUDE_PREFIX
))
1015 IP_ADAPTER_PREFIX
*prefix
;
1017 prefix
= aa
->FirstPrefix
= (IP_ADAPTER_PREFIX
*)ptr
;
1018 for (i
= 0; i
< num_v4addrs
; i
++)
1021 struct WS_sockaddr_in
*sa
;
1023 prefix
->u
.s
.Length
= sizeof(*prefix
);
1024 prefix
->u
.s
.Flags
= 0;
1025 prefix
->Next
= NULL
;
1026 prefix
->Address
.iSockaddrLength
= sizeof(struct sockaddr_in
);
1027 prefix
->Address
.lpSockaddr
= (SOCKADDR
*)((char *)prefix
+ prefix
->u
.s
.Length
);
1029 sa
= (struct WS_sockaddr_in
*)prefix
->Address
.lpSockaddr
;
1030 sa
->sin_family
= WS_AF_INET
;
1031 sa
->sin_addr
.S_un
.S_addr
= v4addrs
[i
] & v4masks
[i
];
1034 prefix
->PrefixLength
= 0;
1035 for (j
= 0; j
< sizeof(*v4masks
) * 8; j
++)
1037 if (v4masks
[i
] & 1 << j
) prefix
->PrefixLength
++;
1040 TRACE("IPv4 network: %s/%u\n",
1041 debugstr_ipv4((const in_addr_t
*)&sa
->sin_addr
.S_un
.S_addr
, addr_buf
),
1042 prefix
->PrefixLength
);
1044 ptr
+= prefix
->u
.s
.Length
+ prefix
->Address
.iSockaddrLength
;
1045 if (i
< num_v4addrs
- 1)
1047 prefix
->Next
= (IP_ADAPTER_PREFIX
*)ptr
;
1048 prefix
= prefix
->Next
;
1052 if (num_v6addrs
&& (flags
& GAA_FLAG_INCLUDE_PREFIX
))
1054 IP_ADAPTER_PREFIX
*prefix
;
1056 if (aa
->FirstPrefix
)
1058 for (prefix
= aa
->FirstPrefix
; prefix
->Next
; prefix
= prefix
->Next
)
1060 prefix
->Next
= (IP_ADAPTER_PREFIX
*)ptr
;
1061 prefix
= (IP_ADAPTER_PREFIX
*)ptr
;
1064 prefix
= aa
->FirstPrefix
= (IP_ADAPTER_PREFIX
*)ptr
;
1065 for (i
= 0; i
< num_v6addrs
; i
++)
1068 struct WS_sockaddr_in6
*sa
;
1069 const IN6_ADDR
*addr
, *mask
;
1073 prefix
->u
.s
.Length
= sizeof(*prefix
);
1074 prefix
->u
.s
.Flags
= 0;
1075 prefix
->Next
= NULL
;
1076 prefix
->Address
.iSockaddrLength
= sizeof(struct sockaddr_in6
);
1077 prefix
->Address
.lpSockaddr
= (SOCKADDR
*)((char *)prefix
+ prefix
->u
.s
.Length
);
1079 sa
= (struct WS_sockaddr_in6
*)prefix
->Address
.lpSockaddr
;
1080 sa
->sin6_family
= WS_AF_INET6
;
1082 sa
->sin6_flowinfo
= 0;
1083 addr
= &((struct WS_sockaddr_in6
*)v6addrs
[i
].lpSockaddr
)->sin6_addr
;
1084 mask
= &((struct WS_sockaddr_in6
*)v6masks
[i
].lpSockaddr
)->sin6_addr
;
1085 for (j
= 0; j
< 8; j
++) sa
->sin6_addr
.u
.Word
[j
] = addr
->u
.Word
[j
] & mask
->u
.Word
[j
];
1086 sa
->sin6_scope_id
= 0;
1088 prefix
->PrefixLength
= 0;
1089 for (k
= 0; k
< 8 && !done
; k
++)
1091 for (j
= 0; j
< sizeof(WORD
) * 8 && !done
; j
++)
1093 if (mask
->u
.Word
[k
] & 1 << j
) prefix
->PrefixLength
++;
1097 TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa
, addr_buf
), prefix
->PrefixLength
);
1099 ptr
+= prefix
->u
.s
.Length
+ prefix
->Address
.iSockaddrLength
;
1100 if (i
< num_v6addrs
- 1)
1102 prefix
->Next
= (IP_ADAPTER_PREFIX
*)ptr
;
1103 prefix
= prefix
->Next
;
1108 getInterfaceMtuByName(name
, &aa
->Mtu
);
1110 getInterfaceStatusByName(name
, &status
);
1111 if (status
== MIB_IF_OPER_STATUS_OPERATIONAL
) aa
->OperStatus
= IfOperStatusUp
;
1112 else if (status
== MIB_IF_OPER_STATUS_NON_OPERATIONAL
) aa
->OperStatus
= IfOperStatusDown
;
1113 else aa
->OperStatus
= IfOperStatusUnknown
;
1116 HeapFree(GetProcessHeap(), 0, routeTable
);
1117 HeapFree(GetProcessHeap(), 0, v6addrs
);
1118 HeapFree(GetProcessHeap(), 0, v6masks
);
1119 HeapFree(GetProcessHeap(), 0, v4addrs
);
1120 HeapFree(GetProcessHeap(), 0, v4masks
);
1121 return ERROR_SUCCESS
;
1124 static void sockaddr_in_to_WS_storage( SOCKADDR_STORAGE
*dst
, const struct sockaddr_in
*src
)
1126 SOCKADDR_IN
*s
= (SOCKADDR_IN
*)dst
;
1128 s
->sin_family
= WS_AF_INET
;
1129 s
->sin_port
= src
->sin_port
;
1130 memcpy( &s
->sin_addr
, &src
->sin_addr
, sizeof(IN_ADDR
) );
1131 memset( (char *)s
+ FIELD_OFFSET( SOCKADDR_IN
, sin_zero
), 0,
1132 sizeof(SOCKADDR_STORAGE
) - FIELD_OFFSET( SOCKADDR_IN
, sin_zero
) );
1135 static void sockaddr_in6_to_WS_storage( SOCKADDR_STORAGE
*dst
, const struct sockaddr_in6
*src
)
1137 SOCKADDR_IN6
*s
= (SOCKADDR_IN6
*)dst
;
1139 s
->sin6_family
= WS_AF_INET6
;
1140 s
->sin6_port
= src
->sin6_port
;
1141 s
->sin6_flowinfo
= src
->sin6_flowinfo
;
1142 memcpy( &s
->sin6_addr
, &src
->sin6_addr
, sizeof(IN6_ADDR
) );
1143 s
->sin6_scope_id
= src
->sin6_scope_id
;
1144 memset( (char *)s
+ sizeof(SOCKADDR_IN6
), 0,
1145 sizeof(SOCKADDR_STORAGE
) - sizeof(SOCKADDR_IN6
) );
1148 #ifdef HAVE_STRUCT___RES_STATE
1149 /* call res_init() just once because of a bug in Mac OS X 10.4 */
1150 /* Call once per thread on systems that have per-thread _res. */
1152 static CRITICAL_SECTION res_init_cs
;
1153 static CRITICAL_SECTION_DEBUG res_init_cs_debug
= {
1155 { &res_init_cs_debug
.ProcessLocksList
, &res_init_cs_debug
.ProcessLocksList
},
1156 0, 0, { (DWORD_PTR
)(__FILE__
": res_init_cs") }
1158 static CRITICAL_SECTION res_init_cs
= { &res_init_cs_debug
, -1, 0, 0, 0, 0 };
1160 static void initialise_resolver(void)
1162 EnterCriticalSection(&res_init_cs
);
1163 if ((_res
.options
& RES_INIT
) == 0)
1165 LeaveCriticalSection(&res_init_cs
);
1168 static int get_dns_servers( SOCKADDR_STORAGE
*servers
, int num
, BOOL ip4_only
)
1170 int i
, ip6_count
= 0;
1171 SOCKADDR_STORAGE
*addr
;
1173 initialise_resolver();
1175 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1176 ip6_count
= _res
._u
._ext
.nscount6
;
1179 if (!servers
|| !num
)
1182 if (ip4_only
) num
-= ip6_count
;
1186 for (i
= 0, addr
= servers
; addr
< (servers
+ num
) && i
< _res
.nscount
; i
++)
1188 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1189 if (_res
._u
._ext
.nsaddrs
[i
])
1191 if (ip4_only
) continue;
1192 sockaddr_in6_to_WS_storage( addr
, _res
._u
._ext
.nsaddrs
[i
] );
1197 sockaddr_in_to_WS_storage( addr
, _res
.nsaddr_list
+ i
);
1201 return addr
- servers
;
1203 #elif defined(HAVE___RES_GET_STATE) && defined(HAVE___RES_GETSERVERS)
1205 static int get_dns_servers( SOCKADDR_STORAGE
*servers
, int num
, BOOL ip4_only
)
1207 extern struct res_state
*__res_get_state( void );
1208 extern int __res_getservers( struct res_state
*, struct sockaddr_storage
*, int );
1209 struct res_state
*state
= __res_get_state();
1210 int i
, found
= 0, total
= __res_getservers( state
, NULL
, 0 );
1211 SOCKADDR_STORAGE
*addr
= servers
;
1212 struct sockaddr_storage
*buf
;
1214 if ((!servers
|| !num
) && !ip4_only
) return total
;
1216 buf
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(struct sockaddr_storage
) );
1217 total
= __res_getservers( state
, buf
, total
);
1219 for (i
= 0; i
< total
; i
++)
1221 if (buf
[i
].ss_family
== AF_INET6
&& ip4_only
) continue;
1222 if (buf
[i
].ss_family
!= AF_INET
&& buf
[i
].ss_family
!= AF_INET6
) continue;
1225 if (!servers
|| !num
) continue;
1227 if (buf
[i
].ss_family
== AF_INET6
)
1229 sockaddr_in6_to_WS_storage( addr
, (struct sockaddr_in6
*)(buf
+ i
) );
1233 sockaddr_in_to_WS_storage( addr
, (struct sockaddr_in
*)(buf
+ i
) );
1235 if (++addr
>= servers
+ num
) break;
1238 HeapFree( GetProcessHeap(), 0, buf
);
1243 static int get_dns_servers( SOCKADDR_STORAGE
*servers
, int num
, BOOL ip4_only
)
1245 FIXME("Unimplemented on this system\n");
1250 static ULONG
get_dns_server_addresses(PIP_ADAPTER_DNS_SERVER_ADDRESS address
, ULONG
*len
)
1252 int num
= get_dns_servers( NULL
, 0, FALSE
);
1255 size
= num
* (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS
) + sizeof(SOCKADDR_STORAGE
));
1256 if (!address
|| *len
< size
)
1259 return ERROR_BUFFER_OVERFLOW
;
1264 PIP_ADAPTER_DNS_SERVER_ADDRESS addr
= address
;
1265 SOCKADDR_STORAGE
*sock_addrs
= (SOCKADDR_STORAGE
*)(address
+ num
);
1268 get_dns_servers( sock_addrs
, num
, FALSE
);
1270 for (i
= 0; i
< num
; i
++, addr
= addr
->Next
)
1272 addr
->u
.s
.Length
= sizeof(*addr
);
1273 if (sock_addrs
[i
].ss_family
== WS_AF_INET6
)
1274 addr
->Address
.iSockaddrLength
= sizeof(SOCKADDR_IN6
);
1276 addr
->Address
.iSockaddrLength
= sizeof(SOCKADDR_IN
);
1277 addr
->Address
.lpSockaddr
= (SOCKADDR
*)(sock_addrs
+ i
);
1281 addr
->Next
= addr
+ 1;
1284 return ERROR_SUCCESS
;
1287 #ifdef HAVE_STRUCT___RES_STATE
1288 static BOOL
is_ip_address_string(const char *str
)
1293 ret
= inet_aton(str
, &in
);
1298 static ULONG
get_dns_suffix(WCHAR
*suffix
, ULONG
*len
)
1301 const char *found_suffix
= "";
1302 /* Always return a NULL-terminated string, even if it's empty. */
1304 #ifdef HAVE_STRUCT___RES_STATE
1307 initialise_resolver();
1308 for (i
= 0; !*found_suffix
&& i
< MAXDNSRCH
+ 1 && _res
.dnsrch
[i
]; i
++)
1310 /* This uses a heuristic to select a DNS suffix:
1311 * the first, non-IP address string is selected.
1313 if (!is_ip_address_string(_res
.dnsrch
[i
]))
1314 found_suffix
= _res
.dnsrch
[i
];
1319 size
= MultiByteToWideChar( CP_UNIXCP
, 0, found_suffix
, -1, NULL
, 0 ) * sizeof(WCHAR
);
1320 if (!suffix
|| *len
< size
)
1323 return ERROR_BUFFER_OVERFLOW
;
1325 *len
= MultiByteToWideChar( CP_UNIXCP
, 0, found_suffix
, -1, suffix
, *len
/ sizeof(WCHAR
) ) * sizeof(WCHAR
);
1326 return ERROR_SUCCESS
;
1329 ULONG WINAPI DECLSPEC_HOTPATCH
GetAdaptersAddresses(ULONG family
, ULONG flags
, PVOID reserved
,
1330 PIP_ADAPTER_ADDRESSES aa
, PULONG buflen
)
1332 InterfaceIndexTable
*table
;
1333 ULONG i
, size
, dns_server_size
= 0, dns_suffix_size
, total_size
, ret
= ERROR_NO_DATA
;
1335 TRACE("(%d, %08x, %p, %p, %p)\n", family
, flags
, reserved
, aa
, buflen
);
1337 if (!buflen
) return ERROR_INVALID_PARAMETER
;
1339 get_interface_indices( FALSE
, &table
);
1340 if (!table
|| !table
->numIndexes
)
1342 HeapFree(GetProcessHeap(), 0, table
);
1343 return ERROR_NO_DATA
;
1346 for (i
= 0; i
< table
->numIndexes
; i
++)
1349 if ((ret
= adapterAddressesFromIndex(family
, flags
, table
->indexes
[i
], NULL
, &size
)))
1351 HeapFree(GetProcessHeap(), 0, table
);
1356 if (!(flags
& GAA_FLAG_SKIP_DNS_SERVER
))
1358 /* Since DNS servers aren't really per adapter, get enough space for a
1359 * single copy of them.
1361 get_dns_server_addresses(NULL
, &dns_server_size
);
1362 total_size
+= dns_server_size
;
1364 /* Since DNS suffix also isn't really per adapter, get enough space for a
1365 * single copy of it.
1367 get_dns_suffix(NULL
, &dns_suffix_size
);
1368 total_size
+= dns_suffix_size
;
1369 if (aa
&& *buflen
>= total_size
)
1371 ULONG bytes_left
= size
= total_size
;
1372 PIP_ADAPTER_ADDRESSES first_aa
= aa
;
1373 PIP_ADAPTER_DNS_SERVER_ADDRESS firstDns
;
1376 for (i
= 0; i
< table
->numIndexes
; i
++)
1378 if ((ret
= adapterAddressesFromIndex(family
, flags
, table
->indexes
[i
], aa
, &size
)))
1380 HeapFree(GetProcessHeap(), 0, table
);
1383 if (i
< table
->numIndexes
- 1)
1385 aa
->Next
= (IP_ADAPTER_ADDRESSES
*)((char *)aa
+ size
);
1387 size
= bytes_left
-= size
;
1390 if (dns_server_size
)
1392 firstDns
= (PIP_ADAPTER_DNS_SERVER_ADDRESS
)((BYTE
*)first_aa
+ total_size
- dns_server_size
- dns_suffix_size
);
1393 get_dns_server_addresses(firstDns
, &dns_server_size
);
1394 for (aa
= first_aa
; aa
; aa
= aa
->Next
)
1396 if (aa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
&& aa
->OperStatus
== IfOperStatusUp
)
1397 aa
->FirstDnsServerAddress
= firstDns
;
1401 dnsSuffix
= (WCHAR
*)((BYTE
*)aa
+ total_size
- dns_suffix_size
);
1402 get_dns_suffix(dnsSuffix
, &dns_suffix_size
);
1403 for (; aa
; aa
= aa
->Next
)
1405 if (aa
->IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
&& aa
->OperStatus
== IfOperStatusUp
)
1406 aa
->DnsSuffix
= dnsSuffix
;
1408 aa
->DnsSuffix
= dnsSuffix
+ dns_suffix_size
/ sizeof(WCHAR
) - 1;
1410 ret
= ERROR_SUCCESS
;
1414 ret
= ERROR_BUFFER_OVERFLOW
;
1415 *buflen
= total_size
;
1418 TRACE("num adapters %u\n", table
->numIndexes
);
1419 HeapFree(GetProcessHeap(), 0, table
);
1423 /******************************************************************
1424 * GetBestInterface (IPHLPAPI.@)
1426 * Get the interface, with the best route for the given IP address.
1429 * dwDestAddr [In] IP address to search the interface for
1430 * pdwBestIfIndex [Out] found best interface
1434 * Failure: error code from winerror.h
1436 DWORD WINAPI
GetBestInterface(IPAddr dwDestAddr
, PDWORD pdwBestIfIndex
)
1438 struct WS_sockaddr_in sa_in
;
1439 memset(&sa_in
, 0, sizeof(sa_in
));
1440 sa_in
.sin_family
= AF_INET
;
1441 sa_in
.sin_addr
.S_un
.S_addr
= dwDestAddr
;
1442 return GetBestInterfaceEx((struct WS_sockaddr
*)&sa_in
, pdwBestIfIndex
);
1445 /******************************************************************
1446 * GetBestInterfaceEx (IPHLPAPI.@)
1448 * Get the interface, with the best route for the given IP address.
1451 * dwDestAddr [In] IP address to search the interface for
1452 * pdwBestIfIndex [Out] found best interface
1456 * Failure: error code from winerror.h
1458 DWORD WINAPI
GetBestInterfaceEx(struct WS_sockaddr
*pDestAddr
, PDWORD pdwBestIfIndex
)
1462 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr
, pdwBestIfIndex
);
1463 if (!pDestAddr
|| !pdwBestIfIndex
)
1464 ret
= ERROR_INVALID_PARAMETER
;
1466 MIB_IPFORWARDROW ipRow
;
1468 if (pDestAddr
->sa_family
== AF_INET
) {
1469 ret
= GetBestRoute(((struct WS_sockaddr_in
*)pDestAddr
)->sin_addr
.S_un
.S_addr
, 0, &ipRow
);
1470 if (ret
== ERROR_SUCCESS
)
1471 *pdwBestIfIndex
= ipRow
.dwForwardIfIndex
;
1473 FIXME("address family %d not supported\n", pDestAddr
->sa_family
);
1474 ret
= ERROR_NOT_SUPPORTED
;
1477 TRACE("returning %d\n", ret
);
1482 /******************************************************************
1483 * GetBestRoute (IPHLPAPI.@)
1485 * Get the best route for the given IP address.
1488 * dwDestAddr [In] IP address to search the best route for
1489 * dwSourceAddr [In] optional source IP address
1490 * pBestRoute [Out] found best route
1494 * Failure: error code from winerror.h
1496 DWORD WINAPI
GetBestRoute(DWORD dwDestAddr
, DWORD dwSourceAddr
, PMIB_IPFORWARDROW pBestRoute
)
1498 PMIB_IPFORWARDTABLE table
;
1501 TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr
,
1502 dwSourceAddr
, pBestRoute
);
1504 return ERROR_INVALID_PARAMETER
;
1506 ret
= AllocateAndGetIpForwardTableFromStack(&table
, FALSE
, GetProcessHeap(), 0);
1508 DWORD ndx
, matchedBits
, matchedNdx
= table
->dwNumEntries
;
1510 for (ndx
= 0, matchedBits
= 0; ndx
< table
->dwNumEntries
; ndx
++) {
1511 if (table
->table
[ndx
].u1
.ForwardType
!= MIB_IPROUTE_TYPE_INVALID
&&
1512 (dwDestAddr
& table
->table
[ndx
].dwForwardMask
) ==
1513 (table
->table
[ndx
].dwForwardDest
& table
->table
[ndx
].dwForwardMask
)) {
1514 DWORD numShifts
, mask
;
1516 for (numShifts
= 0, mask
= table
->table
[ndx
].dwForwardMask
;
1517 mask
&& mask
& 1; mask
>>= 1, numShifts
++)
1519 if (numShifts
> matchedBits
) {
1520 matchedBits
= numShifts
;
1523 else if (!matchedBits
) {
1528 if (matchedNdx
< table
->dwNumEntries
) {
1529 memcpy(pBestRoute
, &table
->table
[matchedNdx
], sizeof(MIB_IPFORWARDROW
));
1530 ret
= ERROR_SUCCESS
;
1533 /* No route matches, which can happen if there's no default route. */
1534 ret
= ERROR_HOST_UNREACHABLE
;
1536 HeapFree(GetProcessHeap(), 0, table
);
1538 TRACE("returning %d\n", ret
);
1543 /******************************************************************
1544 * GetFriendlyIfIndex (IPHLPAPI.@)
1546 * Get a "friendly" version of IfIndex, which is one that doesn't
1547 * have the top byte set. Doesn't validate whether IfIndex is a valid
1551 * IfIndex [In] interface index to get the friendly one for
1554 * A friendly version of IfIndex.
1556 DWORD WINAPI
GetFriendlyIfIndex(DWORD IfIndex
)
1558 /* windows doesn't validate these, either, just makes sure the top byte is
1559 cleared. I assume my ifenum module never gives an index with the top
1561 TRACE("returning %d\n", IfIndex
);
1566 /******************************************************************
1567 * GetIfEntry (IPHLPAPI.@)
1569 * Get information about an interface.
1572 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1573 * Out: interface information
1577 * Failure: error code from winerror.h
1579 DWORD WINAPI
GetIfEntry(PMIB_IFROW pIfRow
)
1582 char nameBuf
[MAX_ADAPTER_NAME
];
1585 TRACE("pIfRow %p\n", pIfRow
);
1587 return ERROR_INVALID_PARAMETER
;
1589 name
= getInterfaceNameByIndex(pIfRow
->dwIndex
, nameBuf
);
1591 ret
= getInterfaceEntryByName(name
, pIfRow
);
1592 if (ret
== NO_ERROR
)
1593 ret
= getInterfaceStatsByName(name
, pIfRow
);
1596 ret
= ERROR_INVALID_DATA
;
1597 TRACE("returning %d\n", ret
);
1602 static int IfTableSorter(const void *a
, const void *b
)
1607 ret
= ((const MIB_IFROW
*)a
)->dwIndex
- ((const MIB_IFROW
*)b
)->dwIndex
;
1614 /******************************************************************
1615 * GetIfTable (IPHLPAPI.@)
1617 * Get a table of local interfaces.
1620 * pIfTable [Out] buffer for local interfaces table
1621 * pdwSize [In/Out] length of output buffer
1622 * bOrder [In] whether to sort the table
1626 * Failure: error code from winerror.h
1629 * If pdwSize is less than required, the function will return
1630 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1632 * If bOrder is true, the returned table will be sorted by interface index.
1634 DWORD WINAPI
GetIfTable(PMIB_IFTABLE pIfTable
, PULONG pdwSize
, BOOL bOrder
)
1638 TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize
, pdwSize
,
1641 ret
= ERROR_INVALID_PARAMETER
;
1643 DWORD numInterfaces
= get_interface_indices( FALSE
, NULL
);
1644 ULONG size
= sizeof(MIB_IFTABLE
);
1646 if (numInterfaces
> 1)
1647 size
+= (numInterfaces
- 1) * sizeof(MIB_IFROW
);
1648 if (!pIfTable
|| *pdwSize
< size
) {
1650 ret
= ERROR_INSUFFICIENT_BUFFER
;
1653 InterfaceIndexTable
*table
;
1654 get_interface_indices( FALSE
, &table
);
1657 size
= sizeof(MIB_IFTABLE
);
1658 if (table
->numIndexes
> 1)
1659 size
+= (table
->numIndexes
- 1) * sizeof(MIB_IFROW
);
1660 if (*pdwSize
< size
) {
1662 ret
= ERROR_INSUFFICIENT_BUFFER
;
1668 pIfTable
->dwNumEntries
= 0;
1669 for (ndx
= 0; ndx
< table
->numIndexes
; ndx
++) {
1670 pIfTable
->table
[ndx
].dwIndex
= table
->indexes
[ndx
];
1671 GetIfEntry(&pIfTable
->table
[ndx
]);
1672 pIfTable
->dwNumEntries
++;
1675 qsort(pIfTable
->table
, pIfTable
->dwNumEntries
, sizeof(MIB_IFROW
),
1679 HeapFree(GetProcessHeap(), 0, table
);
1682 ret
= ERROR_OUTOFMEMORY
;
1685 TRACE("returning %d\n", ret
);
1690 /******************************************************************
1691 * GetInterfaceInfo (IPHLPAPI.@)
1693 * Get a list of network interface adapters.
1696 * pIfTable [Out] buffer for interface adapters
1697 * dwOutBufLen [Out] if buffer is too small, returns required size
1701 * Failure: error code from winerror.h
1704 * MSDN states this should return non-loopback interfaces only.
1706 DWORD WINAPI
GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable
, PULONG dwOutBufLen
)
1710 TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable
, dwOutBufLen
);
1712 ret
= ERROR_INVALID_PARAMETER
;
1714 DWORD numInterfaces
= get_interface_indices( FALSE
, NULL
);
1715 ULONG size
= sizeof(IP_INTERFACE_INFO
);
1717 if (numInterfaces
> 1)
1718 size
+= (numInterfaces
- 1) * sizeof(IP_ADAPTER_INDEX_MAP
);
1719 if (!pIfTable
|| *dwOutBufLen
< size
) {
1720 *dwOutBufLen
= size
;
1721 ret
= ERROR_INSUFFICIENT_BUFFER
;
1724 InterfaceIndexTable
*table
;
1725 get_interface_indices( FALSE
, &table
);
1728 size
= sizeof(IP_INTERFACE_INFO
);
1729 if (table
->numIndexes
> 1)
1730 size
+= (table
->numIndexes
- 1) * sizeof(IP_ADAPTER_INDEX_MAP
);
1731 if (*dwOutBufLen
< size
) {
1732 *dwOutBufLen
= size
;
1733 ret
= ERROR_INSUFFICIENT_BUFFER
;
1737 char nameBuf
[MAX_ADAPTER_NAME
];
1739 *dwOutBufLen
= size
;
1740 pIfTable
->NumAdapters
= 0;
1741 for (ndx
= 0; ndx
< table
->numIndexes
; ndx
++) {
1742 const char *walker
, *name
;
1745 pIfTable
->Adapter
[ndx
].Index
= table
->indexes
[ndx
];
1746 name
= getInterfaceNameByIndex(table
->indexes
[ndx
], nameBuf
);
1747 for (walker
= name
, assigner
= pIfTable
->Adapter
[ndx
].Name
;
1748 walker
&& *walker
&&
1749 assigner
- pIfTable
->Adapter
[ndx
].Name
< MAX_ADAPTER_NAME
- 1;
1750 walker
++, assigner
++)
1751 *assigner
= *walker
;
1753 pIfTable
->NumAdapters
++;
1757 HeapFree(GetProcessHeap(), 0, table
);
1760 ret
= ERROR_OUTOFMEMORY
;
1763 TRACE("returning %d\n", ret
);
1768 /******************************************************************
1769 * GetIpAddrTable (IPHLPAPI.@)
1771 * Get interface-to-IP address mapping table.
1774 * pIpAddrTable [Out] buffer for mapping table
1775 * pdwSize [In/Out] length of output buffer
1776 * bOrder [In] whether to sort the table
1780 * Failure: error code from winerror.h
1783 * If pdwSize is less than required, the function will return
1784 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1786 * If bOrder is true, the returned table will be sorted by the next hop and
1787 * an assortment of arbitrary parameters.
1789 DWORD WINAPI
GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable
, PULONG pdwSize
, BOOL bOrder
)
1793 TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable
, pdwSize
,
1796 ret
= ERROR_INVALID_PARAMETER
;
1798 PMIB_IPADDRTABLE table
;
1800 ret
= getIPAddrTable(&table
, GetProcessHeap(), 0);
1801 if (ret
== NO_ERROR
)
1803 ULONG size
= FIELD_OFFSET(MIB_IPADDRTABLE
, table
[table
->dwNumEntries
]);
1805 if (!pIpAddrTable
|| *pdwSize
< size
) {
1807 ret
= ERROR_INSUFFICIENT_BUFFER
;
1811 memcpy(pIpAddrTable
, table
, size
);
1813 qsort(pIpAddrTable
->table
, pIpAddrTable
->dwNumEntries
,
1814 sizeof(MIB_IPADDRROW
), IpAddrTableSorter
);
1817 HeapFree(GetProcessHeap(), 0, table
);
1820 TRACE("returning %d\n", ret
);
1825 /******************************************************************
1826 * GetIpForwardTable (IPHLPAPI.@)
1828 * Get the route table.
1831 * pIpForwardTable [Out] buffer for route table
1832 * pdwSize [In/Out] length of output buffer
1833 * bOrder [In] whether to sort the table
1837 * Failure: error code from winerror.h
1840 * If pdwSize is less than required, the function will return
1841 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1843 * If bOrder is true, the returned table will be sorted by the next hop and
1844 * an assortment of arbitrary parameters.
1846 DWORD WINAPI
GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable
, PULONG pdwSize
, BOOL bOrder
)
1849 PMIB_IPFORWARDTABLE table
;
1851 TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable
, pdwSize
, bOrder
);
1853 if (!pdwSize
) return ERROR_INVALID_PARAMETER
;
1855 ret
= AllocateAndGetIpForwardTableFromStack(&table
, bOrder
, GetProcessHeap(), 0);
1857 DWORD size
= FIELD_OFFSET( MIB_IPFORWARDTABLE
, table
[table
->dwNumEntries
] );
1858 if (!pIpForwardTable
|| *pdwSize
< size
) {
1860 ret
= ERROR_INSUFFICIENT_BUFFER
;
1864 memcpy(pIpForwardTable
, table
, size
);
1866 HeapFree(GetProcessHeap(), 0, table
);
1868 TRACE("returning %d\n", ret
);
1873 /******************************************************************
1874 * GetIpNetTable (IPHLPAPI.@)
1876 * Get the IP-to-physical address mapping table.
1879 * pIpNetTable [Out] buffer for mapping table
1880 * pdwSize [In/Out] length of output buffer
1881 * bOrder [In] whether to sort the table
1885 * Failure: error code from winerror.h
1888 * If pdwSize is less than required, the function will return
1889 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1891 * If bOrder is true, the returned table will be sorted by IP address.
1893 DWORD WINAPI
GetIpNetTable(PMIB_IPNETTABLE pIpNetTable
, PULONG pdwSize
, BOOL bOrder
)
1896 PMIB_IPNETTABLE table
;
1898 TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable
, pdwSize
, bOrder
);
1900 if (!pdwSize
) return ERROR_INVALID_PARAMETER
;
1902 ret
= AllocateAndGetIpNetTableFromStack( &table
, bOrder
, GetProcessHeap(), 0 );
1904 DWORD size
= FIELD_OFFSET( MIB_IPNETTABLE
, table
[table
->dwNumEntries
] );
1905 if (!pIpNetTable
|| *pdwSize
< size
) {
1907 ret
= ERROR_INSUFFICIENT_BUFFER
;
1911 memcpy(pIpNetTable
, table
, size
);
1913 HeapFree(GetProcessHeap(), 0, table
);
1915 TRACE("returning %d\n", ret
);
1919 /* Gets the DNS server list into the list beginning at list. Assumes that
1920 * a single server address may be placed at list if *len is at least
1921 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
1922 * and assumes that all remaining DNS servers are contiguously located
1923 * beginning at firstDynamic. On input, *len is assumed to be the total number
1924 * of bytes available for all DNS servers, and is ignored if list is NULL.
1925 * On return, *len is set to the total number of bytes required for all DNS
1927 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
1928 * ERROR_SUCCESS otherwise.
1930 static DWORD
get_dns_server_list(PIP_ADDR_STRING list
,
1931 PIP_ADDR_STRING firstDynamic
, DWORD
*len
)
1934 int num
= get_dns_servers( NULL
, 0, TRUE
);
1936 size
= num
* sizeof(IP_ADDR_STRING
);
1937 if (!list
|| *len
< size
) {
1939 return ERROR_BUFFER_OVERFLOW
;
1943 PIP_ADDR_STRING ptr
;
1945 SOCKADDR_STORAGE
*addr
= HeapAlloc( GetProcessHeap(), 0, num
* sizeof(SOCKADDR_STORAGE
) );
1947 get_dns_servers( addr
, num
, TRUE
);
1949 for (i
= 0, ptr
= list
; i
< num
; i
++, ptr
= ptr
->Next
) {
1950 toIPAddressString(((struct sockaddr_in
*)(addr
+ i
))->sin_addr
.s_addr
,
1951 ptr
->IpAddress
.String
);
1955 ptr
->Next
= firstDynamic
;
1957 ptr
->Next
= (PIP_ADDR_STRING
)((PBYTE
)ptr
+ sizeof(IP_ADDR_STRING
));
1959 HeapFree( GetProcessHeap(), 0, addr
);
1961 return ERROR_SUCCESS
;
1964 /******************************************************************
1965 * GetNetworkParams (IPHLPAPI.@)
1967 * Get the network parameters for the local computer.
1970 * pFixedInfo [Out] buffer for network parameters
1971 * pOutBufLen [In/Out] length of output buffer
1975 * Failure: error code from winerror.h
1978 * If pOutBufLen is less than required, the function will return
1979 * ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1982 DWORD WINAPI
GetNetworkParams(PFIXED_INFO pFixedInfo
, PULONG pOutBufLen
)
1984 DWORD ret
, size
, serverListSize
;
1988 TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo
, pOutBufLen
);
1990 return ERROR_INVALID_PARAMETER
;
1992 get_dns_server_list(NULL
, NULL
, &serverListSize
);
1993 size
= sizeof(FIXED_INFO
) + serverListSize
- sizeof(IP_ADDR_STRING
);
1994 if (!pFixedInfo
|| *pOutBufLen
< size
) {
1996 return ERROR_BUFFER_OVERFLOW
;
1999 memset(pFixedInfo
, 0, size
);
2000 size
= sizeof(pFixedInfo
->HostName
);
2001 GetComputerNameExA(ComputerNameDnsHostname
, pFixedInfo
->HostName
, &size
);
2002 size
= sizeof(pFixedInfo
->DomainName
);
2003 GetComputerNameExA(ComputerNameDnsDomain
, pFixedInfo
->DomainName
, &size
);
2004 get_dns_server_list(&pFixedInfo
->DnsServerList
,
2005 (PIP_ADDR_STRING
)((BYTE
*)pFixedInfo
+ sizeof(FIXED_INFO
)),
2007 /* Assume the first DNS server in the list is the "current" DNS server: */
2008 pFixedInfo
->CurrentDnsServer
= &pFixedInfo
->DnsServerList
;
2009 pFixedInfo
->NodeType
= HYBRID_NODETYPE
;
2010 regReturn
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
2011 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ
, &hKey
);
2012 if (regReturn
!= ERROR_SUCCESS
)
2013 regReturn
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
2014 "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ
,
2016 if (regReturn
== ERROR_SUCCESS
)
2018 DWORD size
= sizeof(pFixedInfo
->ScopeId
);
2020 RegQueryValueExA(hKey
, "ScopeID", NULL
, NULL
, (LPBYTE
)pFixedInfo
->ScopeId
, &size
);
2024 /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2025 I suppose could also check for a listener on port 53 to set EnableDns */
2027 TRACE("returning %d\n", ret
);
2032 /******************************************************************
2033 * GetNumberOfInterfaces (IPHLPAPI.@)
2035 * Get the number of interfaces.
2038 * pdwNumIf [Out] number of interfaces
2041 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2043 DWORD WINAPI
GetNumberOfInterfaces(PDWORD pdwNumIf
)
2047 TRACE("pdwNumIf %p\n", pdwNumIf
);
2049 ret
= ERROR_INVALID_PARAMETER
;
2051 *pdwNumIf
= get_interface_indices( FALSE
, NULL
);
2054 TRACE("returning %d\n", ret
);
2059 /******************************************************************
2060 * GetPerAdapterInfo (IPHLPAPI.@)
2062 * Get information about an adapter corresponding to an interface.
2065 * IfIndex [In] interface info
2066 * pPerAdapterInfo [Out] buffer for per adapter info
2067 * pOutBufLen [In/Out] length of output buffer
2071 * Failure: error code from winerror.h
2073 DWORD WINAPI
GetPerAdapterInfo(ULONG IfIndex
, PIP_PER_ADAPTER_INFO pPerAdapterInfo
, PULONG pOutBufLen
)
2075 ULONG bytesNeeded
= sizeof(IP_PER_ADAPTER_INFO
), serverListSize
= 0;
2076 DWORD ret
= NO_ERROR
;
2078 TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex
, pPerAdapterInfo
, pOutBufLen
);
2080 if (!pOutBufLen
) return ERROR_INVALID_PARAMETER
;
2082 if (!isIfIndexLoopback(IfIndex
)) {
2083 get_dns_server_list(NULL
, NULL
, &serverListSize
);
2084 if (serverListSize
> sizeof(IP_ADDR_STRING
))
2085 bytesNeeded
+= serverListSize
- sizeof(IP_ADDR_STRING
);
2087 if (!pPerAdapterInfo
|| *pOutBufLen
< bytesNeeded
)
2089 *pOutBufLen
= bytesNeeded
;
2090 return ERROR_BUFFER_OVERFLOW
;
2093 memset(pPerAdapterInfo
, 0, bytesNeeded
);
2094 if (!isIfIndexLoopback(IfIndex
)) {
2095 ret
= get_dns_server_list(&pPerAdapterInfo
->DnsServerList
,
2096 (PIP_ADDR_STRING
)((PBYTE
)pPerAdapterInfo
+ sizeof(IP_PER_ADAPTER_INFO
)),
2098 /* Assume the first DNS server in the list is the "current" DNS server: */
2099 pPerAdapterInfo
->CurrentDnsServer
= &pPerAdapterInfo
->DnsServerList
;
2105 /******************************************************************
2106 * GetRTTAndHopCount (IPHLPAPI.@)
2108 * Get round-trip time (RTT) and hop count.
2112 * DestIpAddress [In] destination address to get the info for
2113 * HopCount [Out] retrieved hop count
2114 * MaxHops [In] maximum hops to search for the destination
2115 * RTT [Out] RTT in milliseconds
2122 * Stub, returns FALSE.
2124 BOOL WINAPI
GetRTTAndHopCount(IPAddr DestIpAddress
, PULONG HopCount
, ULONG MaxHops
, PULONG RTT
)
2126 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2127 DestIpAddress
, HopCount
, MaxHops
, RTT
);
2132 /******************************************************************
2133 * GetTcpTable (IPHLPAPI.@)
2135 * Get the table of active TCP connections.
2138 * pTcpTable [Out] buffer for TCP connections table
2139 * pdwSize [In/Out] length of output buffer
2140 * bOrder [In] whether to order the table
2144 * Failure: error code from winerror.h
2147 * If pdwSize is less than required, the function will return
2148 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2149 * the required byte size.
2150 * If bOrder is true, the returned table will be sorted, first by
2151 * local address and port number, then by remote address and port
2154 DWORD WINAPI
GetTcpTable(PMIB_TCPTABLE pTcpTable
, PDWORD pdwSize
, BOOL bOrder
)
2156 TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable
, pdwSize
, bOrder
);
2157 return GetExtendedTcpTable(pTcpTable
, pdwSize
, bOrder
, AF_INET
, TCP_TABLE_BASIC_ALL
, 0);
2160 /******************************************************************
2161 * GetExtendedTcpTable (IPHLPAPI.@)
2163 DWORD WINAPI
GetExtendedTcpTable(PVOID pTcpTable
, PDWORD pdwSize
, BOOL bOrder
,
2164 ULONG ulAf
, TCP_TABLE_CLASS TableClass
, ULONG Reserved
)
2169 TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2170 pTcpTable
, pdwSize
, bOrder
, ulAf
, TableClass
, Reserved
);
2172 if (!pdwSize
) return ERROR_INVALID_PARAMETER
;
2174 if (ulAf
!= AF_INET
)
2176 FIXME("ulAf = %u not supported\n", ulAf
);
2177 return ERROR_NOT_SUPPORTED
;
2179 if (TableClass
>= TCP_TABLE_OWNER_MODULE_LISTENER
)
2180 FIXME("module classes not fully supported\n");
2182 if ((ret
= build_tcp_table(TableClass
, &table
, bOrder
, GetProcessHeap(), 0, &size
)))
2185 if (!pTcpTable
|| *pdwSize
< size
)
2188 ret
= ERROR_INSUFFICIENT_BUFFER
;
2193 memcpy(pTcpTable
, table
, size
);
2195 HeapFree(GetProcessHeap(), 0, table
);
2199 /******************************************************************
2200 * GetUdpTable (IPHLPAPI.@)
2202 * Get a table of active UDP connections.
2205 * pUdpTable [Out] buffer for UDP connections table
2206 * pdwSize [In/Out] length of output buffer
2207 * bOrder [In] whether to order the table
2211 * Failure: error code from winerror.h
2214 * If pdwSize is less than required, the function will return
2215 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
2216 * required byte size.
2217 * If bOrder is true, the returned table will be sorted, first by
2218 * local address, then by local port number.
2220 DWORD WINAPI
GetUdpTable(PMIB_UDPTABLE pUdpTable
, PDWORD pdwSize
, BOOL bOrder
)
2222 return GetExtendedUdpTable(pUdpTable
, pdwSize
, bOrder
, AF_INET
, UDP_TABLE_BASIC
, 0);
2225 /******************************************************************
2226 * GetExtendedUdpTable (IPHLPAPI.@)
2228 DWORD WINAPI
GetExtendedUdpTable(PVOID pUdpTable
, PDWORD pdwSize
, BOOL bOrder
,
2229 ULONG ulAf
, UDP_TABLE_CLASS TableClass
, ULONG Reserved
)
2234 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2235 pUdpTable
, pdwSize
, bOrder
, ulAf
, TableClass
, Reserved
);
2237 if (!pdwSize
) return ERROR_INVALID_PARAMETER
;
2239 if (ulAf
!= AF_INET
)
2241 FIXME("ulAf = %u not supported\n", ulAf
);
2242 return ERROR_NOT_SUPPORTED
;
2244 if (TableClass
== UDP_TABLE_OWNER_MODULE
)
2245 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
2247 if ((ret
= build_udp_table(TableClass
, &table
, bOrder
, GetProcessHeap(), 0, &size
)))
2250 if (!pUdpTable
|| *pdwSize
< size
)
2253 ret
= ERROR_INSUFFICIENT_BUFFER
;
2258 memcpy(pUdpTable
, table
, size
);
2260 HeapFree(GetProcessHeap(), 0, table
);
2264 /******************************************************************
2265 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2267 * This is a Win98-only function to get information on "unidirectional"
2268 * adapters. Since this is pretty nonsensical in other contexts, it
2269 * never returns anything.
2272 * pIPIfInfo [Out] buffer for adapter infos
2273 * dwOutBufLen [Out] length of the output buffer
2277 * Failure: error code from winerror.h
2280 * Stub, returns ERROR_NOT_SUPPORTED.
2282 DWORD WINAPI
GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo
, PULONG dwOutBufLen
)
2284 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo
, dwOutBufLen
);
2285 /* a unidirectional adapter?? not bloody likely! */
2286 return ERROR_NOT_SUPPORTED
;
2290 /******************************************************************
2291 * IpReleaseAddress (IPHLPAPI.@)
2293 * Release an IP obtained through DHCP,
2296 * AdapterInfo [In] adapter to release IP address
2300 * Failure: error code from winerror.h
2303 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2304 * this function does nothing.
2307 * Stub, returns ERROR_NOT_SUPPORTED.
2309 DWORD WINAPI
IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
2311 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
2312 return ERROR_NOT_SUPPORTED
;
2316 /******************************************************************
2317 * IpRenewAddress (IPHLPAPI.@)
2319 * Renew an IP obtained through DHCP.
2322 * AdapterInfo [In] adapter to renew IP address
2326 * Failure: error code from winerror.h
2329 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2330 * this function does nothing.
2333 * Stub, returns ERROR_NOT_SUPPORTED.
2335 DWORD WINAPI
IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
2337 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
2338 return ERROR_NOT_SUPPORTED
;
2342 /******************************************************************
2343 * NotifyAddrChange (IPHLPAPI.@)
2345 * Notify caller whenever the ip-interface map is changed.
2348 * Handle [Out] handle usable in asynchronous notification
2349 * overlapped [In] overlapped structure that notifies the caller
2353 * Failure: error code from winerror.h
2356 * Stub, returns ERROR_NOT_SUPPORTED.
2358 DWORD WINAPI
NotifyAddrChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
2360 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
2361 if (Handle
) *Handle
= INVALID_HANDLE_VALUE
;
2362 if (overlapped
) ((IO_STATUS_BLOCK
*) overlapped
)->u
.Status
= STATUS_PENDING
;
2363 return ERROR_IO_PENDING
;
2367 /******************************************************************
2368 * NotifyIpInterfaceChange (IPHLPAPI.@)
2370 DWORD WINAPI
NotifyIpInterfaceChange(ULONG family
, PVOID callback
, PVOID context
,
2371 BOOLEAN init_notify
, PHANDLE handle
)
2373 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
2374 family
, callback
, context
, init_notify
, handle
);
2375 if (handle
) *handle
= NULL
;
2376 return ERROR_NOT_SUPPORTED
;
2380 /******************************************************************
2381 * NotifyRouteChange (IPHLPAPI.@)
2383 * Notify caller whenever the ip routing table is changed.
2386 * Handle [Out] handle usable in asynchronous notification
2387 * overlapped [In] overlapped structure that notifies the caller
2391 * Failure: error code from winerror.h
2394 * Stub, returns ERROR_NOT_SUPPORTED.
2396 DWORD WINAPI
NotifyRouteChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
2398 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
2399 return ERROR_NOT_SUPPORTED
;
2403 /******************************************************************
2404 * SendARP (IPHLPAPI.@)
2406 * Send an ARP request.
2409 * DestIP [In] attempt to obtain this IP
2410 * SrcIP [In] optional sender IP address
2411 * pMacAddr [Out] buffer for the mac address
2412 * PhyAddrLen [In/Out] length of the output buffer
2416 * Failure: error code from winerror.h
2419 * Stub, returns ERROR_NOT_SUPPORTED.
2421 DWORD WINAPI
SendARP(IPAddr DestIP
, IPAddr SrcIP
, PULONG pMacAddr
, PULONG PhyAddrLen
)
2423 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
2424 DestIP
, SrcIP
, pMacAddr
, PhyAddrLen
);
2425 return ERROR_NOT_SUPPORTED
;
2429 /******************************************************************
2430 * SetIfEntry (IPHLPAPI.@)
2432 * Set the administrative status of an interface.
2435 * pIfRow [In] dwAdminStatus member specifies the new status.
2439 * Failure: error code from winerror.h
2442 * Stub, returns ERROR_NOT_SUPPORTED.
2444 DWORD WINAPI
SetIfEntry(PMIB_IFROW pIfRow
)
2446 FIXME("(pIfRow %p): stub\n", pIfRow
);
2447 /* this is supposed to set an interface administratively up or down.
2448 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2449 this sort of down is indistinguishable from other sorts of down (e.g. no
2451 return ERROR_NOT_SUPPORTED
;
2455 /******************************************************************
2456 * SetIpForwardEntry (IPHLPAPI.@)
2458 * Modify an existing route.
2461 * pRoute [In] route with the new information
2465 * Failure: error code from winerror.h
2468 * Stub, returns NO_ERROR.
2470 DWORD WINAPI
SetIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
2472 FIXME("(pRoute %p): stub\n", pRoute
);
2473 /* this is to add a route entry, how's it distinguishable from
2474 CreateIpForwardEntry?
2475 could use SIOCADDRT, not sure I want to */
2480 /******************************************************************
2481 * SetIpNetEntry (IPHLPAPI.@)
2483 * Modify an existing ARP entry.
2486 * pArpEntry [In] ARP entry with the new information
2490 * Failure: error code from winerror.h
2493 * Stub, returns NO_ERROR.
2495 DWORD WINAPI
SetIpNetEntry(PMIB_IPNETROW pArpEntry
)
2497 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
2498 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
2503 /******************************************************************
2504 * SetIpStatistics (IPHLPAPI.@)
2506 * Toggle IP forwarding and det the default TTL value.
2509 * pIpStats [In] IP statistics with the new information
2513 * Failure: error code from winerror.h
2516 * Stub, returns NO_ERROR.
2518 DWORD WINAPI
SetIpStatistics(PMIB_IPSTATS pIpStats
)
2520 FIXME("(pIpStats %p): stub\n", pIpStats
);
2525 /******************************************************************
2526 * SetIpTTL (IPHLPAPI.@)
2528 * Set the default TTL value.
2531 * nTTL [In] new TTL value
2535 * Failure: error code from winerror.h
2538 * Stub, returns NO_ERROR.
2540 DWORD WINAPI
SetIpTTL(UINT nTTL
)
2542 FIXME("(nTTL %d): stub\n", nTTL
);
2543 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2544 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2549 /******************************************************************
2550 * SetTcpEntry (IPHLPAPI.@)
2552 * Set the state of a TCP connection.
2555 * pTcpRow [In] specifies connection with new state
2559 * Failure: error code from winerror.h
2562 * Stub, returns NO_ERROR.
2564 DWORD WINAPI
SetTcpEntry(PMIB_TCPROW pTcpRow
)
2566 FIXME("(pTcpRow %p): stub\n", pTcpRow
);
2571 /******************************************************************
2572 * UnenableRouter (IPHLPAPI.@)
2574 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2575 * if it reaches zero.
2578 * pOverlapped [In/Out] should be the same as in EnableRouter()
2579 * lpdwEnableCount [Out] optional, receives reference count
2583 * Failure: error code from winerror.h
2586 * Stub, returns ERROR_NOT_SUPPORTED.
2588 DWORD WINAPI
UnenableRouter(OVERLAPPED
* pOverlapped
, LPDWORD lpdwEnableCount
)
2590 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped
,
2592 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2593 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2595 return ERROR_NOT_SUPPORTED
;
2598 /******************************************************************
2599 * PfCreateInterface (IPHLPAPI.@)
2601 DWORD WINAPI
PfCreateInterface(DWORD dwName
, PFFORWARD_ACTION inAction
, PFFORWARD_ACTION outAction
,
2602 BOOL bUseLog
, BOOL bMustBeUnique
, INTERFACE_HANDLE
*ppInterface
)
2604 FIXME("(%d %d %d %x %x %p) stub\n", dwName
, inAction
, outAction
, bUseLog
, bMustBeUnique
, ppInterface
);
2605 return ERROR_CALL_NOT_IMPLEMENTED
;
2608 /******************************************************************
2609 * PfUnBindInterface (IPHLPAPI.@)
2611 DWORD WINAPI
PfUnBindInterface(INTERFACE_HANDLE interface
)
2613 FIXME("(%p) stub\n", interface
);
2614 return ERROR_CALL_NOT_IMPLEMENTED
;
2617 /******************************************************************
2618 * PfDeleteInterface(IPHLPAPI.@)
2620 DWORD WINAPI
PfDeleteInterface(INTERFACE_HANDLE interface
)
2622 FIXME("(%p) stub\n", interface
);
2623 return ERROR_CALL_NOT_IMPLEMENTED
;
2626 /******************************************************************
2627 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
2629 DWORD WINAPI
PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface
, PFADDRESSTYPE type
, PBYTE ip
)
2631 FIXME("(%p %d %p) stub\n", interface
, type
, ip
);
2632 return ERROR_CALL_NOT_IMPLEMENTED
;
2635 /******************************************************************
2636 * GetTcpTable2 (IPHLPAPI.@)
2638 ULONG WINAPI
GetTcpTable2(PMIB_TCPTABLE2 table
, PULONG size
, BOOL order
)
2640 FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table
, size
, order
);
2641 return ERROR_NOT_SUPPORTED
;
2644 /******************************************************************
2645 * GetTcp6Table (IPHLPAPI.@)
2647 ULONG WINAPI
GetTcp6Table(PMIB_TCP6TABLE table
, PULONG size
, BOOL order
)
2649 FIXME("pTcp6Table %p, size %p, order %d: stub\n", table
, size
, order
);
2650 return ERROR_NOT_SUPPORTED
;
2653 /******************************************************************
2654 * GetTcp6Table2 (IPHLPAPI.@)
2656 ULONG WINAPI
GetTcp6Table2(PMIB_TCP6TABLE2 table
, PULONG size
, BOOL order
)
2658 FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table
, size
, order
);
2659 return ERROR_NOT_SUPPORTED
;