msi: Improve support for advertized shortcuts.
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blob88db25a3f853df610c16d87aa41d22d3a3b382d8
1 /*
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
21 #include "config.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
29 #endif
30 #ifdef HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
32 #endif
33 #ifdef HAVE_ARPA_NAMESER_H
34 # include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 # include <resolv.h>
38 #endif
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winreg.h"
45 #define USE_WS_PREFIX
46 #include "winsock2.h"
47 #include "winternl.h"
48 #include "ws2ipdef.h"
49 #include "iphlpapi.h"
50 #include "ifenum.h"
51 #include "ipstats.h"
52 #include "ipifcons.h"
53 #include "fltdefs.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
59 #ifndef IF_NAMESIZE
60 #define IF_NAMESIZE 16
61 #endif
63 #ifndef INADDR_NONE
64 #define INADDR_NONE ~0UL
65 #endif
67 /******************************************************************
68 * AddIPAddress (IPHLPAPI.@)
70 * Add an IP address to an adapter.
72 * PARAMS
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
79 * RETURNS
80 * Success: NO_ERROR
81 * Failure: error code from winerror.h
83 * FIXME
84 * Stub. Currently returns ERROR_NOT_SUPPORTED.
86 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
88 FIXME(":stub\n");
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.
99 * PARAMS
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
106 * RETURNS
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)
113 DWORD ret;
115 TRACE("ppIfTable %p, bOrder %d, heap %p, flags 0x%08x\n", ppIfTable,
116 bOrder, heap, flags);
117 if (!ppIfTable)
118 ret = ERROR_INVALID_PARAMETER;
119 else {
120 DWORD dwSize = 0;
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);
129 return ret;
133 static int IpAddrTableSorter(const void *a, const void *b)
135 int ret;
137 if (a && b)
138 ret = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
139 else
140 ret = 0;
141 return ret;
145 /******************************************************************
146 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
148 * Get interface-to-IP address mapping table.
149 * Like GetIpAddrTable(), but allocate the returned table from heap.
151 * PARAMS
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
158 * RETURNS
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)
165 DWORD ret;
167 TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
168 ppIpAddrTable, bOrder, heap, flags);
169 ret = getIPAddrTable(ppIpAddrTable, heap, flags);
170 if (!ret && bOrder)
171 qsort((*ppIpAddrTable)->table, (*ppIpAddrTable)->dwNumEntries,
172 sizeof(MIB_IPADDRROW), IpAddrTableSorter);
173 TRACE("returning %d\n", ret);
174 return ret;
178 /******************************************************************
179 * CancelIPChangeNotify (IPHLPAPI.@)
181 * Cancel a previous notification created by NotifyAddrChange or
182 * NotifyRouteChange.
184 * PARAMS
185 * overlapped [In] overlapped structure that notifies the caller
187 * RETURNS
188 * Success: TRUE
189 * Failure: FALSE
191 * FIXME
192 * Stub, returns FALSE.
194 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
196 FIXME("(overlapped %p): stub\n", overlapped);
197 return FALSE;
202 /******************************************************************
203 * CreateIpForwardEntry (IPHLPAPI.@)
205 * Create a route in the local computer's IP table.
207 * PARAMS
208 * pRoute [In] new route information
210 * RETURNS
211 * Success: NO_ERROR
212 * Failure: error code from winerror.h
214 * FIXME
215 * Stub, always returns NO_ERROR.
217 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
219 FIXME("(pRoute %p): stub\n", pRoute);
220 /* could use SIOCADDRT, not sure I want to */
221 return 0;
225 /******************************************************************
226 * CreateIpNetEntry (IPHLPAPI.@)
228 * Create entry in the ARP table.
230 * PARAMS
231 * pArpEntry [In] new ARP entry
233 * RETURNS
234 * Success: NO_ERROR
235 * Failure: error code from winerror.h
237 * FIXME
238 * Stub, always returns NO_ERROR.
240 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
242 FIXME("(pArpEntry %p)\n", pArpEntry);
243 /* could use SIOCSARP on systems that support it, not sure I want to */
244 return 0;
248 /******************************************************************
249 * CreateProxyArpEntry (IPHLPAPI.@)
251 * Create a Proxy ARP (PARP) entry for an IP address.
253 * PARAMS
254 * dwAddress [In] IP address for which this computer acts as a proxy.
255 * dwMask [In] subnet mask for dwAddress
256 * dwIfIndex [In] interface index
258 * RETURNS
259 * Success: NO_ERROR
260 * Failure: error code from winerror.h
262 * FIXME
263 * Stub, returns ERROR_NOT_SUPPORTED.
265 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
267 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
268 dwAddress, dwMask, dwIfIndex);
269 return ERROR_NOT_SUPPORTED;
273 /******************************************************************
274 * DeleteIPAddress (IPHLPAPI.@)
276 * Delete an IP address added with AddIPAddress().
278 * PARAMS
279 * NTEContext [In] NTE context from AddIPAddress();
281 * RETURNS
282 * Success: NO_ERROR
283 * Failure: error code from winerror.h
285 * FIXME
286 * Stub, returns ERROR_NOT_SUPPORTED.
288 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
290 FIXME("(NTEContext %d): stub\n", NTEContext);
291 return ERROR_NOT_SUPPORTED;
295 /******************************************************************
296 * DeleteIpForwardEntry (IPHLPAPI.@)
298 * Delete a route.
300 * PARAMS
301 * pRoute [In] route to delete
303 * RETURNS
304 * Success: NO_ERROR
305 * Failure: error code from winerror.h
307 * FIXME
308 * Stub, returns NO_ERROR.
310 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
312 FIXME("(pRoute %p): stub\n", pRoute);
313 /* could use SIOCDELRT, not sure I want to */
314 return 0;
318 /******************************************************************
319 * DeleteIpNetEntry (IPHLPAPI.@)
321 * Delete an ARP entry.
323 * PARAMS
324 * pArpEntry [In] ARP entry to delete
326 * RETURNS
327 * Success: NO_ERROR
328 * Failure: error code from winerror.h
330 * FIXME
331 * Stub, returns NO_ERROR.
333 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
335 FIXME("(pArpEntry %p): stub\n", pArpEntry);
336 /* could use SIOCDARP on systems that support it, not sure I want to */
337 return 0;
341 /******************************************************************
342 * DeleteProxyArpEntry (IPHLPAPI.@)
344 * Delete a Proxy ARP entry.
346 * PARAMS
347 * dwAddress [In] IP address for which this computer acts as a proxy.
348 * dwMask [In] subnet mask for dwAddress
349 * dwIfIndex [In] interface index
351 * RETURNS
352 * Success: NO_ERROR
353 * Failure: error code from winerror.h
355 * FIXME
356 * Stub, returns ERROR_NOT_SUPPORTED.
358 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
360 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
361 dwAddress, dwMask, dwIfIndex);
362 return ERROR_NOT_SUPPORTED;
366 /******************************************************************
367 * EnableRouter (IPHLPAPI.@)
369 * Turn on ip forwarding.
371 * PARAMS
372 * pHandle [In/Out]
373 * pOverlapped [In/Out] hEvent member should contain a valid handle.
375 * RETURNS
376 * Success: ERROR_IO_PENDING
377 * Failure: error code from winerror.h
379 * FIXME
380 * Stub, returns ERROR_NOT_SUPPORTED.
382 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
384 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
385 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
386 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
388 return ERROR_NOT_SUPPORTED;
392 /******************************************************************
393 * FlushIpNetTable (IPHLPAPI.@)
395 * Delete all ARP entries of an interface
397 * PARAMS
398 * dwIfIndex [In] interface index
400 * RETURNS
401 * Success: NO_ERROR
402 * Failure: error code from winerror.h
404 * FIXME
405 * Stub, returns ERROR_NOT_SUPPORTED.
407 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
409 FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
410 /* this flushes the arp cache of the given index */
411 return ERROR_NOT_SUPPORTED;
415 /******************************************************************
416 * GetAdapterIndex (IPHLPAPI.@)
418 * Get interface index from its name.
420 * PARAMS
421 * AdapterName [In] unicode string with the adapter name
422 * IfIndex [Out] returns found interface index
424 * RETURNS
425 * Success: NO_ERROR
426 * Failure: error code from winerror.h
428 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
430 char adapterName[MAX_ADAPTER_NAME];
431 unsigned int i;
432 DWORD ret;
434 TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName, IfIndex);
435 /* The adapter name is guaranteed not to have any unicode characters, so
436 * this translation is never lossy */
437 for (i = 0; i < sizeof(adapterName) - 1 && AdapterName[i]; i++)
438 adapterName[i] = (char)AdapterName[i];
439 adapterName[i] = '\0';
440 ret = getInterfaceIndexByName(adapterName, IfIndex);
441 TRACE("returning %d\n", ret);
442 return ret;
446 /******************************************************************
447 * GetAdaptersInfo (IPHLPAPI.@)
449 * Get information about adapters.
451 * PARAMS
452 * pAdapterInfo [Out] buffer for adapter infos
453 * pOutBufLen [In] length of output buffer
455 * RETURNS
456 * Success: NO_ERROR
457 * Failure: error code from winerror.h
459 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
461 DWORD ret;
463 TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
464 if (!pOutBufLen)
465 ret = ERROR_INVALID_PARAMETER;
466 else {
467 DWORD numNonLoopbackInterfaces = get_interface_indices( TRUE, NULL );
469 if (numNonLoopbackInterfaces > 0) {
470 DWORD numIPAddresses = getNumIPAddresses();
471 ULONG size;
473 /* This may slightly overestimate the amount of space needed, because
474 * the IP addresses include the loopback address, but it's easier
475 * to make sure there's more than enough space than to make sure there's
476 * precisely enough space.
478 size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
479 size += numIPAddresses * sizeof(IP_ADDR_STRING);
480 if (!pAdapterInfo || *pOutBufLen < size) {
481 *pOutBufLen = size;
482 ret = ERROR_BUFFER_OVERFLOW;
484 else {
485 InterfaceIndexTable *table = NULL;
486 PMIB_IPADDRTABLE ipAddrTable = NULL;
487 PMIB_IPFORWARDTABLE routeTable = NULL;
489 ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
490 if (!ret)
491 ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
492 if (!ret)
493 get_interface_indices( TRUE, &table );
494 if (table) {
495 size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
496 size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING);
497 if (*pOutBufLen < size) {
498 *pOutBufLen = size;
499 ret = ERROR_INSUFFICIENT_BUFFER;
501 else {
502 DWORD ndx;
503 HKEY hKey;
504 BOOL winsEnabled = FALSE;
505 IP_ADDRESS_STRING primaryWINS, secondaryWINS;
506 PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
507 + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
509 memset(pAdapterInfo, 0, size);
510 /* @@ Wine registry key: HKCU\Software\Wine\Network */
511 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
512 &hKey) == ERROR_SUCCESS) {
513 DWORD size = sizeof(primaryWINS.String);
514 unsigned long addr;
516 RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
517 (LPBYTE)primaryWINS.String, &size);
518 addr = inet_addr(primaryWINS.String);
519 if (addr != INADDR_NONE && addr != INADDR_ANY)
520 winsEnabled = TRUE;
521 size = sizeof(secondaryWINS.String);
522 RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
523 (LPBYTE)secondaryWINS.String, &size);
524 addr = inet_addr(secondaryWINS.String);
525 if (addr != INADDR_NONE && addr != INADDR_ANY)
526 winsEnabled = TRUE;
527 RegCloseKey(hKey);
529 for (ndx = 0; ndx < table->numIndexes; ndx++) {
530 PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
531 DWORD i;
532 PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
533 BOOL firstIPAddr = TRUE;
535 /* on Win98 this is left empty, but whatever */
536 getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
537 getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
538 ptr->AddressLength = sizeof(ptr->Address);
539 getInterfacePhysicalByIndex(table->indexes[ndx],
540 &ptr->AddressLength, ptr->Address, &ptr->Type);
541 ptr->Index = table->indexes[ndx];
542 for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
543 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
544 if (firstIPAddr) {
545 toIPAddressString(ipAddrTable->table[i].dwAddr,
546 ptr->IpAddressList.IpAddress.String);
547 toIPAddressString(ipAddrTable->table[i].dwMask,
548 ptr->IpAddressList.IpMask.String);
549 firstIPAddr = FALSE;
551 else {
552 currentIPAddr->Next = nextIPAddr;
553 currentIPAddr = nextIPAddr;
554 toIPAddressString(ipAddrTable->table[i].dwAddr,
555 currentIPAddr->IpAddress.String);
556 toIPAddressString(ipAddrTable->table[i].dwMask,
557 currentIPAddr->IpMask.String);
558 nextIPAddr++;
562 /* Find first router through this interface, which we'll assume
563 * is the default gateway for this adapter */
564 for (i = 0; i < routeTable->dwNumEntries; i++)
565 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
566 && routeTable->table[i].u1.ForwardType ==
567 MIB_IPROUTE_TYPE_INDIRECT)
569 toIPAddressString(routeTable->table[i].dwForwardNextHop,
570 ptr->GatewayList.IpAddress.String);
571 toIPAddressString(routeTable->table[i].dwForwardMask,
572 ptr->GatewayList.IpMask.String);
574 if (winsEnabled) {
575 ptr->HaveWins = TRUE;
576 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
577 primaryWINS.String, sizeof(primaryWINS.String));
578 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
579 secondaryWINS.String, sizeof(secondaryWINS.String));
581 if (ndx < table->numIndexes - 1)
582 ptr->Next = &pAdapterInfo[ndx + 1];
583 else
584 ptr->Next = NULL;
586 ptr->DhcpEnabled = TRUE;
588 ret = NO_ERROR;
590 HeapFree(GetProcessHeap(), 0, table);
592 else
593 ret = ERROR_OUTOFMEMORY;
594 HeapFree(GetProcessHeap(), 0, routeTable);
595 HeapFree(GetProcessHeap(), 0, ipAddrTable);
598 else
599 ret = ERROR_NO_DATA;
601 TRACE("returning %d\n", ret);
602 return ret;
605 static DWORD typeFromMibType(DWORD mib_type)
607 switch (mib_type)
609 case MIB_IF_TYPE_ETHERNET: return IF_TYPE_ETHERNET_CSMACD;
610 case MIB_IF_TYPE_TOKENRING: return IF_TYPE_ISO88025_TOKENRING;
611 case MIB_IF_TYPE_PPP: return IF_TYPE_PPP;
612 case MIB_IF_TYPE_LOOPBACK: return IF_TYPE_SOFTWARE_LOOPBACK;
613 default: return IF_TYPE_OTHER;
617 static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
619 switch (mib_type)
621 case MIB_IF_TYPE_PPP: return NET_IF_CONNECTION_DEMAND;
622 case MIB_IF_TYPE_SLIP: return NET_IF_CONNECTION_DEMAND;
623 default: return NET_IF_CONNECTION_DEDICATED;
627 static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs, DWORD **masks)
629 ULONG ret, i, j;
630 MIB_IPADDRTABLE *at;
632 *num_addrs = 0;
633 if ((ret = getIPAddrTable(&at, GetProcessHeap(), 0))) return ret;
634 for (i = 0; i < at->dwNumEntries; i++)
636 if (at->table[i].dwIndex == index) (*num_addrs)++;
638 if (!(*addrs = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
640 HeapFree(GetProcessHeap(), 0, at);
641 return ERROR_OUTOFMEMORY;
643 if (!(*masks = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
645 HeapFree(GetProcessHeap(), 0, *addrs);
646 HeapFree(GetProcessHeap(), 0, at);
647 return ERROR_OUTOFMEMORY;
649 for (i = 0, j = 0; i < at->dwNumEntries; i++)
651 if (at->table[i].dwIndex == index)
653 (*addrs)[j] = at->table[i].dwAddr;
654 (*masks)[j] = at->table[i].dwMask;
655 j++;
658 HeapFree(GetProcessHeap(), 0, at);
659 return ERROR_SUCCESS;
662 static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf)
664 const BYTE *addrp;
665 char *p = buf;
667 for (addrp = (const BYTE *)in_addr;
668 addrp - (const BYTE *)in_addr < sizeof(*in_addr);
669 addrp++)
671 if (addrp == (const BYTE *)in_addr + sizeof(*in_addr) - 1)
672 sprintf(p, "%d", *addrp);
673 else
674 p += sprintf(p, "%d.", *addrp);
676 return buf;
679 static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf)
681 const IN6_ADDR *addr = &sin->sin6_addr;
682 char *p = buf;
683 int i;
684 BOOL in_zero = FALSE;
686 for (i = 0; i < 7; i++)
688 if (!addr->u.Word[i])
690 if (i == 0)
691 *p++ = ':';
692 if (!in_zero)
694 *p++ = ':';
695 in_zero = TRUE;
698 else
700 p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
701 in_zero = FALSE;
704 sprintf(p, "%x", ntohs(addr->u.Word[7]));
705 return buf;
708 static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable)
710 DWORD i, num_gateways = 0;
712 for (i = 0; i < routeTable->dwNumEntries; i++)
714 if (routeTable->table[i].dwForwardIfIndex == index &&
715 routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
716 num_gateways++;
718 return num_gateways;
721 static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
722 PMIB_IPFORWARDTABLE routeTable)
724 DWORD i;
725 PMIB_IPFORWARDROW row = NULL;
727 for (i = 0; !row && i < routeTable->dwNumEntries; i++)
729 if (routeTable->table[i].dwForwardIfIndex == index &&
730 routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
731 row = &routeTable->table[i];
733 return row;
736 static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
737 IP_ADAPTER_ADDRESSES *aa, ULONG *size)
739 ULONG ret = ERROR_SUCCESS, i, j, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
740 DWORD *v4addrs = NULL, *v4masks = NULL;
741 SOCKET_ADDRESS *v6addrs = NULL, *v6masks = NULL;
742 PMIB_IPFORWARDTABLE routeTable = NULL;
744 if (family == WS_AF_INET)
746 ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
748 if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
750 ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
751 if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable);
754 else if (family == WS_AF_INET6)
756 ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
758 else if (family == WS_AF_UNSPEC)
760 ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
762 if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
764 ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
765 if (!ret) num_v4_gateways = count_v4_gateways(index, routeTable);
767 if (!ret) ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
769 else
771 FIXME("address family %u unsupported\n", family);
772 ret = ERROR_NO_DATA;
774 if (ret)
776 HeapFree(GetProcessHeap(), 0, v4addrs);
777 HeapFree(GetProcessHeap(), 0, v4masks);
778 HeapFree(GetProcessHeap(), 0, v6addrs);
779 HeapFree(GetProcessHeap(), 0, v6masks);
780 HeapFree(GetProcessHeap(), 0, routeTable);
781 return ret;
784 total_size = sizeof(IP_ADAPTER_ADDRESSES);
785 total_size += IF_NAMESIZE;
786 total_size += IF_NAMESIZE * sizeof(WCHAR);
787 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
788 total_size += IF_NAMESIZE * sizeof(WCHAR);
789 if (flags & GAA_FLAG_INCLUDE_PREFIX)
791 total_size += sizeof(IP_ADAPTER_PREFIX) * num_v4addrs;
792 total_size += sizeof(IP_ADAPTER_PREFIX) * num_v6addrs;
793 total_size += sizeof(struct sockaddr_in) * num_v4addrs;
794 for (i = 0; i < num_v6addrs; i++)
795 total_size += v6masks[i].iSockaddrLength;
797 total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
798 total_size += sizeof(struct sockaddr_in) * num_v4addrs;
799 total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways;
800 total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v6addrs;
801 total_size += sizeof(SOCKET_ADDRESS) * num_v6addrs;
802 for (i = 0; i < num_v6addrs; i++)
803 total_size += v6addrs[i].iSockaddrLength;
805 if (aa && *size >= total_size)
807 char name[IF_NAMESIZE], *ptr = (char *)aa + sizeof(IP_ADAPTER_ADDRESSES), *src;
808 WCHAR *dst;
809 DWORD buflen, type;
810 INTERNAL_IF_OPER_STATUS status;
812 memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES));
813 aa->u.s.Length = sizeof(IP_ADAPTER_ADDRESSES);
814 aa->u.s.IfIndex = index;
816 getInterfaceNameByIndex(index, name);
817 memcpy(ptr, name, IF_NAMESIZE);
818 aa->AdapterName = ptr;
819 ptr += IF_NAMESIZE;
820 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
822 aa->FriendlyName = (WCHAR *)ptr;
823 for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
824 *dst = *src;
825 *dst++ = 0;
826 ptr = (char *)dst;
828 aa->Description = (WCHAR *)ptr;
829 for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
830 *dst = *src;
831 *dst++ = 0;
832 ptr = (char *)dst;
834 TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name, num_v4addrs,
835 num_v6addrs);
836 if (num_v4_gateways)
838 PMIB_IPFORWARDROW adapterRow;
840 if ((adapterRow = findIPv4Gateway(index, routeTable)))
842 PIP_ADAPTER_GATEWAY_ADDRESS gw;
843 PSOCKADDR_IN sin;
845 gw = (PIP_ADAPTER_GATEWAY_ADDRESS)ptr;
846 aa->FirstGatewayAddress = gw;
848 gw->u.s.Length = sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
849 ptr += sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
850 sin = (PSOCKADDR_IN)ptr;
851 sin->sin_family = AF_INET;
852 sin->sin_port = 0;
853 memcpy(&sin->sin_addr, &adapterRow->dwForwardNextHop,
854 sizeof(DWORD));
855 gw->Address.lpSockaddr = (LPSOCKADDR)sin;
856 gw->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
857 gw->Next = NULL;
858 ptr += sizeof(SOCKADDR_IN);
861 if (num_v4addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
863 IP_ADAPTER_UNICAST_ADDRESS *ua;
864 struct WS_sockaddr_in *sa;
865 aa->Flags |= IP_ADAPTER_IPV4_ENABLED;
866 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
867 for (i = 0; i < num_v4addrs; i++)
869 char addr_buf[16];
871 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
872 ua->u.s.Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
873 ua->Address.iSockaddrLength = sizeof(struct sockaddr_in);
874 ua->Address.lpSockaddr = (SOCKADDR *)((char *)ua + ua->u.s.Length);
876 sa = (struct WS_sockaddr_in *)ua->Address.lpSockaddr;
877 sa->sin_family = WS_AF_INET;
878 sa->sin_addr.S_un.S_addr = v4addrs[i];
879 sa->sin_port = 0;
880 TRACE("IPv4 %d/%d: %s\n", i + 1, num_v4addrs,
881 debugstr_ipv4(&sa->sin_addr.S_un.S_addr, addr_buf));
883 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
884 if (i < num_v4addrs - 1)
886 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
887 ua = ua->Next;
891 if (num_v6addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
893 IP_ADAPTER_UNICAST_ADDRESS *ua;
894 struct WS_sockaddr_in6 *sa;
896 aa->Flags |= IP_ADAPTER_IPV6_ENABLED;
897 if (aa->FirstUnicastAddress)
899 for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
901 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
902 ua = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
904 else
905 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
906 for (i = 0; i < num_v6addrs; i++)
908 char addr_buf[46];
910 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
911 ua->u.s.Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
912 ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
913 ua->Address.lpSockaddr = (SOCKADDR *)((char *)ua + ua->u.s.Length);
915 sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
916 memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
917 TRACE("IPv6 %d/%d: %s\n", i + 1, num_v6addrs,
918 debugstr_ipv6(sa, addr_buf));
920 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
921 if (i < num_v6addrs - 1)
923 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
924 ua = ua->Next;
928 if (num_v4addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
930 IP_ADAPTER_PREFIX *prefix;
932 prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
933 for (i = 0; i < num_v4addrs; i++)
935 char addr_buf[16];
936 struct WS_sockaddr_in *sa;
938 prefix->u.s.Length = sizeof(*prefix);
939 prefix->u.s.Flags = 0;
940 prefix->Next = NULL;
941 prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in);
942 prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
944 sa = (struct WS_sockaddr_in *)prefix->Address.lpSockaddr;
945 sa->sin_family = WS_AF_INET;
946 sa->sin_addr.S_un.S_addr = v4addrs[i] & v4masks[i];
947 sa->sin_port = 0;
949 prefix->PrefixLength = 0;
950 for (j = 0; j < sizeof(*v4masks) * 8; j++)
952 if (v4masks[i] & 1 << j) prefix->PrefixLength++;
953 else break;
955 TRACE("IPv4 network: %s/%u\n",
956 debugstr_ipv4((const in_addr_t *)&sa->sin_addr.S_un.S_addr, addr_buf),
957 prefix->PrefixLength);
959 ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
960 if (i < num_v4addrs - 1)
962 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
963 prefix = prefix->Next;
967 if (num_v6addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
969 IP_ADAPTER_PREFIX *prefix;
971 if (aa->FirstPrefix)
973 for (prefix = aa->FirstPrefix; prefix->Next; prefix = prefix->Next)
975 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
976 prefix = (IP_ADAPTER_PREFIX *)ptr;
978 else
979 prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
980 for (i = 0; i < num_v6addrs; i++)
982 char addr_buf[46];
983 struct WS_sockaddr_in6 *sa;
984 const IN6_ADDR *addr, *mask;
985 BOOL done = FALSE;
987 prefix->u.s.Length = sizeof(*prefix);
988 prefix->u.s.Flags = 0;
989 prefix->Next = NULL;
990 prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in6);
991 prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
993 sa = (struct WS_sockaddr_in6 *)prefix->Address.lpSockaddr;
994 sa->sin6_family = WS_AF_INET6;
995 sa->sin6_port = 0;
996 sa->sin6_flowinfo = 0;
997 addr = &((struct WS_sockaddr_in6 *)v6addrs[i].lpSockaddr)->sin6_addr;
998 mask = &((struct WS_sockaddr_in6 *)v6masks[i].lpSockaddr)->sin6_addr;
999 for (j = 0; j < 8; j++) sa->sin6_addr.u.Word[j] = addr->u.Word[j] & mask->u.Word[j];
1000 sa->sin6_scope_id = 0;
1002 prefix->PrefixLength = 0;
1003 for (i = 0; i < 8 && !done; i++)
1005 for (j = 0; j < sizeof(WORD) * 8 && !done; j++)
1007 if (mask->u.Word[i] & 1 << j) prefix->PrefixLength++;
1008 else done = TRUE;
1011 TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa, addr_buf), prefix->PrefixLength);
1013 ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
1014 if (i < num_v6addrs - 1)
1016 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
1017 prefix = prefix->Next;
1022 buflen = MAX_INTERFACE_PHYSADDR;
1023 getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
1024 aa->PhysicalAddressLength = buflen;
1025 aa->IfType = typeFromMibType(type);
1026 aa->ConnectionType = connectionTypeFromMibType(type);
1028 getInterfaceMtuByName(name, &aa->Mtu);
1030 getInterfaceStatusByName(name, &status);
1031 if (status == MIB_IF_OPER_STATUS_OPERATIONAL) aa->OperStatus = IfOperStatusUp;
1032 else if (status == MIB_IF_OPER_STATUS_NON_OPERATIONAL) aa->OperStatus = IfOperStatusDown;
1033 else aa->OperStatus = IfOperStatusUnknown;
1035 *size = total_size;
1036 HeapFree(GetProcessHeap(), 0, routeTable);
1037 HeapFree(GetProcessHeap(), 0, v6addrs);
1038 HeapFree(GetProcessHeap(), 0, v6masks);
1039 HeapFree(GetProcessHeap(), 0, v4addrs);
1040 HeapFree(GetProcessHeap(), 0, v4masks);
1041 return ERROR_SUCCESS;
1044 static void sockaddr_in_to_WS_storage( SOCKADDR_STORAGE *dst, const struct sockaddr_in *src )
1046 SOCKADDR_IN *s = (SOCKADDR_IN *)dst;
1048 s->sin_family = WS_AF_INET;
1049 s->sin_port = src->sin_port;
1050 memcpy( &s->sin_addr, &src->sin_addr, sizeof(IN_ADDR) );
1051 memset( (char *)s + FIELD_OFFSET( SOCKADDR_IN, sin_zero ), 0,
1052 sizeof(SOCKADDR_STORAGE) - FIELD_OFFSET( SOCKADDR_IN, sin_zero) );
1055 static void sockaddr_in6_to_WS_storage( SOCKADDR_STORAGE *dst, const struct sockaddr_in6 *src )
1057 SOCKADDR_IN6 *s = (SOCKADDR_IN6 *)dst;
1059 s->sin6_family = WS_AF_INET6;
1060 s->sin6_port = src->sin6_port;
1061 s->sin6_flowinfo = src->sin6_flowinfo;
1062 memcpy( &s->sin6_addr, &src->sin6_addr, sizeof(IN6_ADDR) );
1063 s->sin6_scope_id = src->sin6_scope_id;
1064 memset( (char *)s + sizeof(SOCKADDR_IN6), 0,
1065 sizeof(SOCKADDR_STORAGE) - sizeof(SOCKADDR_IN6) );
1068 #ifdef HAVE_STRUCT___RES_STATE
1069 /* call res_init() just once because of a bug in Mac OS X 10.4 */
1070 /* Call once per thread on systems that have per-thread _res. */
1072 static CRITICAL_SECTION res_init_cs;
1073 static CRITICAL_SECTION_DEBUG res_init_cs_debug = {
1074 0, 0, &res_init_cs,
1075 { &res_init_cs_debug.ProcessLocksList, &res_init_cs_debug.ProcessLocksList },
1076 0, 0, { (DWORD_PTR)(__FILE__ ": res_init_cs") }
1078 static CRITICAL_SECTION res_init_cs = { &res_init_cs_debug, -1, 0, 0, 0, 0 };
1080 static void initialise_resolver(void)
1082 EnterCriticalSection(&res_init_cs);
1083 if ((_res.options & RES_INIT) == 0)
1084 res_init();
1085 LeaveCriticalSection(&res_init_cs);
1088 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1090 int i, ip6_count = 0;
1091 SOCKADDR_STORAGE *addr;
1093 initialise_resolver();
1095 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1096 ip6_count = _res._u._ext.nscount6;
1097 #endif
1099 if (!servers || !num)
1101 num = _res.nscount;
1102 if (ip4_only) num -= ip6_count;
1103 return num;
1106 for (i = 0, addr = servers; addr < (servers + num) && i < _res.nscount; i++)
1108 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1109 if (_res._u._ext.nsaddrs[i])
1111 if (ip4_only) continue;
1112 sockaddr_in6_to_WS_storage( addr, _res._u._ext.nsaddrs[i] );
1114 else
1115 #endif
1117 sockaddr_in_to_WS_storage( addr, _res.nsaddr_list + i );
1119 addr++;
1121 return addr - servers;
1123 #elif defined(HAVE___RES_GET_STATE) && defined(HAVE___RES_GETSERVERS)
1125 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1127 extern struct res_state *__res_get_state( void );
1128 extern int __res_getservers( struct res_state *, struct sockaddr_storage *, int );
1129 struct res_state *state = __res_get_state();
1130 int i, found = 0, total = __res_getservers( state, NULL, 0 );
1131 SOCKADDR_STORAGE *addr = servers;
1132 struct sockaddr_storage *buf;
1134 if ((!servers || !num) && !ip4_only) return total;
1136 buf = HeapAlloc( GetProcessHeap(), 0, total * sizeof(struct sockaddr_storage) );
1137 total = __res_getservers( state, buf, total );
1139 for (i = 0; i < total; i++)
1141 if (buf[i].ss_family == AF_INET6 && ip4_only) continue;
1142 if (buf[i].ss_family != AF_INET && buf[i].ss_family != AF_INET6) continue;
1144 found++;
1145 if (!servers || !num) continue;
1147 if (buf[i].ss_family == AF_INET6)
1149 sockaddr_in6_to_WS_storage( addr, (struct sockaddr_in6 *)(buf + i) );
1151 else
1153 sockaddr_in_to_WS_storage( addr, (struct sockaddr_in *)(buf + i) );
1155 if (++addr >= servers + num) break;
1158 HeapFree( GetProcessHeap(), 0, buf );
1159 return found;
1161 #else
1163 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1165 FIXME("Unimplemented on this system\n");
1166 return 0;
1168 #endif
1170 static ULONG get_dns_server_addresses(PIP_ADAPTER_DNS_SERVER_ADDRESS address, ULONG *len)
1172 int num = get_dns_servers( NULL, 0, FALSE );
1173 DWORD size;
1175 size = num * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR_STORAGE));
1176 if (!address || *len < size)
1178 *len = size;
1179 return ERROR_BUFFER_OVERFLOW;
1181 *len = size;
1182 if (num > 0)
1184 PIP_ADAPTER_DNS_SERVER_ADDRESS addr = address;
1185 SOCKADDR_STORAGE *sock_addrs = (SOCKADDR_STORAGE *)(address + num);
1186 int i;
1188 get_dns_servers( sock_addrs, num, FALSE );
1190 for (i = 0; i < num; i++, addr = addr->Next)
1192 addr->u.s.Length = sizeof(*addr);
1193 if (sock_addrs[i].ss_family == WS_AF_INET6)
1194 addr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
1195 else
1196 addr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
1197 addr->Address.lpSockaddr = (SOCKADDR *)(sock_addrs + i);
1198 if (i == num - 1)
1199 addr->Next = NULL;
1200 else
1201 addr->Next = addr + 1;
1204 return ERROR_SUCCESS;
1207 #ifdef HAVE_STRUCT___RES_STATE
1208 static BOOL is_ip_address_string(const char *str)
1210 struct in_addr in;
1211 int ret;
1213 ret = inet_aton(str, &in);
1214 return ret != 0;
1216 #endif
1218 static ULONG get_dns_suffix(WCHAR *suffix, ULONG *len)
1220 ULONG size;
1221 const char *found_suffix = "";
1222 /* Always return a NULL-terminated string, even if it's empty. */
1224 #ifdef HAVE_STRUCT___RES_STATE
1226 ULONG i;
1227 initialise_resolver();
1228 for (i = 0; !*found_suffix && i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
1230 /* This uses a heuristic to select a DNS suffix:
1231 * the first, non-IP address string is selected.
1233 if (!is_ip_address_string(_res.dnsrch[i]))
1234 found_suffix = _res.dnsrch[i];
1237 #endif
1239 size = MultiByteToWideChar( CP_UNIXCP, 0, found_suffix, -1, NULL, 0 ) * sizeof(WCHAR);
1240 if (!suffix || *len < size)
1242 *len = size;
1243 return ERROR_BUFFER_OVERFLOW;
1245 *len = MultiByteToWideChar( CP_UNIXCP, 0, found_suffix, -1, suffix, *len / sizeof(WCHAR) ) * sizeof(WCHAR);
1246 return ERROR_SUCCESS;
1249 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG family, ULONG flags, PVOID reserved,
1250 PIP_ADAPTER_ADDRESSES aa, PULONG buflen)
1252 InterfaceIndexTable *table;
1253 ULONG i, size, dns_server_size, dns_suffix_size, total_size, ret = ERROR_NO_DATA;
1255 TRACE("(%d, %08x, %p, %p, %p)\n", family, flags, reserved, aa, buflen);
1257 if (!buflen) return ERROR_INVALID_PARAMETER;
1259 get_interface_indices( FALSE, &table );
1260 if (!table || !table->numIndexes)
1262 HeapFree(GetProcessHeap(), 0, table);
1263 return ERROR_NO_DATA;
1265 total_size = 0;
1266 for (i = 0; i < table->numIndexes; i++)
1268 size = 0;
1269 if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], NULL, &size)))
1271 HeapFree(GetProcessHeap(), 0, table);
1272 return ret;
1274 total_size += size;
1276 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1278 /* Since DNS servers aren't really per adapter, get enough space for a
1279 * single copy of them.
1281 get_dns_server_addresses(NULL, &dns_server_size);
1282 total_size += dns_server_size;
1284 /* Since DNS suffix also isn't really per adapter, get enough space for a
1285 * single copy of it.
1287 get_dns_suffix(NULL, &dns_suffix_size);
1288 total_size += dns_suffix_size;
1289 if (aa && *buflen >= total_size)
1291 ULONG bytes_left = size = total_size;
1292 PIP_ADAPTER_ADDRESSES first_aa = aa;
1293 PIP_ADAPTER_DNS_SERVER_ADDRESS firstDns;
1294 WCHAR *dnsSuffix;
1296 for (i = 0; i < table->numIndexes; i++)
1298 if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], aa, &size)))
1300 HeapFree(GetProcessHeap(), 0, table);
1301 return ret;
1303 if (i < table->numIndexes - 1)
1305 aa->Next = (IP_ADAPTER_ADDRESSES *)((char *)aa + size);
1306 aa = aa->Next;
1307 size = bytes_left -= size;
1310 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER) && dns_server_size)
1312 firstDns = (PIP_ADAPTER_DNS_SERVER_ADDRESS)((BYTE *)first_aa + total_size - dns_server_size - dns_suffix_size);
1313 get_dns_server_addresses(firstDns, &dns_server_size);
1314 for (aa = first_aa; aa; aa = aa->Next)
1316 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1317 aa->FirstDnsServerAddress = firstDns;
1320 aa = first_aa;
1321 dnsSuffix = (WCHAR *)((BYTE *)aa + total_size - dns_suffix_size);
1322 get_dns_suffix(dnsSuffix, &dns_suffix_size);
1323 for (; aa; aa = aa->Next)
1325 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1326 aa->DnsSuffix = dnsSuffix;
1327 else
1328 aa->DnsSuffix = dnsSuffix + dns_suffix_size / sizeof(WCHAR) - 1;
1330 ret = ERROR_SUCCESS;
1332 else
1333 ret = ERROR_BUFFER_OVERFLOW;
1334 *buflen = total_size;
1336 TRACE("num adapters %u\n", table->numIndexes);
1337 HeapFree(GetProcessHeap(), 0, table);
1338 return ret;
1341 /******************************************************************
1342 * GetBestInterface (IPHLPAPI.@)
1344 * Get the interface, with the best route for the given IP address.
1346 * PARAMS
1347 * dwDestAddr [In] IP address to search the interface for
1348 * pdwBestIfIndex [Out] found best interface
1350 * RETURNS
1351 * Success: NO_ERROR
1352 * Failure: error code from winerror.h
1354 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1356 struct WS_sockaddr_in sa_in;
1357 memset(&sa_in, 0, sizeof(sa_in));
1358 sa_in.sin_family = AF_INET;
1359 sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1360 return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
1363 /******************************************************************
1364 * GetBestInterfaceEx (IPHLPAPI.@)
1366 * Get the interface, with the best route for the given IP address.
1368 * PARAMS
1369 * dwDestAddr [In] IP address to search the interface for
1370 * pdwBestIfIndex [Out] found best interface
1372 * RETURNS
1373 * Success: NO_ERROR
1374 * Failure: error code from winerror.h
1376 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1378 DWORD ret;
1380 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1381 if (!pDestAddr || !pdwBestIfIndex)
1382 ret = ERROR_INVALID_PARAMETER;
1383 else {
1384 MIB_IPFORWARDROW ipRow;
1386 if (pDestAddr->sa_family == AF_INET) {
1387 ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1388 if (ret == ERROR_SUCCESS)
1389 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1390 } else {
1391 FIXME("address family %d not supported\n", pDestAddr->sa_family);
1392 ret = ERROR_NOT_SUPPORTED;
1395 TRACE("returning %d\n", ret);
1396 return ret;
1400 /******************************************************************
1401 * GetBestRoute (IPHLPAPI.@)
1403 * Get the best route for the given IP address.
1405 * PARAMS
1406 * dwDestAddr [In] IP address to search the best route for
1407 * dwSourceAddr [In] optional source IP address
1408 * pBestRoute [Out] found best route
1410 * RETURNS
1411 * Success: NO_ERROR
1412 * Failure: error code from winerror.h
1414 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1416 PMIB_IPFORWARDTABLE table;
1417 DWORD ret;
1419 TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
1420 dwSourceAddr, pBestRoute);
1421 if (!pBestRoute)
1422 return ERROR_INVALID_PARAMETER;
1424 ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1425 if (!ret) {
1426 DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1428 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1429 if (table->table[ndx].u1.ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1430 (dwDestAddr & table->table[ndx].dwForwardMask) ==
1431 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1432 DWORD numShifts, mask;
1434 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1435 mask && mask & 1; mask >>= 1, numShifts++)
1437 if (numShifts > matchedBits) {
1438 matchedBits = numShifts;
1439 matchedNdx = ndx;
1441 else if (!matchedBits) {
1442 matchedNdx = ndx;
1446 if (matchedNdx < table->dwNumEntries) {
1447 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1448 ret = ERROR_SUCCESS;
1450 else {
1451 /* No route matches, which can happen if there's no default route. */
1452 ret = ERROR_HOST_UNREACHABLE;
1454 HeapFree(GetProcessHeap(), 0, table);
1456 TRACE("returning %d\n", ret);
1457 return ret;
1461 /******************************************************************
1462 * GetFriendlyIfIndex (IPHLPAPI.@)
1464 * Get a "friendly" version of IfIndex, which is one that doesn't
1465 * have the top byte set. Doesn't validate whether IfIndex is a valid
1466 * adapter index.
1468 * PARAMS
1469 * IfIndex [In] interface index to get the friendly one for
1471 * RETURNS
1472 * A friendly version of IfIndex.
1474 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1476 /* windows doesn't validate these, either, just makes sure the top byte is
1477 cleared. I assume my ifenum module never gives an index with the top
1478 byte set. */
1479 TRACE("returning %d\n", IfIndex);
1480 return IfIndex;
1484 /******************************************************************
1485 * GetIfEntry (IPHLPAPI.@)
1487 * Get information about an interface.
1489 * PARAMS
1490 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1491 * Out: interface information
1493 * RETURNS
1494 * Success: NO_ERROR
1495 * Failure: error code from winerror.h
1497 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1499 DWORD ret;
1500 char nameBuf[MAX_ADAPTER_NAME];
1501 char *name;
1503 TRACE("pIfRow %p\n", pIfRow);
1504 if (!pIfRow)
1505 return ERROR_INVALID_PARAMETER;
1507 name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
1508 if (name) {
1509 ret = getInterfaceEntryByName(name, pIfRow);
1510 if (ret == NO_ERROR)
1511 ret = getInterfaceStatsByName(name, pIfRow);
1513 else
1514 ret = ERROR_INVALID_DATA;
1515 TRACE("returning %d\n", ret);
1516 return ret;
1520 static int IfTableSorter(const void *a, const void *b)
1522 int ret;
1524 if (a && b)
1525 ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1526 else
1527 ret = 0;
1528 return ret;
1532 /******************************************************************
1533 * GetIfTable (IPHLPAPI.@)
1535 * Get a table of local interfaces.
1537 * PARAMS
1538 * pIfTable [Out] buffer for local interfaces table
1539 * pdwSize [In/Out] length of output buffer
1540 * bOrder [In] whether to sort the table
1542 * RETURNS
1543 * Success: NO_ERROR
1544 * Failure: error code from winerror.h
1546 * NOTES
1547 * If pdwSize is less than required, the function will return
1548 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1549 * size.
1550 * If bOrder is true, the returned table will be sorted by interface index.
1552 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1554 DWORD ret;
1556 TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
1557 (DWORD)bOrder);
1558 if (!pdwSize)
1559 ret = ERROR_INVALID_PARAMETER;
1560 else {
1561 DWORD numInterfaces = get_interface_indices( FALSE, NULL );
1562 ULONG size = sizeof(MIB_IFTABLE);
1564 if (numInterfaces > 1)
1565 size += (numInterfaces - 1) * sizeof(MIB_IFROW);
1566 if (!pIfTable || *pdwSize < size) {
1567 *pdwSize = size;
1568 ret = ERROR_INSUFFICIENT_BUFFER;
1570 else {
1571 InterfaceIndexTable *table;
1572 get_interface_indices( FALSE, &table );
1574 if (table) {
1575 size = sizeof(MIB_IFTABLE);
1576 if (table->numIndexes > 1)
1577 size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
1578 if (*pdwSize < size) {
1579 *pdwSize = size;
1580 ret = ERROR_INSUFFICIENT_BUFFER;
1582 else {
1583 DWORD ndx;
1585 *pdwSize = size;
1586 pIfTable->dwNumEntries = 0;
1587 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1588 pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1589 GetIfEntry(&pIfTable->table[ndx]);
1590 pIfTable->dwNumEntries++;
1592 if (bOrder)
1593 qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1594 IfTableSorter);
1595 ret = NO_ERROR;
1597 HeapFree(GetProcessHeap(), 0, table);
1599 else
1600 ret = ERROR_OUTOFMEMORY;
1603 TRACE("returning %d\n", ret);
1604 return ret;
1608 /******************************************************************
1609 * GetInterfaceInfo (IPHLPAPI.@)
1611 * Get a list of network interface adapters.
1613 * PARAMS
1614 * pIfTable [Out] buffer for interface adapters
1615 * dwOutBufLen [Out] if buffer is too small, returns required size
1617 * RETURNS
1618 * Success: NO_ERROR
1619 * Failure: error code from winerror.h
1621 * BUGS
1622 * MSDN states this should return non-loopback interfaces only.
1624 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1626 DWORD ret;
1628 TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1629 if (!dwOutBufLen)
1630 ret = ERROR_INVALID_PARAMETER;
1631 else {
1632 DWORD numInterfaces = get_interface_indices( FALSE, NULL );
1633 ULONG size = sizeof(IP_INTERFACE_INFO);
1635 if (numInterfaces > 1)
1636 size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1637 if (!pIfTable || *dwOutBufLen < size) {
1638 *dwOutBufLen = size;
1639 ret = ERROR_INSUFFICIENT_BUFFER;
1641 else {
1642 InterfaceIndexTable *table;
1643 get_interface_indices( FALSE, &table );
1645 if (table) {
1646 size = sizeof(IP_INTERFACE_INFO);
1647 if (table->numIndexes > 1)
1648 size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1649 if (*dwOutBufLen < size) {
1650 *dwOutBufLen = size;
1651 ret = ERROR_INSUFFICIENT_BUFFER;
1653 else {
1654 DWORD ndx;
1655 char nameBuf[MAX_ADAPTER_NAME];
1657 *dwOutBufLen = size;
1658 pIfTable->NumAdapters = 0;
1659 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1660 const char *walker, *name;
1661 WCHAR *assigner;
1663 pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1664 name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
1665 for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1666 walker && *walker &&
1667 assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1668 walker++, assigner++)
1669 *assigner = *walker;
1670 *assigner = 0;
1671 pIfTable->NumAdapters++;
1673 ret = NO_ERROR;
1675 HeapFree(GetProcessHeap(), 0, table);
1677 else
1678 ret = ERROR_OUTOFMEMORY;
1681 TRACE("returning %d\n", ret);
1682 return ret;
1686 /******************************************************************
1687 * GetIpAddrTable (IPHLPAPI.@)
1689 * Get interface-to-IP address mapping table.
1691 * PARAMS
1692 * pIpAddrTable [Out] buffer for mapping table
1693 * pdwSize [In/Out] length of output buffer
1694 * bOrder [In] whether to sort the table
1696 * RETURNS
1697 * Success: NO_ERROR
1698 * Failure: error code from winerror.h
1700 * NOTES
1701 * If pdwSize is less than required, the function will return
1702 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1703 * size.
1704 * If bOrder is true, the returned table will be sorted by the next hop and
1705 * an assortment of arbitrary parameters.
1707 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1709 DWORD ret;
1711 TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
1712 (DWORD)bOrder);
1713 if (!pdwSize)
1714 ret = ERROR_INVALID_PARAMETER;
1715 else {
1716 PMIB_IPADDRTABLE table;
1718 ret = getIPAddrTable(&table, GetProcessHeap(), 0);
1719 if (ret == NO_ERROR)
1721 ULONG size = FIELD_OFFSET(MIB_IPADDRTABLE, table[table->dwNumEntries]);
1723 if (!pIpAddrTable || *pdwSize < size) {
1724 *pdwSize = size;
1725 ret = ERROR_INSUFFICIENT_BUFFER;
1727 else {
1728 *pdwSize = size;
1729 memcpy(pIpAddrTable, table, size);
1730 if (bOrder)
1731 qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1732 sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1733 ret = NO_ERROR;
1735 HeapFree(GetProcessHeap(), 0, table);
1738 TRACE("returning %d\n", ret);
1739 return ret;
1743 /******************************************************************
1744 * GetIpForwardTable (IPHLPAPI.@)
1746 * Get the route table.
1748 * PARAMS
1749 * pIpForwardTable [Out] buffer for route table
1750 * pdwSize [In/Out] length of output buffer
1751 * bOrder [In] whether to sort the table
1753 * RETURNS
1754 * Success: NO_ERROR
1755 * Failure: error code from winerror.h
1757 * NOTES
1758 * If pdwSize is less than required, the function will return
1759 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1760 * size.
1761 * If bOrder is true, the returned table will be sorted by the next hop and
1762 * an assortment of arbitrary parameters.
1764 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1766 DWORD ret;
1767 PMIB_IPFORWARDTABLE table;
1769 TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
1771 if (!pdwSize) return ERROR_INVALID_PARAMETER;
1773 ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1774 if (!ret) {
1775 DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
1776 if (!pIpForwardTable || *pdwSize < size) {
1777 *pdwSize = size;
1778 ret = ERROR_INSUFFICIENT_BUFFER;
1780 else {
1781 *pdwSize = size;
1782 memcpy(pIpForwardTable, table, size);
1784 HeapFree(GetProcessHeap(), 0, table);
1786 TRACE("returning %d\n", ret);
1787 return ret;
1791 /******************************************************************
1792 * GetIpNetTable (IPHLPAPI.@)
1794 * Get the IP-to-physical address mapping table.
1796 * PARAMS
1797 * pIpNetTable [Out] buffer for mapping table
1798 * pdwSize [In/Out] length of output buffer
1799 * bOrder [In] whether to sort the table
1801 * RETURNS
1802 * Success: NO_ERROR
1803 * Failure: error code from winerror.h
1805 * NOTES
1806 * If pdwSize is less than required, the function will return
1807 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1808 * size.
1809 * If bOrder is true, the returned table will be sorted by IP address.
1811 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1813 DWORD ret;
1814 PMIB_IPNETTABLE table;
1816 TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder);
1818 if (!pdwSize) return ERROR_INVALID_PARAMETER;
1820 ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1821 if (!ret) {
1822 DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] );
1823 if (!pIpNetTable || *pdwSize < size) {
1824 *pdwSize = size;
1825 ret = ERROR_INSUFFICIENT_BUFFER;
1827 else {
1828 *pdwSize = size;
1829 memcpy(pIpNetTable, table, size);
1831 HeapFree(GetProcessHeap(), 0, table);
1833 TRACE("returning %d\n", ret);
1834 return ret;
1837 /* Gets the DNS server list into the list beginning at list. Assumes that
1838 * a single server address may be placed at list if *len is at least
1839 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
1840 * and assumes that all remaining DNS servers are contiguously located
1841 * beginning at firstDynamic. On input, *len is assumed to be the total number
1842 * of bytes available for all DNS servers, and is ignored if list is NULL.
1843 * On return, *len is set to the total number of bytes required for all DNS
1844 * servers.
1845 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
1846 * ERROR_SUCCESS otherwise.
1848 static DWORD get_dns_server_list(PIP_ADDR_STRING list,
1849 PIP_ADDR_STRING firstDynamic, DWORD *len)
1851 DWORD size;
1852 int num = get_dns_servers( NULL, 0, TRUE );
1854 size = num * sizeof(IP_ADDR_STRING);
1855 if (!list || *len < size) {
1856 *len = size;
1857 return ERROR_BUFFER_OVERFLOW;
1859 *len = size;
1860 if (num > 0) {
1861 PIP_ADDR_STRING ptr;
1862 int i;
1863 SOCKADDR_STORAGE *addr = HeapAlloc( GetProcessHeap(), 0, num * sizeof(SOCKADDR_STORAGE) );
1865 get_dns_servers( addr, num, TRUE );
1867 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next) {
1868 toIPAddressString(((struct sockaddr_in *)(addr + i))->sin_addr.s_addr,
1869 ptr->IpAddress.String);
1870 if (i == num - 1)
1871 ptr->Next = NULL;
1872 else if (i == 0)
1873 ptr->Next = firstDynamic;
1874 else
1875 ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1877 HeapFree( GetProcessHeap(), 0, addr );
1879 return ERROR_SUCCESS;
1882 /******************************************************************
1883 * GetNetworkParams (IPHLPAPI.@)
1885 * Get the network parameters for the local computer.
1887 * PARAMS
1888 * pFixedInfo [Out] buffer for network parameters
1889 * pOutBufLen [In/Out] length of output buffer
1891 * RETURNS
1892 * Success: NO_ERROR
1893 * Failure: error code from winerror.h
1895 * NOTES
1896 * If pOutBufLen is less than required, the function will return
1897 * ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1898 * size.
1900 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1902 DWORD ret, size, serverListSize;
1903 LONG regReturn;
1904 HKEY hKey;
1906 TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1907 if (!pOutBufLen)
1908 return ERROR_INVALID_PARAMETER;
1910 get_dns_server_list(NULL, NULL, &serverListSize);
1911 size = sizeof(FIXED_INFO) + serverListSize - sizeof(IP_ADDR_STRING);
1912 if (!pFixedInfo || *pOutBufLen < size) {
1913 *pOutBufLen = size;
1914 return ERROR_BUFFER_OVERFLOW;
1917 memset(pFixedInfo, 0, size);
1918 size = sizeof(pFixedInfo->HostName);
1919 GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1920 size = sizeof(pFixedInfo->DomainName);
1921 GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1922 get_dns_server_list(&pFixedInfo->DnsServerList,
1923 (PIP_ADDR_STRING)((BYTE *)pFixedInfo + sizeof(FIXED_INFO)),
1924 &serverListSize);
1925 /* Assume the first DNS server in the list is the "current" DNS server: */
1926 pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList;
1927 pFixedInfo->NodeType = HYBRID_NODETYPE;
1928 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1929 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1930 if (regReturn != ERROR_SUCCESS)
1931 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1932 "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1933 &hKey);
1934 if (regReturn == ERROR_SUCCESS)
1936 DWORD size = sizeof(pFixedInfo->ScopeId);
1938 RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1939 RegCloseKey(hKey);
1942 /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1943 I suppose could also check for a listener on port 53 to set EnableDns */
1944 ret = NO_ERROR;
1945 TRACE("returning %d\n", ret);
1946 return ret;
1950 /******************************************************************
1951 * GetNumberOfInterfaces (IPHLPAPI.@)
1953 * Get the number of interfaces.
1955 * PARAMS
1956 * pdwNumIf [Out] number of interfaces
1958 * RETURNS
1959 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1961 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1963 DWORD ret;
1965 TRACE("pdwNumIf %p\n", pdwNumIf);
1966 if (!pdwNumIf)
1967 ret = ERROR_INVALID_PARAMETER;
1968 else {
1969 *pdwNumIf = get_interface_indices( FALSE, NULL );
1970 ret = NO_ERROR;
1972 TRACE("returning %d\n", ret);
1973 return ret;
1977 /******************************************************************
1978 * GetPerAdapterInfo (IPHLPAPI.@)
1980 * Get information about an adapter corresponding to an interface.
1982 * PARAMS
1983 * IfIndex [In] interface info
1984 * pPerAdapterInfo [Out] buffer for per adapter info
1985 * pOutBufLen [In/Out] length of output buffer
1987 * RETURNS
1988 * Success: NO_ERROR
1989 * Failure: error code from winerror.h
1991 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1993 ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO), serverListSize = 0;
1994 DWORD ret = NO_ERROR;
1996 TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex, pPerAdapterInfo, pOutBufLen);
1998 if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
2000 if (!isIfIndexLoopback(IfIndex)) {
2001 get_dns_server_list(NULL, NULL, &serverListSize);
2002 if (serverListSize > sizeof(IP_ADDR_STRING))
2003 bytesNeeded += serverListSize - sizeof(IP_ADDR_STRING);
2005 if (!pPerAdapterInfo || *pOutBufLen < bytesNeeded)
2007 *pOutBufLen = bytesNeeded;
2008 return ERROR_BUFFER_OVERFLOW;
2011 memset(pPerAdapterInfo, 0, bytesNeeded);
2012 if (!isIfIndexLoopback(IfIndex)) {
2013 ret = get_dns_server_list(&pPerAdapterInfo->DnsServerList,
2014 (PIP_ADDR_STRING)((PBYTE)pPerAdapterInfo + sizeof(IP_PER_ADAPTER_INFO)),
2015 &serverListSize);
2016 /* Assume the first DNS server in the list is the "current" DNS server: */
2017 pPerAdapterInfo->CurrentDnsServer = &pPerAdapterInfo->DnsServerList;
2019 return ret;
2023 /******************************************************************
2024 * GetRTTAndHopCount (IPHLPAPI.@)
2026 * Get round-trip time (RTT) and hop count.
2028 * PARAMS
2030 * DestIpAddress [In] destination address to get the info for
2031 * HopCount [Out] retrieved hop count
2032 * MaxHops [In] maximum hops to search for the destination
2033 * RTT [Out] RTT in milliseconds
2035 * RETURNS
2036 * Success: TRUE
2037 * Failure: FALSE
2039 * FIXME
2040 * Stub, returns FALSE.
2042 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2044 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2045 DestIpAddress, HopCount, MaxHops, RTT);
2046 return FALSE;
2050 /******************************************************************
2051 * GetTcpTable (IPHLPAPI.@)
2053 * Get the table of active TCP connections.
2055 * PARAMS
2056 * pTcpTable [Out] buffer for TCP connections table
2057 * pdwSize [In/Out] length of output buffer
2058 * bOrder [In] whether to order the table
2060 * RETURNS
2061 * Success: NO_ERROR
2062 * Failure: error code from winerror.h
2064 * NOTES
2065 * If pdwSize is less than required, the function will return
2066 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2067 * the required byte size.
2068 * If bOrder is true, the returned table will be sorted, first by
2069 * local address and port number, then by remote address and port
2070 * number.
2072 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2074 TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
2075 return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2078 /******************************************************************
2079 * GetExtendedTcpTable (IPHLPAPI.@)
2081 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
2082 ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
2084 DWORD ret, size;
2085 void *table;
2087 TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2088 pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2090 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2092 if (ulAf != AF_INET)
2094 FIXME("ulAf = %u not supported\n", ulAf);
2095 return ERROR_NOT_SUPPORTED;
2097 if (TableClass >= TCP_TABLE_OWNER_MODULE_LISTENER)
2098 FIXME("module classes not fully supported\n");
2100 if ((ret = build_tcp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size)))
2101 return ret;
2103 if (!pTcpTable || *pdwSize < size)
2105 *pdwSize = size;
2106 ret = ERROR_INSUFFICIENT_BUFFER;
2108 else
2110 *pdwSize = size;
2111 memcpy(pTcpTable, table, size);
2113 HeapFree(GetProcessHeap(), 0, table);
2114 return ret;
2117 /******************************************************************
2118 * GetUdpTable (IPHLPAPI.@)
2120 * Get a table of active UDP connections.
2122 * PARAMS
2123 * pUdpTable [Out] buffer for UDP connections table
2124 * pdwSize [In/Out] length of output buffer
2125 * bOrder [In] whether to order the table
2127 * RETURNS
2128 * Success: NO_ERROR
2129 * Failure: error code from winerror.h
2131 * NOTES
2132 * If pdwSize is less than required, the function will return
2133 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
2134 * required byte size.
2135 * If bOrder is true, the returned table will be sorted, first by
2136 * local address, then by local port number.
2138 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2140 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2143 /******************************************************************
2144 * GetExtendedUdpTable (IPHLPAPI.@)
2146 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
2147 ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
2149 DWORD ret, size;
2150 void *table;
2152 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2153 pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2155 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2157 if (ulAf != AF_INET)
2159 FIXME("ulAf = %u not supported\n", ulAf);
2160 return ERROR_NOT_SUPPORTED;
2162 if (TableClass == UDP_TABLE_OWNER_MODULE)
2163 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
2165 if ((ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size)))
2166 return ret;
2168 if (!pUdpTable || *pdwSize < size)
2170 *pdwSize = size;
2171 ret = ERROR_INSUFFICIENT_BUFFER;
2173 else
2175 *pdwSize = size;
2176 memcpy(pUdpTable, table, size);
2178 HeapFree(GetProcessHeap(), 0, table);
2179 return ret;
2182 /******************************************************************
2183 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2185 * This is a Win98-only function to get information on "unidirectional"
2186 * adapters. Since this is pretty nonsensical in other contexts, it
2187 * never returns anything.
2189 * PARAMS
2190 * pIPIfInfo [Out] buffer for adapter infos
2191 * dwOutBufLen [Out] length of the output buffer
2193 * RETURNS
2194 * Success: NO_ERROR
2195 * Failure: error code from winerror.h
2197 * FIXME
2198 * Stub, returns ERROR_NOT_SUPPORTED.
2200 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2202 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2203 /* a unidirectional adapter?? not bloody likely! */
2204 return ERROR_NOT_SUPPORTED;
2208 /******************************************************************
2209 * IpReleaseAddress (IPHLPAPI.@)
2211 * Release an IP obtained through DHCP,
2213 * PARAMS
2214 * AdapterInfo [In] adapter to release IP address
2216 * RETURNS
2217 * Success: NO_ERROR
2218 * Failure: error code from winerror.h
2220 * NOTES
2221 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2222 * this function does nothing.
2224 * FIXME
2225 * Stub, returns ERROR_NOT_SUPPORTED.
2227 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2229 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2230 return ERROR_NOT_SUPPORTED;
2234 /******************************************************************
2235 * IpRenewAddress (IPHLPAPI.@)
2237 * Renew an IP obtained through DHCP.
2239 * PARAMS
2240 * AdapterInfo [In] adapter to renew IP address
2242 * RETURNS
2243 * Success: NO_ERROR
2244 * Failure: error code from winerror.h
2246 * NOTES
2247 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2248 * this function does nothing.
2250 * FIXME
2251 * Stub, returns ERROR_NOT_SUPPORTED.
2253 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2255 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2256 return ERROR_NOT_SUPPORTED;
2260 /******************************************************************
2261 * NotifyAddrChange (IPHLPAPI.@)
2263 * Notify caller whenever the ip-interface map is changed.
2265 * PARAMS
2266 * Handle [Out] handle usable in asynchronous notification
2267 * overlapped [In] overlapped structure that notifies the caller
2269 * RETURNS
2270 * Success: NO_ERROR
2271 * Failure: error code from winerror.h
2273 * FIXME
2274 * Stub, returns ERROR_NOT_SUPPORTED.
2276 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2278 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2279 if (Handle) *Handle = INVALID_HANDLE_VALUE;
2280 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
2281 return ERROR_IO_PENDING;
2285 /******************************************************************
2286 * NotifyRouteChange (IPHLPAPI.@)
2288 * Notify caller whenever the ip routing table is changed.
2290 * PARAMS
2291 * Handle [Out] handle usable in asynchronous notification
2292 * overlapped [In] overlapped structure that notifies the caller
2294 * RETURNS
2295 * Success: NO_ERROR
2296 * Failure: error code from winerror.h
2298 * FIXME
2299 * Stub, returns ERROR_NOT_SUPPORTED.
2301 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2303 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2304 return ERROR_NOT_SUPPORTED;
2308 /******************************************************************
2309 * SendARP (IPHLPAPI.@)
2311 * Send an ARP request.
2313 * PARAMS
2314 * DestIP [In] attempt to obtain this IP
2315 * SrcIP [In] optional sender IP address
2316 * pMacAddr [Out] buffer for the mac address
2317 * PhyAddrLen [In/Out] length of the output buffer
2319 * RETURNS
2320 * Success: NO_ERROR
2321 * Failure: error code from winerror.h
2323 * FIXME
2324 * Stub, returns ERROR_NOT_SUPPORTED.
2326 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2328 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
2329 DestIP, SrcIP, pMacAddr, PhyAddrLen);
2330 return ERROR_NOT_SUPPORTED;
2334 /******************************************************************
2335 * SetIfEntry (IPHLPAPI.@)
2337 * Set the administrative status of an interface.
2339 * PARAMS
2340 * pIfRow [In] dwAdminStatus member specifies the new status.
2342 * RETURNS
2343 * Success: NO_ERROR
2344 * Failure: error code from winerror.h
2346 * FIXME
2347 * Stub, returns ERROR_NOT_SUPPORTED.
2349 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2351 FIXME("(pIfRow %p): stub\n", pIfRow);
2352 /* this is supposed to set an interface administratively up or down.
2353 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2354 this sort of down is indistinguishable from other sorts of down (e.g. no
2355 link). */
2356 return ERROR_NOT_SUPPORTED;
2360 /******************************************************************
2361 * SetIpForwardEntry (IPHLPAPI.@)
2363 * Modify an existing route.
2365 * PARAMS
2366 * pRoute [In] route with the new information
2368 * RETURNS
2369 * Success: NO_ERROR
2370 * Failure: error code from winerror.h
2372 * FIXME
2373 * Stub, returns NO_ERROR.
2375 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2377 FIXME("(pRoute %p): stub\n", pRoute);
2378 /* this is to add a route entry, how's it distinguishable from
2379 CreateIpForwardEntry?
2380 could use SIOCADDRT, not sure I want to */
2381 return 0;
2385 /******************************************************************
2386 * SetIpNetEntry (IPHLPAPI.@)
2388 * Modify an existing ARP entry.
2390 * PARAMS
2391 * pArpEntry [In] ARP entry with the new information
2393 * RETURNS
2394 * Success: NO_ERROR
2395 * Failure: error code from winerror.h
2397 * FIXME
2398 * Stub, returns NO_ERROR.
2400 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2402 FIXME("(pArpEntry %p): stub\n", pArpEntry);
2403 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
2404 return 0;
2408 /******************************************************************
2409 * SetIpStatistics (IPHLPAPI.@)
2411 * Toggle IP forwarding and det the default TTL value.
2413 * PARAMS
2414 * pIpStats [In] IP statistics with the new information
2416 * RETURNS
2417 * Success: NO_ERROR
2418 * Failure: error code from winerror.h
2420 * FIXME
2421 * Stub, returns NO_ERROR.
2423 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2425 FIXME("(pIpStats %p): stub\n", pIpStats);
2426 return 0;
2430 /******************************************************************
2431 * SetIpTTL (IPHLPAPI.@)
2433 * Set the default TTL value.
2435 * PARAMS
2436 * nTTL [In] new TTL value
2438 * RETURNS
2439 * Success: NO_ERROR
2440 * Failure: error code from winerror.h
2442 * FIXME
2443 * Stub, returns NO_ERROR.
2445 DWORD WINAPI SetIpTTL(UINT nTTL)
2447 FIXME("(nTTL %d): stub\n", nTTL);
2448 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2449 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2450 return 0;
2454 /******************************************************************
2455 * SetTcpEntry (IPHLPAPI.@)
2457 * Set the state of a TCP connection.
2459 * PARAMS
2460 * pTcpRow [In] specifies connection with new state
2462 * RETURNS
2463 * Success: NO_ERROR
2464 * Failure: error code from winerror.h
2466 * FIXME
2467 * Stub, returns NO_ERROR.
2469 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2471 FIXME("(pTcpRow %p): stub\n", pTcpRow);
2472 return 0;
2476 /******************************************************************
2477 * UnenableRouter (IPHLPAPI.@)
2479 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2480 * if it reaches zero.
2482 * PARAMS
2483 * pOverlapped [In/Out] should be the same as in EnableRouter()
2484 * lpdwEnableCount [Out] optional, receives reference count
2486 * RETURNS
2487 * Success: NO_ERROR
2488 * Failure: error code from winerror.h
2490 * FIXME
2491 * Stub, returns ERROR_NOT_SUPPORTED.
2493 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2495 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2496 lpdwEnableCount);
2497 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2498 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2500 return ERROR_NOT_SUPPORTED;
2503 /******************************************************************
2504 * PfCreateInterface (IPHLPAPI.@)
2506 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
2507 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
2509 FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
2510 return ERROR_CALL_NOT_IMPLEMENTED;
2513 /******************************************************************
2514 * PfUnBindInterface (IPHLPAPI.@)
2516 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
2518 FIXME("(%p) stub\n", interface);
2519 return ERROR_CALL_NOT_IMPLEMENTED;
2522 /******************************************************************
2523 * PfDeleteInterface(IPHLPAPI.@)
2525 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
2527 FIXME("(%p) stub\n", interface);
2528 return ERROR_CALL_NOT_IMPLEMENTED;
2531 /******************************************************************
2532 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
2534 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
2536 FIXME("(%p %d %p) stub\n", interface, type, ip);
2537 return ERROR_CALL_NOT_IMPLEMENTED;
2540 /******************************************************************
2541 * GetTcpTable2 (IPHLPAPI.@)
2543 ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
2545 FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
2546 return ERROR_NOT_SUPPORTED;
2549 /******************************************************************
2550 * GetTcp6Table (IPHLPAPI.@)
2552 ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
2554 FIXME("pTcp6Table %p, size %p, order %d: stub\n", table, size, order);
2555 return ERROR_NOT_SUPPORTED;
2558 /******************************************************************
2559 * GetTcp6Table2 (IPHLPAPI.@)
2561 ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
2563 FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
2564 return ERROR_NOT_SUPPORTED;