iphlpapi: Implement AllocateAndGetIfTableFromStack() on top of nsi.
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blobdac84ee2afbb759c15eeda95691794b86c0ef4c0
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 "windns.h"
50 #include "iphlpapi.h"
51 #include "ifenum.h"
52 #include "ipstats.h"
53 #include "ipifcons.h"
54 #include "fltdefs.h"
55 #include "ifdef.h"
56 #include "netioapi.h"
57 #include "tcpestats.h"
58 #include "ip2string.h"
59 #include "netiodef.h"
61 #include "wine/nsi.h"
62 #include "wine/debug.h"
63 #include "wine/unicode.h"
64 #include "wine/heap.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
68 #ifndef IF_NAMESIZE
69 #define IF_NAMESIZE 16
70 #endif
72 #ifndef INADDR_NONE
73 #define INADDR_NONE ~0UL
74 #endif
76 #define CHARS_IN_GUID 39
78 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags );
80 DWORD WINAPI ConvertGuidToStringA( const GUID *guid, char *str, DWORD len )
82 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
83 sprintf( str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
84 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
85 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
86 return ERROR_SUCCESS;
89 DWORD WINAPI ConvertGuidToStringW( const GUID *guid, WCHAR *str, DWORD len )
91 static const WCHAR fmt[] = { '{','%','0','8','X','-','%','0','4','X','-','%','0','4','X','-',
92 '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X',
93 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','}',0 };
95 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
96 sprintfW( str, fmt,
97 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
98 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
99 return ERROR_SUCCESS;
102 DWORD WINAPI ConvertStringToGuidW( const WCHAR *str, GUID *guid )
104 UNICODE_STRING ustr;
106 RtlInitUnicodeString( &ustr, str );
107 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr, guid ) );
110 /******************************************************************
111 * AddIPAddress (IPHLPAPI.@)
113 * Add an IP address to an adapter.
115 * PARAMS
116 * Address [In] IP address to add to the adapter
117 * IpMask [In] subnet mask for the IP address
118 * IfIndex [In] adapter index to add the address
119 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
120 * NTEInstance [Out] NTE instance for the IP address
122 * RETURNS
123 * Success: NO_ERROR
124 * Failure: error code from winerror.h
126 * FIXME
127 * Stub. Currently returns ERROR_NOT_SUPPORTED.
129 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
131 FIXME(":stub\n");
132 return ERROR_NOT_SUPPORTED;
135 static int IpAddrTableNumericSorter(const void *a, const void *b)
137 int ret = 0;
139 if (a && b)
140 ret = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
141 return ret;
144 static int IpAddrTableLoopbackSorter(const void *a, const void *b)
146 const MIB_IPADDRROW *left = a, *right = b;
147 int ret = 0;
149 if (isIfIndexLoopback(left->dwIndex))
150 ret = 1;
151 else if (isIfIndexLoopback(right->dwIndex))
152 ret = -1;
154 return ret;
157 /******************************************************************
158 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
160 * Get interface-to-IP address mapping table.
161 * Like GetIpAddrTable(), but allocate the returned table from heap.
163 * PARAMS
164 * ppIpAddrTable [Out] pointer into which the MIB_IPADDRTABLE is
165 * allocated and returned.
166 * bOrder [In] whether to sort the table
167 * heap [In] heap from which the table is allocated
168 * flags [In] flags to HeapAlloc
170 * RETURNS
171 * ERROR_INVALID_PARAMETER if ppIpAddrTable is NULL, other error codes on
172 * failure, NO_ERROR on success.
174 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
175 BOOL bOrder, HANDLE heap, DWORD flags)
177 DWORD ret;
179 TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
180 ppIpAddrTable, bOrder, heap, flags);
181 ret = getIPAddrTable(ppIpAddrTable, heap, flags);
182 if (!ret && bOrder)
183 qsort((*ppIpAddrTable)->table, (*ppIpAddrTable)->dwNumEntries,
184 sizeof(MIB_IPADDRROW), IpAddrTableNumericSorter);
185 TRACE("returning %d\n", ret);
186 return ret;
190 /******************************************************************
191 * CancelIPChangeNotify (IPHLPAPI.@)
193 * Cancel a previous notification created by NotifyAddrChange or
194 * NotifyRouteChange.
196 * PARAMS
197 * overlapped [In] overlapped structure that notifies the caller
199 * RETURNS
200 * Success: TRUE
201 * Failure: FALSE
203 * FIXME
204 * Stub, returns FALSE.
206 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
208 FIXME("(overlapped %p): stub\n", overlapped);
209 return FALSE;
213 /******************************************************************
214 * CancelMibChangeNotify2 (IPHLPAPI.@)
216 DWORD WINAPI CancelMibChangeNotify2(HANDLE handle)
218 FIXME("(handle %p): stub\n", handle);
219 return NO_ERROR;
223 /******************************************************************
224 * CreateIpForwardEntry (IPHLPAPI.@)
226 * Create a route in the local computer's IP table.
228 * PARAMS
229 * pRoute [In] new route information
231 * RETURNS
232 * Success: NO_ERROR
233 * Failure: error code from winerror.h
235 * FIXME
236 * Stub, always returns NO_ERROR.
238 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
240 FIXME("(pRoute %p): stub\n", pRoute);
241 /* could use SIOCADDRT, not sure I want to */
242 return 0;
246 /******************************************************************
247 * CreateIpNetEntry (IPHLPAPI.@)
249 * Create entry in the ARP table.
251 * PARAMS
252 * pArpEntry [In] new ARP entry
254 * RETURNS
255 * Success: NO_ERROR
256 * Failure: error code from winerror.h
258 * FIXME
259 * Stub, always returns NO_ERROR.
261 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
263 FIXME("(pArpEntry %p)\n", pArpEntry);
264 /* could use SIOCSARP on systems that support it, not sure I want to */
265 return 0;
269 /******************************************************************
270 * CreateProxyArpEntry (IPHLPAPI.@)
272 * Create a Proxy ARP (PARP) entry for an IP address.
274 * PARAMS
275 * dwAddress [In] IP address for which this computer acts as a proxy.
276 * dwMask [In] subnet mask for dwAddress
277 * dwIfIndex [In] interface index
279 * RETURNS
280 * Success: NO_ERROR
281 * Failure: error code from winerror.h
283 * FIXME
284 * Stub, returns ERROR_NOT_SUPPORTED.
286 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
288 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
289 dwAddress, dwMask, dwIfIndex);
290 return ERROR_NOT_SUPPORTED;
293 static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf)
295 const IN6_ADDR *addr = &sin->sin6_addr;
296 char *p = buf;
297 int i;
298 BOOL in_zero = FALSE;
300 for (i = 0; i < 7; i++)
302 if (!addr->u.Word[i])
304 if (i == 0)
305 *p++ = ':';
306 if (!in_zero)
308 *p++ = ':';
309 in_zero = TRUE;
312 else
314 p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
315 in_zero = FALSE;
318 sprintf(p, "%x", ntohs(addr->u.Word[7]));
319 return buf;
322 static BOOL map_address_6to4( const SOCKADDR_IN6 *addr6, SOCKADDR_IN *addr4 )
324 ULONG i;
326 if (addr6->sin6_family != WS_AF_INET6) return FALSE;
328 for (i = 0; i < 5; i++)
329 if (addr6->sin6_addr.u.Word[i]) return FALSE;
331 if (addr6->sin6_addr.u.Word[5] != 0xffff) return FALSE;
333 addr4->sin_family = WS_AF_INET;
334 addr4->sin_port = addr6->sin6_port;
335 addr4->sin_addr.S_un.S_addr = addr6->sin6_addr.u.Word[6] << 16 | addr6->sin6_addr.u.Word[7];
336 memset( &addr4->sin_zero, 0, sizeof(addr4->sin_zero) );
338 return TRUE;
341 static BOOL find_src_address( MIB_IPADDRTABLE *table, const SOCKADDR_IN *dst, SOCKADDR_IN6 *src )
343 MIB_IPFORWARDROW row;
344 DWORD i, j;
346 if (GetBestRoute( dst->sin_addr.S_un.S_addr, 0, &row )) return FALSE;
348 for (i = 0; i < table->dwNumEntries; i++)
350 /* take the first address */
351 if (table->table[i].dwIndex == row.dwForwardIfIndex)
353 src->sin6_family = WS_AF_INET6;
354 src->sin6_port = 0;
355 src->sin6_flowinfo = 0;
356 for (j = 0; j < 5; j++) src->sin6_addr.u.Word[j] = 0;
357 src->sin6_addr.u.Word[5] = 0xffff;
358 src->sin6_addr.u.Word[6] = table->table[i].dwAddr & 0xffff;
359 src->sin6_addr.u.Word[7] = table->table[i].dwAddr >> 16;
360 return TRUE;
364 return FALSE;
367 /******************************************************************
368 * CreateSortedAddressPairs (IPHLPAPI.@)
370 DWORD WINAPI CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list, DWORD src_count,
371 const PSOCKADDR_IN6 dst_list, DWORD dst_count,
372 DWORD options, PSOCKADDR_IN6_PAIR *pair_list,
373 DWORD *pair_count )
375 DWORD i, size, ret;
376 SOCKADDR_IN6_PAIR *pairs;
377 SOCKADDR_IN6 *ptr;
378 SOCKADDR_IN addr4;
379 MIB_IPADDRTABLE *table;
381 FIXME( "(src_list %p src_count %u dst_list %p dst_count %u options %x pair_list %p pair_count %p): stub\n",
382 src_list, src_count, dst_list, dst_count, options, pair_list, pair_count );
384 if (src_list || src_count || !dst_list || !pair_list || !pair_count || dst_count > 500)
385 return ERROR_INVALID_PARAMETER;
387 for (i = 0; i < dst_count; i++)
389 if (!map_address_6to4( &dst_list[i], &addr4 ))
391 FIXME("only mapped IPv4 addresses are supported\n");
392 return ERROR_NOT_SUPPORTED;
396 size = dst_count * sizeof(*pairs);
397 size += dst_count * sizeof(SOCKADDR_IN6) * 2; /* source address + destination address */
398 if (!(pairs = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_NOT_ENOUGH_MEMORY;
399 ptr = (SOCKADDR_IN6 *)&pairs[dst_count];
401 if ((ret = getIPAddrTable( &table, GetProcessHeap(), 0 )))
403 HeapFree( GetProcessHeap(), 0, pairs );
404 return ret;
407 for (i = 0; i < dst_count; i++)
409 pairs[i].SourceAddress = ptr++;
410 if (!map_address_6to4( &dst_list[i], &addr4 ) ||
411 !find_src_address( table, &addr4, pairs[i].SourceAddress ))
413 char buf[46];
414 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list[i], buf) );
415 memset( pairs[i].SourceAddress, 0, sizeof(*pairs[i].SourceAddress) );
416 pairs[i].SourceAddress->sin6_family = WS_AF_INET6;
419 pairs[i].DestinationAddress = ptr++;
420 memcpy( pairs[i].DestinationAddress, &dst_list[i], sizeof(*pairs[i].DestinationAddress) );
422 *pair_list = pairs;
423 *pair_count = dst_count;
425 HeapFree( GetProcessHeap(), 0, table );
426 return NO_ERROR;
430 /******************************************************************
431 * DeleteIPAddress (IPHLPAPI.@)
433 * Delete an IP address added with AddIPAddress().
435 * PARAMS
436 * NTEContext [In] NTE context from AddIPAddress();
438 * RETURNS
439 * Success: NO_ERROR
440 * Failure: error code from winerror.h
442 * FIXME
443 * Stub, returns ERROR_NOT_SUPPORTED.
445 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
447 FIXME("(NTEContext %d): stub\n", NTEContext);
448 return ERROR_NOT_SUPPORTED;
452 /******************************************************************
453 * DeleteIpForwardEntry (IPHLPAPI.@)
455 * Delete a route.
457 * PARAMS
458 * pRoute [In] route to delete
460 * RETURNS
461 * Success: NO_ERROR
462 * Failure: error code from winerror.h
464 * FIXME
465 * Stub, returns NO_ERROR.
467 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
469 FIXME("(pRoute %p): stub\n", pRoute);
470 /* could use SIOCDELRT, not sure I want to */
471 return 0;
475 /******************************************************************
476 * DeleteIpNetEntry (IPHLPAPI.@)
478 * Delete an ARP entry.
480 * PARAMS
481 * pArpEntry [In] ARP entry to delete
483 * RETURNS
484 * Success: NO_ERROR
485 * Failure: error code from winerror.h
487 * FIXME
488 * Stub, returns NO_ERROR.
490 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
492 FIXME("(pArpEntry %p): stub\n", pArpEntry);
493 /* could use SIOCDARP on systems that support it, not sure I want to */
494 return 0;
498 /******************************************************************
499 * DeleteProxyArpEntry (IPHLPAPI.@)
501 * Delete a Proxy ARP entry.
503 * PARAMS
504 * dwAddress [In] IP address for which this computer acts as a proxy.
505 * dwMask [In] subnet mask for dwAddress
506 * dwIfIndex [In] interface index
508 * RETURNS
509 * Success: NO_ERROR
510 * Failure: error code from winerror.h
512 * FIXME
513 * Stub, returns ERROR_NOT_SUPPORTED.
515 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
517 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
518 dwAddress, dwMask, dwIfIndex);
519 return ERROR_NOT_SUPPORTED;
523 /******************************************************************
524 * EnableRouter (IPHLPAPI.@)
526 * Turn on ip forwarding.
528 * PARAMS
529 * pHandle [In/Out]
530 * pOverlapped [In/Out] hEvent member should contain a valid handle.
532 * RETURNS
533 * Success: ERROR_IO_PENDING
534 * Failure: error code from winerror.h
536 * FIXME
537 * Stub, returns ERROR_NOT_SUPPORTED.
539 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
541 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
542 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
543 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
545 return ERROR_NOT_SUPPORTED;
549 /******************************************************************
550 * FlushIpNetTable (IPHLPAPI.@)
552 * Delete all ARP entries of an interface
554 * PARAMS
555 * dwIfIndex [In] interface index
557 * RETURNS
558 * Success: NO_ERROR
559 * Failure: error code from winerror.h
561 * FIXME
562 * Stub, returns ERROR_NOT_SUPPORTED.
564 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
566 FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
567 /* this flushes the arp cache of the given index */
568 return ERROR_NOT_SUPPORTED;
571 /******************************************************************
572 * FreeMibTable (IPHLPAPI.@)
574 * Free buffer allocated by network functions
576 * PARAMS
577 * ptr [In] pointer to the buffer to free
580 void WINAPI FreeMibTable(void *ptr)
582 TRACE("(%p)\n", ptr);
583 HeapFree(GetProcessHeap(), 0, ptr);
586 /******************************************************************
587 * GetAdapterIndex (IPHLPAPI.@)
589 * Get interface index from its name.
591 * PARAMS
592 * adapter_name [In] unicode string with the adapter name
593 * index [Out] returns found interface index
595 * RETURNS
596 * Success: NO_ERROR
597 * Failure: error code from winerror.h
599 DWORD WINAPI GetAdapterIndex( WCHAR *adapter_name, ULONG *index )
601 MIB_IFTABLE *if_table;
602 DWORD err, i;
604 TRACE( "name %s, index %p\n", debugstr_w( adapter_name ), index );
606 err = AllocateAndGetIfTableFromStack( &if_table, 0, GetProcessHeap(), 0 );
607 if (err) return err;
609 err = ERROR_INVALID_PARAMETER;
610 for (i = 0; i < if_table->dwNumEntries; i++)
612 if (!strcmpW( adapter_name, if_table->table[i].wszName ))
614 *index = if_table->table[i].dwIndex;
615 err = ERROR_SUCCESS;
616 break;
619 heap_free( if_table );
620 return err;
624 /******************************************************************
625 * GetAdaptersInfo (IPHLPAPI.@)
627 * Get information about adapters.
629 * PARAMS
630 * pAdapterInfo [Out] buffer for adapter infos
631 * pOutBufLen [In] length of output buffer
633 * RETURNS
634 * Success: NO_ERROR
635 * Failure: error code from winerror.h
637 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
639 DWORD ret;
641 TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
642 if (!pOutBufLen)
643 ret = ERROR_INVALID_PARAMETER;
644 else {
645 DWORD numNonLoopbackInterfaces = get_interface_indices( TRUE, NULL );
647 if (numNonLoopbackInterfaces > 0) {
648 DWORD numIPAddresses = getNumIPAddresses();
649 ULONG size;
651 /* This may slightly overestimate the amount of space needed, because
652 * the IP addresses include the loopback address, but it's easier
653 * to make sure there's more than enough space than to make sure there's
654 * precisely enough space.
656 size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
657 size += numIPAddresses * sizeof(IP_ADDR_STRING);
658 if (!pAdapterInfo || *pOutBufLen < size) {
659 *pOutBufLen = size;
660 ret = ERROR_BUFFER_OVERFLOW;
662 else {
663 InterfaceIndexTable *table = NULL;
664 PMIB_IPADDRTABLE ipAddrTable = NULL;
665 PMIB_IPFORWARDTABLE routeTable = NULL;
667 ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
668 if (!ret)
669 ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
670 if (!ret)
671 get_interface_indices( TRUE, &table );
672 if (table) {
673 size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
674 size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING);
675 if (*pOutBufLen < size) {
676 *pOutBufLen = size;
677 ret = ERROR_INSUFFICIENT_BUFFER;
679 else {
680 DWORD ndx;
681 HKEY hKey;
682 BOOL winsEnabled = FALSE;
683 IP_ADDRESS_STRING primaryWINS, secondaryWINS;
684 PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
685 + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
687 memset(pAdapterInfo, 0, size);
688 /* @@ Wine registry key: HKCU\Software\Wine\Network */
689 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
690 &hKey) == ERROR_SUCCESS) {
691 DWORD size = sizeof(primaryWINS.String);
692 unsigned long addr;
694 RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
695 (LPBYTE)primaryWINS.String, &size);
696 addr = inet_addr(primaryWINS.String);
697 if (addr != INADDR_NONE && addr != INADDR_ANY)
698 winsEnabled = TRUE;
699 size = sizeof(secondaryWINS.String);
700 RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
701 (LPBYTE)secondaryWINS.String, &size);
702 addr = inet_addr(secondaryWINS.String);
703 if (addr != INADDR_NONE && addr != INADDR_ANY)
704 winsEnabled = TRUE;
705 RegCloseKey(hKey);
707 for (ndx = 0; ndx < table->numIndexes; ndx++) {
708 PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
709 DWORD i;
710 PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
711 BOOL firstIPAddr = TRUE;
712 NET_LUID luid;
713 GUID guid;
715 /* on Win98 this is left empty, but whatever */
716 ConvertInterfaceIndexToLuid(table->indexes[ndx], &luid);
717 ConvertInterfaceLuidToGuid(&luid, &guid);
718 ConvertGuidToStringA( &guid, ptr->AdapterName, ARRAY_SIZE(ptr->AdapterName) );
719 getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
720 ptr->AddressLength = sizeof(ptr->Address);
721 getInterfacePhysicalByIndex(table->indexes[ndx],
722 &ptr->AddressLength, ptr->Address, &ptr->Type);
723 ptr->Index = table->indexes[ndx];
724 for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
725 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
726 if (firstIPAddr) {
727 RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwAddr,
728 ptr->IpAddressList.IpAddress.String);
729 RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwMask,
730 ptr->IpAddressList.IpMask.String);
731 firstIPAddr = FALSE;
733 else {
734 currentIPAddr->Next = nextIPAddr;
735 currentIPAddr = nextIPAddr;
736 RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwAddr,
737 currentIPAddr->IpAddress.String);
738 RtlIpv4AddressToStringA((IN_ADDR *)&ipAddrTable->table[i].dwMask,
739 currentIPAddr->IpMask.String);
740 nextIPAddr++;
744 /* If no IP was found it probably means that the interface is not
745 * configured. In this case we have to return a zeroed IP and mask. */
746 if (firstIPAddr) {
747 strcpy(ptr->IpAddressList.IpAddress.String, "0.0.0.0");
748 strcpy(ptr->IpAddressList.IpMask.String, "0.0.0.0");
750 /* Find first router through this interface, which we'll assume
751 * is the default gateway for this adapter */
752 strcpy(ptr->GatewayList.IpAddress.String, "0.0.0.0");
753 strcpy(ptr->GatewayList.IpMask.String, "255.255.255.255");
754 for (i = 0; i < routeTable->dwNumEntries; i++)
755 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
756 && routeTable->table[i].u1.ForwardType ==
757 MIB_IPROUTE_TYPE_INDIRECT)
759 RtlIpv4AddressToStringA((IN_ADDR *)&routeTable->table[i].dwForwardNextHop,
760 ptr->GatewayList.IpAddress.String);
761 RtlIpv4AddressToStringA((IN_ADDR *)&routeTable->table[i].dwForwardMask,
762 ptr->GatewayList.IpMask.String);
764 if (winsEnabled) {
765 ptr->HaveWins = TRUE;
766 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
767 primaryWINS.String, sizeof(primaryWINS.String));
768 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
769 secondaryWINS.String, sizeof(secondaryWINS.String));
771 if (ndx < table->numIndexes - 1)
772 ptr->Next = &pAdapterInfo[ndx + 1];
773 else
774 ptr->Next = NULL;
776 ptr->DhcpEnabled = TRUE;
778 ret = NO_ERROR;
780 HeapFree(GetProcessHeap(), 0, table);
782 else
783 ret = ERROR_OUTOFMEMORY;
784 HeapFree(GetProcessHeap(), 0, routeTable);
785 HeapFree(GetProcessHeap(), 0, ipAddrTable);
788 else
789 ret = ERROR_NO_DATA;
791 TRACE("returning %d\n", ret);
792 return ret;
795 static DWORD typeFromMibType(DWORD mib_type)
797 switch (mib_type)
799 case MIB_IF_TYPE_ETHERNET: return IF_TYPE_ETHERNET_CSMACD;
800 case MIB_IF_TYPE_TOKENRING: return IF_TYPE_ISO88025_TOKENRING;
801 case MIB_IF_TYPE_PPP: return IF_TYPE_PPP;
802 case MIB_IF_TYPE_LOOPBACK: return IF_TYPE_SOFTWARE_LOOPBACK;
803 default: return IF_TYPE_OTHER;
807 static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
809 switch (mib_type)
811 case MIB_IF_TYPE_PPP: return NET_IF_CONNECTION_DEMAND;
812 case MIB_IF_TYPE_SLIP: return NET_IF_CONNECTION_DEMAND;
813 default: return NET_IF_CONNECTION_DEDICATED;
817 static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs, DWORD **masks)
819 ULONG ret, i, j;
820 MIB_IPADDRTABLE *at;
822 *num_addrs = 0;
823 if ((ret = getIPAddrTable(&at, GetProcessHeap(), 0))) return ret;
824 for (i = 0; i < at->dwNumEntries; i++)
826 if (at->table[i].dwIndex == index) (*num_addrs)++;
828 if (!(*addrs = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
830 HeapFree(GetProcessHeap(), 0, at);
831 return ERROR_OUTOFMEMORY;
833 if (!(*masks = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
835 HeapFree(GetProcessHeap(), 0, *addrs);
836 HeapFree(GetProcessHeap(), 0, at);
837 return ERROR_OUTOFMEMORY;
839 for (i = 0, j = 0; i < at->dwNumEntries; i++)
841 if (at->table[i].dwIndex == index)
843 (*addrs)[j] = at->table[i].dwAddr;
844 (*masks)[j] = at->table[i].dwMask;
845 j++;
848 HeapFree(GetProcessHeap(), 0, at);
849 return ERROR_SUCCESS;
852 static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf)
854 const BYTE *addrp;
855 char *p = buf;
857 for (addrp = (const BYTE *)in_addr;
858 addrp - (const BYTE *)in_addr < sizeof(*in_addr);
859 addrp++)
861 if (addrp == (const BYTE *)in_addr + sizeof(*in_addr) - 1)
862 sprintf(p, "%d", *addrp);
863 else
864 p += sprintf(p, "%d.", *addrp);
866 return buf;
869 static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable)
871 DWORD i, num_gateways = 0;
873 for (i = 0; i < routeTable->dwNumEntries; i++)
875 if (routeTable->table[i].dwForwardIfIndex == index &&
876 routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
877 num_gateways++;
879 return num_gateways;
882 static DWORD mask_v4_to_prefix(DWORD m)
884 #ifdef HAVE___BUILTIN_POPCOUNT
885 return __builtin_popcount(m);
886 #else
887 m -= m >> 1 & 0x55555555;
888 m = (m & 0x33333333) + (m >> 2 & 0x33333333);
889 return ((m + (m >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
890 #endif
893 static DWORD mask_v6_to_prefix(SOCKET_ADDRESS *m)
895 const IN6_ADDR *mask = &((struct WS_sockaddr_in6 *)m->lpSockaddr)->sin6_addr;
896 DWORD ret = 0, i;
898 for (i = 0; i < 8; i++)
899 ret += mask_v4_to_prefix(mask->u.Word[i]);
900 return ret;
903 static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
904 PMIB_IPFORWARDTABLE routeTable)
906 DWORD i;
907 PMIB_IPFORWARDROW row = NULL;
909 for (i = 0; !row && i < routeTable->dwNumEntries; i++)
911 if (routeTable->table[i].dwForwardIfIndex == index &&
912 routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
913 row = &routeTable->table[i];
915 return row;
918 static void fill_unicast_addr_data(IP_ADAPTER_ADDRESSES *aa, IP_ADAPTER_UNICAST_ADDRESS *ua)
920 /* Actually this information should be read somewhere from the system
921 * but it doesn't matter much for the bugs found so far.
922 * This information is required for DirectPlay8 games. */
923 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK)
925 ua->PrefixOrigin = IpPrefixOriginDhcp;
926 ua->SuffixOrigin = IpSuffixOriginDhcp;
928 else
930 ua->PrefixOrigin = IpPrefixOriginManual;
931 ua->SuffixOrigin = IpSuffixOriginManual;
934 /* The address is not duplicated in the network */
935 ua->DadState = IpDadStatePreferred;
937 /* Some address life time values, required even for non-dhcp addresses */
938 ua->ValidLifetime = 60000;
939 ua->PreferredLifetime = 60000;
940 ua->LeaseLifetime = 60000;
943 static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
944 IP_ADAPTER_ADDRESSES *aa, ULONG *size)
946 ULONG ret = ERROR_SUCCESS, i, j, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
947 DWORD *v4addrs = NULL, *v4masks = NULL;
948 SOCKET_ADDRESS *v6addrs = NULL, *v6masks = NULL;
949 PMIB_IPFORWARDTABLE routeTable = NULL;
950 BOOL output_gateways;
952 if ((flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) || !(flags & GAA_FLAG_SKIP_UNICAST))
954 ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
955 if (ret) return ret;
956 num_v4_gateways = count_v4_gateways(index, routeTable);
958 output_gateways = (flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS) && (family == WS_AF_INET || family == WS_AF_UNSPEC);
960 if (family == WS_AF_INET)
962 ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
964 else if (family == WS_AF_INET6)
966 ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
968 else if (family == WS_AF_UNSPEC)
970 ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs, &v4masks);
971 if (!ret) ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs, &v6masks);
973 else
975 FIXME("address family %u unsupported\n", family);
976 ret = ERROR_NO_DATA;
978 if (ret)
980 HeapFree(GetProcessHeap(), 0, v4addrs);
981 HeapFree(GetProcessHeap(), 0, v4masks);
982 HeapFree(GetProcessHeap(), 0, v6addrs);
983 HeapFree(GetProcessHeap(), 0, v6masks);
984 HeapFree(GetProcessHeap(), 0, routeTable);
985 return ret;
988 total_size = sizeof(IP_ADAPTER_ADDRESSES);
989 total_size += CHARS_IN_GUID;
990 total_size += IF_NAMESIZE * sizeof(WCHAR);
991 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
992 total_size += IF_NAMESIZE * sizeof(WCHAR);
993 if (flags & GAA_FLAG_INCLUDE_PREFIX)
995 total_size += sizeof(IP_ADAPTER_PREFIX) * num_v4addrs;
996 total_size += sizeof(IP_ADAPTER_PREFIX) * num_v6addrs;
997 total_size += sizeof(struct sockaddr_in) * num_v4addrs;
998 for (i = 0; i < num_v6addrs; i++)
999 total_size += v6masks[i].iSockaddrLength;
1001 total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
1002 total_size += sizeof(struct sockaddr_in) * num_v4addrs;
1003 if (output_gateways)
1004 total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways;
1005 total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v6addrs;
1006 total_size += sizeof(SOCKET_ADDRESS) * num_v6addrs;
1007 for (i = 0; i < num_v6addrs; i++)
1008 total_size += v6addrs[i].iSockaddrLength;
1010 if (aa && *size >= total_size)
1012 char name[IF_NAMESIZE], *ptr = (char *)aa + sizeof(IP_ADAPTER_ADDRESSES), *src;
1013 WCHAR *dst;
1014 DWORD buflen, type;
1015 INTERNAL_IF_OPER_STATUS status;
1016 NET_LUID luid;
1017 GUID guid;
1019 memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES));
1020 aa->u.s.Length = sizeof(IP_ADAPTER_ADDRESSES);
1021 aa->u.s.IfIndex = index;
1023 ConvertInterfaceIndexToLuid(index, &luid);
1024 ConvertInterfaceLuidToGuid(&luid, &guid);
1025 ConvertGuidToStringA( &guid, ptr, CHARS_IN_GUID );
1026 aa->AdapterName = ptr;
1027 ptr += CHARS_IN_GUID;
1029 getInterfaceNameByIndex(index, name);
1030 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
1032 aa->FriendlyName = (WCHAR *)ptr;
1033 for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
1034 *dst = *src;
1035 *dst++ = 0;
1036 ptr = (char *)dst;
1038 aa->Description = (WCHAR *)ptr;
1039 for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
1040 *dst = *src;
1041 *dst++ = 0;
1042 ptr = (char *)dst;
1044 TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name, num_v4addrs,
1045 num_v6addrs);
1047 buflen = MAX_INTERFACE_PHYSADDR;
1048 getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
1049 aa->PhysicalAddressLength = buflen;
1050 aa->IfType = typeFromMibType(type);
1051 aa->ConnectionType = connectionTypeFromMibType(type);
1052 ConvertInterfaceIndexToLuid( index, &aa->Luid );
1054 if (output_gateways && num_v4_gateways)
1056 PMIB_IPFORWARDROW adapterRow;
1058 if ((adapterRow = findIPv4Gateway(index, routeTable)))
1060 PIP_ADAPTER_GATEWAY_ADDRESS gw;
1061 PSOCKADDR_IN sin;
1063 gw = (PIP_ADAPTER_GATEWAY_ADDRESS)ptr;
1064 aa->FirstGatewayAddress = gw;
1066 gw->u.s.Length = sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
1067 ptr += sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
1068 sin = (PSOCKADDR_IN)ptr;
1069 sin->sin_family = WS_AF_INET;
1070 sin->sin_port = 0;
1071 memcpy(&sin->sin_addr, &adapterRow->dwForwardNextHop,
1072 sizeof(DWORD));
1073 gw->Address.lpSockaddr = (LPSOCKADDR)sin;
1074 gw->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
1075 gw->Next = NULL;
1076 ptr += sizeof(SOCKADDR_IN);
1079 if (num_v4addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
1081 IP_ADAPTER_UNICAST_ADDRESS *ua;
1082 struct WS_sockaddr_in *sa;
1083 aa->u1.s1.Ipv4Enabled = TRUE;
1084 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1085 for (i = 0; i < num_v4addrs; i++)
1087 char addr_buf[16];
1089 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
1090 ua->u.s.Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
1091 ua->Address.iSockaddrLength = sizeof(struct sockaddr_in);
1092 ua->Address.lpSockaddr = (SOCKADDR *)((char *)ua + ua->u.s.Length);
1093 if (num_v4_gateways)
1094 ua->u.s.Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
1096 sa = (struct WS_sockaddr_in *)ua->Address.lpSockaddr;
1097 sa->sin_family = WS_AF_INET;
1098 sa->sin_addr.S_un.S_addr = v4addrs[i];
1099 sa->sin_port = 0;
1100 TRACE("IPv4 %d/%d: %s\n", i + 1, num_v4addrs,
1101 debugstr_ipv4(&sa->sin_addr.S_un.S_addr, addr_buf));
1102 fill_unicast_addr_data(aa, ua);
1104 ua->OnLinkPrefixLength = mask_v4_to_prefix(v4masks[i]);
1106 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
1107 if (i < num_v4addrs - 1)
1109 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1110 ua = ua->Next;
1114 if (num_v6addrs && !(flags & GAA_FLAG_SKIP_UNICAST))
1116 IP_ADAPTER_UNICAST_ADDRESS *ua;
1117 struct WS_sockaddr_in6 *sa;
1119 aa->u1.s1.Ipv6Enabled = TRUE;
1120 if (aa->FirstUnicastAddress)
1122 for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
1124 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1125 ua = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1127 else
1128 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1129 for (i = 0; i < num_v6addrs; i++)
1131 char addr_buf[46];
1133 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
1134 ua->u.s.Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
1135 ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
1136 ua->Address.lpSockaddr = (SOCKADDR *)((char *)ua + ua->u.s.Length);
1138 sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
1139 memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
1140 TRACE("IPv6 %d/%d: %s\n", i + 1, num_v6addrs,
1141 debugstr_ipv6(sa, addr_buf));
1142 fill_unicast_addr_data(aa, ua);
1144 ua->OnLinkPrefixLength = mask_v6_to_prefix(&v6masks[i]);
1146 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
1147 if (i < num_v6addrs - 1)
1149 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
1150 ua = ua->Next;
1154 if (num_v4addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
1156 IP_ADAPTER_PREFIX *prefix;
1158 prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
1159 for (i = 0; i < num_v4addrs; i++)
1161 char addr_buf[16];
1162 struct WS_sockaddr_in *sa;
1164 prefix->u.s.Length = sizeof(*prefix);
1165 prefix->u.s.Flags = 0;
1166 prefix->Next = NULL;
1167 prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in);
1168 prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
1170 sa = (struct WS_sockaddr_in *)prefix->Address.lpSockaddr;
1171 sa->sin_family = WS_AF_INET;
1172 sa->sin_addr.S_un.S_addr = v4addrs[i] & v4masks[i];
1173 sa->sin_port = 0;
1175 prefix->PrefixLength = mask_v4_to_prefix(v4masks[i]);
1177 TRACE("IPv4 network: %s/%u\n",
1178 debugstr_ipv4((const in_addr_t *)&sa->sin_addr.S_un.S_addr, addr_buf),
1179 prefix->PrefixLength);
1181 ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
1182 if (i < num_v4addrs - 1)
1184 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
1185 prefix = prefix->Next;
1189 if (num_v6addrs && (flags & GAA_FLAG_INCLUDE_PREFIX))
1191 IP_ADAPTER_PREFIX *prefix;
1193 if (aa->FirstPrefix)
1195 for (prefix = aa->FirstPrefix; prefix->Next; prefix = prefix->Next)
1197 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
1198 prefix = (IP_ADAPTER_PREFIX *)ptr;
1200 else
1201 prefix = aa->FirstPrefix = (IP_ADAPTER_PREFIX *)ptr;
1202 for (i = 0; i < num_v6addrs; i++)
1204 char addr_buf[46];
1205 struct WS_sockaddr_in6 *sa;
1206 const IN6_ADDR *addr, *mask;
1208 prefix->u.s.Length = sizeof(*prefix);
1209 prefix->u.s.Flags = 0;
1210 prefix->Next = NULL;
1211 prefix->Address.iSockaddrLength = sizeof(struct sockaddr_in6);
1212 prefix->Address.lpSockaddr = (SOCKADDR *)((char *)prefix + prefix->u.s.Length);
1214 sa = (struct WS_sockaddr_in6 *)prefix->Address.lpSockaddr;
1215 sa->sin6_family = WS_AF_INET6;
1216 sa->sin6_port = 0;
1217 sa->sin6_flowinfo = 0;
1218 addr = &((struct WS_sockaddr_in6 *)v6addrs[i].lpSockaddr)->sin6_addr;
1219 mask = &((struct WS_sockaddr_in6 *)v6masks[i].lpSockaddr)->sin6_addr;
1220 for (j = 0; j < 8; j++) sa->sin6_addr.u.Word[j] = addr->u.Word[j] & mask->u.Word[j];
1221 sa->sin6_scope_id = 0;
1223 prefix->PrefixLength = mask_v6_to_prefix(&v6masks[i]);
1225 TRACE("IPv6 network: %s/%u\n", debugstr_ipv6(sa, addr_buf), prefix->PrefixLength);
1227 ptr += prefix->u.s.Length + prefix->Address.iSockaddrLength;
1228 if (i < num_v6addrs - 1)
1230 prefix->Next = (IP_ADAPTER_PREFIX *)ptr;
1231 prefix = prefix->Next;
1236 getInterfaceMtuByName(name, &aa->Mtu);
1238 getInterfaceStatusByName(name, &status);
1239 if (status == MIB_IF_OPER_STATUS_OPERATIONAL) aa->OperStatus = IfOperStatusUp;
1240 else if (status == MIB_IF_OPER_STATUS_NON_OPERATIONAL) aa->OperStatus = IfOperStatusDown;
1241 else aa->OperStatus = IfOperStatusUnknown;
1243 *size = total_size;
1244 HeapFree(GetProcessHeap(), 0, routeTable);
1245 HeapFree(GetProcessHeap(), 0, v6addrs);
1246 HeapFree(GetProcessHeap(), 0, v6masks);
1247 HeapFree(GetProcessHeap(), 0, v4addrs);
1248 HeapFree(GetProcessHeap(), 0, v4masks);
1249 return ERROR_SUCCESS;
1252 static void sockaddr_in_to_WS_storage( SOCKADDR_STORAGE *dst, const struct sockaddr_in *src )
1254 SOCKADDR_IN *s = (SOCKADDR_IN *)dst;
1256 s->sin_family = WS_AF_INET;
1257 s->sin_port = src->sin_port;
1258 memcpy( &s->sin_addr, &src->sin_addr, sizeof(IN_ADDR) );
1259 memset( (char *)s + FIELD_OFFSET( SOCKADDR_IN, sin_zero ), 0,
1260 sizeof(SOCKADDR_STORAGE) - FIELD_OFFSET( SOCKADDR_IN, sin_zero) );
1263 #if defined(HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6) || \
1264 (defined(HAVE___RES_GET_STATE) && defined(HAVE___RES_GETSERVERS)) || \
1265 defined(HAVE_RES_GETSERVERS)
1266 static void sockaddr_in6_to_WS_storage( SOCKADDR_STORAGE *dst, const struct sockaddr_in6 *src )
1268 SOCKADDR_IN6 *s = (SOCKADDR_IN6 *)dst;
1270 s->sin6_family = WS_AF_INET6;
1271 s->sin6_port = src->sin6_port;
1272 s->sin6_flowinfo = src->sin6_flowinfo;
1273 memcpy( &s->sin6_addr, &src->sin6_addr, sizeof(IN6_ADDR) );
1274 s->sin6_scope_id = src->sin6_scope_id;
1275 memset( (char *)s + sizeof(SOCKADDR_IN6), 0,
1276 sizeof(SOCKADDR_STORAGE) - sizeof(SOCKADDR_IN6) );
1278 #endif
1280 #ifdef HAVE_STRUCT___RES_STATE
1281 /* call res_init() just once because of a bug in Mac OS X 10.4 */
1282 /* Call once per thread on systems that have per-thread _res. */
1284 static CRITICAL_SECTION res_init_cs;
1285 static CRITICAL_SECTION_DEBUG res_init_cs_debug = {
1286 0, 0, &res_init_cs,
1287 { &res_init_cs_debug.ProcessLocksList, &res_init_cs_debug.ProcessLocksList },
1288 0, 0, { (DWORD_PTR)(__FILE__ ": res_init_cs") }
1290 static CRITICAL_SECTION res_init_cs = { &res_init_cs_debug, -1, 0, 0, 0, 0 };
1292 static void initialise_resolver(void)
1294 EnterCriticalSection(&res_init_cs);
1295 if ((_res.options & RES_INIT) == 0)
1296 res_init();
1297 LeaveCriticalSection(&res_init_cs);
1300 #ifdef HAVE_RES_GETSERVERS
1301 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1303 struct __res_state *state = &_res;
1304 int i, found = 0, total;
1305 SOCKADDR_STORAGE *addr = servers;
1306 union res_sockaddr_union *buf;
1308 initialise_resolver();
1310 total = res_getservers( state, NULL, 0 );
1312 if ((!servers || !num) && !ip4_only) return total;
1314 buf = HeapAlloc( GetProcessHeap(), 0, total * sizeof(union res_sockaddr_union) );
1315 total = res_getservers( state, buf, total );
1317 for (i = 0; i < total; i++)
1319 if (buf[i].sin6.sin6_family == AF_INET6 && ip4_only) continue;
1320 if (buf[i].sin.sin_family != AF_INET && buf[i].sin6.sin6_family != AF_INET6) continue;
1322 found++;
1323 if (!servers || !num) continue;
1325 if (buf[i].sin6.sin6_family == AF_INET6)
1327 sockaddr_in6_to_WS_storage( addr, &buf[i].sin6 );
1329 else
1331 sockaddr_in_to_WS_storage( addr, &buf[i].sin );
1333 if (++addr >= servers + num) break;
1336 HeapFree( GetProcessHeap(), 0, buf );
1337 return found;
1339 #else
1341 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1343 int i, ip6_count = 0;
1344 SOCKADDR_STORAGE *addr;
1346 initialise_resolver();
1348 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1349 ip6_count = _res._u._ext.nscount6;
1350 #endif
1352 if (!servers || !num)
1354 num = _res.nscount;
1355 if (ip4_only) num -= ip6_count;
1356 return num;
1359 for (i = 0, addr = servers; addr < (servers + num) && i < _res.nscount; i++)
1361 #ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
1362 if (_res._u._ext.nsaddrs[i] && _res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
1364 if (ip4_only) continue;
1365 sockaddr_in6_to_WS_storage( addr, _res._u._ext.nsaddrs[i] );
1367 else
1368 #endif
1370 sockaddr_in_to_WS_storage( addr, _res.nsaddr_list + i );
1372 addr++;
1374 return addr - servers;
1376 #endif
1377 #elif defined(HAVE___RES_GET_STATE) && defined(HAVE___RES_GETSERVERS)
1379 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1381 extern struct res_state *__res_get_state( void );
1382 extern int __res_getservers( struct res_state *, struct sockaddr_storage *, int );
1383 struct res_state *state = __res_get_state();
1384 int i, found = 0, total = __res_getservers( state, NULL, 0 );
1385 SOCKADDR_STORAGE *addr = servers;
1386 struct sockaddr_storage *buf;
1388 if ((!servers || !num) && !ip4_only) return total;
1390 buf = HeapAlloc( GetProcessHeap(), 0, total * sizeof(struct sockaddr_storage) );
1391 total = __res_getservers( state, buf, total );
1393 for (i = 0; i < total; i++)
1395 if (buf[i].ss_family == AF_INET6 && ip4_only) continue;
1396 if (buf[i].ss_family != AF_INET && buf[i].ss_family != AF_INET6) continue;
1398 found++;
1399 if (!servers || !num) continue;
1401 if (buf[i].ss_family == AF_INET6)
1403 sockaddr_in6_to_WS_storage( addr, (struct sockaddr_in6 *)(buf + i) );
1405 else
1407 sockaddr_in_to_WS_storage( addr, (struct sockaddr_in *)(buf + i) );
1409 if (++addr >= servers + num) break;
1412 HeapFree( GetProcessHeap(), 0, buf );
1413 return found;
1415 #else
1417 static int get_dns_servers( SOCKADDR_STORAGE *servers, int num, BOOL ip4_only )
1419 FIXME("Unimplemented on this system\n");
1420 return 0;
1422 #endif
1424 static ULONG get_dns_server_addresses(PIP_ADAPTER_DNS_SERVER_ADDRESS address, ULONG *len)
1426 int num = get_dns_servers( NULL, 0, FALSE );
1427 DWORD size;
1429 size = num * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR_STORAGE));
1430 if (!address || *len < size)
1432 *len = size;
1433 return ERROR_BUFFER_OVERFLOW;
1435 *len = size;
1436 if (num > 0)
1438 PIP_ADAPTER_DNS_SERVER_ADDRESS addr = address;
1439 SOCKADDR_STORAGE *sock_addrs = (SOCKADDR_STORAGE *)(address + num);
1440 int i;
1442 get_dns_servers( sock_addrs, num, FALSE );
1444 for (i = 0; i < num; i++, addr = addr->Next)
1446 addr->u.s.Length = sizeof(*addr);
1447 if (sock_addrs[i].ss_family == WS_AF_INET6)
1448 addr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6);
1449 else
1450 addr->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
1451 addr->Address.lpSockaddr = (SOCKADDR *)(sock_addrs + i);
1452 if (i == num - 1)
1453 addr->Next = NULL;
1454 else
1455 addr->Next = addr + 1;
1458 return ERROR_SUCCESS;
1461 #ifdef HAVE_STRUCT___RES_STATE
1462 static BOOL is_ip_address_string(const char *str)
1464 struct in_addr in;
1465 int ret;
1467 ret = inet_aton(str, &in);
1468 return ret != 0;
1470 #endif
1472 static ULONG get_dns_suffix(WCHAR *suffix, ULONG *len)
1474 ULONG size;
1475 const char *found_suffix = "";
1476 /* Always return a NULL-terminated string, even if it's empty. */
1478 #ifdef HAVE_STRUCT___RES_STATE
1480 ULONG i;
1481 initialise_resolver();
1482 for (i = 0; !*found_suffix && i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
1484 /* This uses a heuristic to select a DNS suffix:
1485 * the first, non-IP address string is selected.
1487 if (!is_ip_address_string(_res.dnsrch[i]))
1488 found_suffix = _res.dnsrch[i];
1491 #endif
1493 size = MultiByteToWideChar( CP_UNIXCP, 0, found_suffix, -1, NULL, 0 ) * sizeof(WCHAR);
1494 if (!suffix || *len < size)
1496 *len = size;
1497 return ERROR_BUFFER_OVERFLOW;
1499 *len = MultiByteToWideChar( CP_UNIXCP, 0, found_suffix, -1, suffix, *len / sizeof(WCHAR) ) * sizeof(WCHAR);
1500 return ERROR_SUCCESS;
1503 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG family, ULONG flags, PVOID reserved,
1504 PIP_ADAPTER_ADDRESSES aa, PULONG buflen)
1506 InterfaceIndexTable *table;
1507 ULONG i, size, dns_server_size = 0, dns_suffix_size, total_size, ret = ERROR_NO_DATA;
1509 TRACE("(%d, %08x, %p, %p, %p)\n", family, flags, reserved, aa, buflen);
1511 if (!buflen) return ERROR_INVALID_PARAMETER;
1513 get_interface_indices( FALSE, &table );
1514 if (!table || !table->numIndexes)
1516 HeapFree(GetProcessHeap(), 0, table);
1517 return ERROR_NO_DATA;
1519 total_size = 0;
1520 for (i = 0; i < table->numIndexes; i++)
1522 size = 0;
1523 if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], NULL, &size)))
1525 HeapFree(GetProcessHeap(), 0, table);
1526 return ret;
1528 total_size += size;
1530 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1532 /* Since DNS servers aren't really per adapter, get enough space for a
1533 * single copy of them.
1535 get_dns_server_addresses(NULL, &dns_server_size);
1536 total_size += dns_server_size;
1538 /* Since DNS suffix also isn't really per adapter, get enough space for a
1539 * single copy of it.
1541 get_dns_suffix(NULL, &dns_suffix_size);
1542 total_size += dns_suffix_size;
1543 if (aa && *buflen >= total_size)
1545 ULONG bytes_left = size = total_size;
1546 PIP_ADAPTER_ADDRESSES first_aa = aa;
1547 PIP_ADAPTER_DNS_SERVER_ADDRESS firstDns;
1548 WCHAR *dnsSuffix;
1550 for (i = 0; i < table->numIndexes; i++)
1552 if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], aa, &size)))
1554 HeapFree(GetProcessHeap(), 0, table);
1555 return ret;
1557 if (i < table->numIndexes - 1)
1559 aa->Next = (IP_ADAPTER_ADDRESSES *)((char *)aa + size);
1560 aa = aa->Next;
1561 size = bytes_left -= size;
1564 if (dns_server_size)
1566 firstDns = (PIP_ADAPTER_DNS_SERVER_ADDRESS)((BYTE *)first_aa + total_size - dns_server_size - dns_suffix_size);
1567 get_dns_server_addresses(firstDns, &dns_server_size);
1568 for (aa = first_aa; aa; aa = aa->Next)
1570 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1571 aa->FirstDnsServerAddress = firstDns;
1574 aa = first_aa;
1575 dnsSuffix = (WCHAR *)((BYTE *)aa + total_size - dns_suffix_size);
1576 get_dns_suffix(dnsSuffix, &dns_suffix_size);
1577 for (; aa; aa = aa->Next)
1579 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1580 aa->DnsSuffix = dnsSuffix;
1581 else
1582 aa->DnsSuffix = dnsSuffix + dns_suffix_size / sizeof(WCHAR) - 1;
1584 ret = ERROR_SUCCESS;
1586 else
1588 ret = ERROR_BUFFER_OVERFLOW;
1589 *buflen = total_size;
1592 TRACE("num adapters %u\n", table->numIndexes);
1593 HeapFree(GetProcessHeap(), 0, table);
1594 return ret;
1597 /******************************************************************
1598 * GetBestInterface (IPHLPAPI.@)
1600 * Get the interface, with the best route for the given IP address.
1602 * PARAMS
1603 * dwDestAddr [In] IP address to search the interface for
1604 * pdwBestIfIndex [Out] found best interface
1606 * RETURNS
1607 * Success: NO_ERROR
1608 * Failure: error code from winerror.h
1610 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1612 struct WS_sockaddr_in sa_in;
1613 memset(&sa_in, 0, sizeof(sa_in));
1614 sa_in.sin_family = WS_AF_INET;
1615 sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1616 return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
1619 /******************************************************************
1620 * GetBestInterfaceEx (IPHLPAPI.@)
1622 * Get the interface, with the best route for the given IP address.
1624 * PARAMS
1625 * dwDestAddr [In] IP address to search the interface for
1626 * pdwBestIfIndex [Out] found best interface
1628 * RETURNS
1629 * Success: NO_ERROR
1630 * Failure: error code from winerror.h
1632 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1634 DWORD ret;
1636 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1637 if (!pDestAddr || !pdwBestIfIndex)
1638 ret = ERROR_INVALID_PARAMETER;
1639 else {
1640 MIB_IPFORWARDROW ipRow;
1642 if (pDestAddr->sa_family == WS_AF_INET) {
1643 ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1644 if (ret == ERROR_SUCCESS)
1645 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1646 } else {
1647 FIXME("address family %d not supported\n", pDestAddr->sa_family);
1648 ret = ERROR_NOT_SUPPORTED;
1651 TRACE("returning %d\n", ret);
1652 return ret;
1656 /******************************************************************
1657 * GetBestRoute (IPHLPAPI.@)
1659 * Get the best route for the given IP address.
1661 * PARAMS
1662 * dwDestAddr [In] IP address to search the best route for
1663 * dwSourceAddr [In] optional source IP address
1664 * pBestRoute [Out] found best route
1666 * RETURNS
1667 * Success: NO_ERROR
1668 * Failure: error code from winerror.h
1670 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1672 PMIB_IPFORWARDTABLE table;
1673 DWORD ret;
1675 TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
1676 dwSourceAddr, pBestRoute);
1677 if (!pBestRoute)
1678 return ERROR_INVALID_PARAMETER;
1680 ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1681 if (!ret) {
1682 DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1684 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1685 if (table->table[ndx].u1.ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1686 (dwDestAddr & table->table[ndx].dwForwardMask) ==
1687 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1688 DWORD numShifts, mask;
1690 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1691 mask && mask & 1; mask >>= 1, numShifts++)
1693 if (numShifts > matchedBits) {
1694 matchedBits = numShifts;
1695 matchedNdx = ndx;
1697 else if (!matchedBits) {
1698 matchedNdx = ndx;
1702 if (matchedNdx < table->dwNumEntries) {
1703 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1704 ret = ERROR_SUCCESS;
1706 else {
1707 /* No route matches, which can happen if there's no default route. */
1708 ret = ERROR_HOST_UNREACHABLE;
1710 HeapFree(GetProcessHeap(), 0, table);
1712 TRACE("returning %d\n", ret);
1713 return ret;
1717 /******************************************************************
1718 * GetFriendlyIfIndex (IPHLPAPI.@)
1720 * Get a "friendly" version of IfIndex, which is one that doesn't
1721 * have the top byte set. Doesn't validate whether IfIndex is a valid
1722 * adapter index.
1724 * PARAMS
1725 * IfIndex [In] interface index to get the friendly one for
1727 * RETURNS
1728 * A friendly version of IfIndex.
1730 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1732 /* windows doesn't validate these, either, just makes sure the top byte is
1733 cleared. I assume my ifenum module never gives an index with the top
1734 byte set. */
1735 TRACE("returning %d\n", IfIndex);
1736 return IfIndex;
1739 static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src );
1741 static void if_row_fill( MIB_IFROW *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1742 struct nsi_ndis_ifinfo_static *stat )
1744 if_counted_string_copy( row->wszName, ARRAY_SIZE(row->wszName), &rw->alias );
1745 row->dwIndex = stat->if_index;
1746 row->dwType = stat->type;
1747 row->dwMtu = dyn->mtu;
1748 row->dwSpeed = dyn->rcv_speed;
1749 row->dwPhysAddrLen = rw->phys_addr.Length;
1750 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
1751 memcpy( row->bPhysAddr, rw->phys_addr.Address, row->dwPhysAddrLen );
1752 row->dwAdminStatus = rw->admin_status;
1753 row->dwOperStatus = (dyn->oper_status == IfOperStatusUp) ? MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_NON_OPERATIONAL;
1754 row->dwLastChange = 0;
1755 row->dwInOctets = dyn->in_octets;
1756 row->dwInUcastPkts = dyn->in_ucast_pkts;
1757 row->dwInNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1758 row->dwInDiscards = dyn->in_discards;
1759 row->dwInErrors = dyn->in_errors;
1760 row->dwInUnknownProtos = 0;
1761 row->dwOutOctets = dyn->out_octets;
1762 row->dwOutUcastPkts = dyn->out_ucast_pkts;
1763 row->dwOutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1764 row->dwOutDiscards = dyn->out_discards;
1765 row->dwOutErrors = dyn->out_errors;
1766 row->dwOutQLen = 0;
1767 row->dwDescrLen = WideCharToMultiByte( CP_ACP, 0, stat->descr.String, stat->descr.Length / sizeof(WCHAR),
1768 (char *)row->bDescr, sizeof(row->bDescr) - 1, NULL, NULL );
1769 row->bDescr[row->dwDescrLen] = '\0';
1772 /******************************************************************
1773 * GetIfEntry (IPHLPAPI.@)
1775 * Get information about an interface.
1777 * PARAMS
1778 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1779 * Out: interface information
1781 * RETURNS
1782 * Success: NO_ERROR
1783 * Failure: error code from winerror.h
1785 DWORD WINAPI GetIfEntry( MIB_IFROW *row )
1787 struct nsi_ndis_ifinfo_rw rw;
1788 struct nsi_ndis_ifinfo_dynamic dyn;
1789 struct nsi_ndis_ifinfo_static stat;
1790 NET_LUID luid;
1791 DWORD err;
1793 TRACE( "row %p\n", row );
1794 if (!row) return ERROR_INVALID_PARAMETER;
1796 err = ConvertInterfaceIndexToLuid( row->dwIndex, &luid );
1797 if (err) return err;
1799 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1800 &luid, sizeof(luid), &rw, sizeof(rw),
1801 &dyn, sizeof(dyn), &stat, sizeof(stat) );
1802 if (!err) if_row_fill( row, &rw, &dyn, &stat );
1803 return err;
1806 static int ifrow_cmp( const void *a, const void *b )
1808 return ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1811 /******************************************************************
1812 * GetIfTable (IPHLPAPI.@)
1814 * Get a table of local interfaces.
1816 * PARAMS
1817 * table [Out] buffer for local interfaces table
1818 * size [In/Out] length of output buffer
1819 * sort [In] whether to sort the table
1821 * RETURNS
1822 * Success: NO_ERROR
1823 * Failure: error code from winerror.h
1825 * NOTES
1826 * If size is less than required, the function will return
1827 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1828 * size.
1829 * If sort is true, the returned table will be sorted by interface index.
1831 DWORD WINAPI GetIfTable( MIB_IFTABLE *table, ULONG *size, BOOL sort )
1833 DWORD i, count, needed, err;
1834 NET_LUID *keys;
1835 struct nsi_ndis_ifinfo_rw *rw;
1836 struct nsi_ndis_ifinfo_dynamic *dyn;
1837 struct nsi_ndis_ifinfo_static *stat;
1839 if (!size) return ERROR_INVALID_PARAMETER;
1841 /* While this could be implemented on top of GetIfTable2(), it would require
1842 an additional copy of the data */
1843 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1844 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1845 (void **)&stat, sizeof(*stat), &count, 0 );
1846 if (err) return err;
1848 needed = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1850 if (!table || *size < needed)
1852 *size = needed;
1853 err = ERROR_INSUFFICIENT_BUFFER;
1854 goto err;
1857 table->dwNumEntries = count;
1858 for (i = 0; i < count; i++)
1860 MIB_IFROW *row = table->table + i;
1862 if_row_fill( row, rw + i, dyn + i, stat + i );
1865 if (sort) qsort( table->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1867 err:
1868 NsiFreeTable( keys, rw, dyn, stat );
1869 return err;
1872 /******************************************************************
1873 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1875 * Get table of local interfaces.
1876 * Like GetIfTable(), but allocate the returned table from heap.
1878 * PARAMS
1879 * table [Out] pointer into which the MIB_IFTABLE is
1880 * allocated and returned.
1881 * sort [In] whether to sort the table
1882 * heap [In] heap from which the table is allocated
1883 * flags [In] flags to HeapAlloc
1885 * RETURNS
1886 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1887 * GetIfTable() returns otherwise.
1889 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1891 DWORD i, count, size, err;
1892 NET_LUID *keys;
1893 struct nsi_ndis_ifinfo_rw *rw;
1894 struct nsi_ndis_ifinfo_dynamic *dyn;
1895 struct nsi_ndis_ifinfo_static *stat;
1897 if (!table) return ERROR_INVALID_PARAMETER;
1899 /* While this could be implemented on top of GetIfTable(), it would require
1900 an additional call to retrieve the size */
1901 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1902 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1903 (void **)&stat, sizeof(*stat), &count, 0 );
1904 if (err) return err;
1906 size = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1907 *table = HeapAlloc( heap, flags, size );
1908 if (!*table)
1910 err = ERROR_NOT_ENOUGH_MEMORY;
1911 goto err;
1914 (*table)->dwNumEntries = count;
1915 for (i = 0; i < count; i++)
1917 MIB_IFROW *row = (*table)->table + i;
1919 if_row_fill( row, rw + i, dyn + i, stat + i );
1921 if (sort) qsort( (*table)->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1923 err:
1924 NsiFreeTable( keys, rw, dyn, stat );
1925 return err;
1928 static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
1930 unsigned int copy = src->Length;
1932 if (copy >= len * sizeof(WCHAR)) copy = 0;
1933 memcpy( dst, src->String, copy );
1934 memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
1937 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1938 struct nsi_ndis_ifinfo_static *stat )
1940 row->InterfaceIndex = stat->if_index;
1941 row->InterfaceGuid = stat->if_guid;
1942 if_counted_string_copy( row->Alias, ARRAY_SIZE(row->Alias), &rw->alias );
1943 if_counted_string_copy( row->Description, ARRAY_SIZE(row->Description), &stat->descr );
1944 row->PhysicalAddressLength = rw->phys_addr.Length;
1945 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress)) row->PhysicalAddressLength = 0;
1946 memcpy( row->PhysicalAddress, rw->phys_addr.Address, row->PhysicalAddressLength );
1947 memcpy( row->PermanentPhysicalAddress, stat->perm_phys_addr.Address, row->PhysicalAddressLength );
1948 row->Mtu = dyn->mtu;
1949 row->Type = stat->type;
1950 row->TunnelType = TUNNEL_TYPE_NONE; /* fixme */
1951 row->MediaType = stat->media_type;
1952 row->PhysicalMediumType = stat->phys_medium_type;
1953 row->AccessType = stat->access_type;
1954 row->DirectionType = NET_IF_DIRECTION_SENDRECEIVE; /* fixme */
1955 row->InterfaceAndOperStatusFlags.HardwareInterface = stat->flags.hw;
1956 row->InterfaceAndOperStatusFlags.FilterInterface = stat->flags.filter;
1957 row->InterfaceAndOperStatusFlags.ConnectorPresent = !!stat->conn_present;
1958 row->InterfaceAndOperStatusFlags.NotAuthenticated = 0; /* fixme */
1959 row->InterfaceAndOperStatusFlags.NotMediaConnected = dyn->flags.not_media_conn;
1960 row->InterfaceAndOperStatusFlags.Paused = 0; /* fixme */
1961 row->InterfaceAndOperStatusFlags.LowPower = 0; /* fixme */
1962 row->InterfaceAndOperStatusFlags.EndPointInterface = 0; /* fixme */
1963 row->OperStatus = dyn->oper_status;
1964 row->AdminStatus = rw->admin_status;
1965 row->MediaConnectState = dyn->media_conn_state;
1966 row->NetworkGuid = rw->network_guid;
1967 row->ConnectionType = stat->conn_type;
1968 row->TransmitLinkSpeed = dyn->xmit_speed;
1969 row->ReceiveLinkSpeed = dyn->rcv_speed;
1970 row->InOctets = dyn->in_octets;
1971 row->InUcastPkts = dyn->in_ucast_pkts;
1972 row->InNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1973 row->InDiscards = dyn->in_discards;
1974 row->InErrors = dyn->in_errors;
1975 row->InUnknownProtos = 0; /* fixme */
1976 row->InUcastOctets = dyn->in_ucast_octs;
1977 row->InMulticastOctets = dyn->in_mcast_octs;
1978 row->InBroadcastOctets = dyn->in_bcast_octs;
1979 row->OutOctets = dyn->out_octets;
1980 row->OutUcastPkts = dyn->out_ucast_pkts;
1981 row->OutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1982 row->OutDiscards = dyn->out_discards;
1983 row->OutErrors = dyn->out_errors;
1984 row->OutUcastOctets = dyn->out_ucast_octs;
1985 row->OutMulticastOctets = dyn->out_mcast_octs;
1986 row->OutBroadcastOctets = dyn->out_bcast_octs;
1987 row->OutQLen = 0; /* fixme */
1990 /******************************************************************
1991 * GetIfEntry2Ex (IPHLPAPI.@)
1993 DWORD WINAPI GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_ROW2 *row )
1995 DWORD err;
1996 struct nsi_ndis_ifinfo_rw rw;
1997 struct nsi_ndis_ifinfo_dynamic dyn;
1998 struct nsi_ndis_ifinfo_static stat;
2000 TRACE( "(%d, %p)\n", level, row );
2002 if (level != MibIfTableNormal) FIXME( "level %u not fully supported\n", level );
2003 if (!row) return ERROR_INVALID_PARAMETER;
2005 if (!row->InterfaceLuid.Value)
2007 if (!row->InterfaceIndex) return ERROR_INVALID_PARAMETER;
2008 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
2009 if (err) return err;
2012 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
2013 &row->InterfaceLuid, sizeof(row->InterfaceLuid),
2014 &rw, sizeof(rw), &dyn, sizeof(dyn), &stat, sizeof(stat) );
2015 if (!err) if_row2_fill( row, &rw, &dyn, &stat );
2016 return err;
2019 /******************************************************************
2020 * GetIfEntry2 (IPHLPAPI.@)
2022 DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row )
2024 return GetIfEntry2Ex( MibIfTableNormal, row );
2027 /******************************************************************
2028 * GetIfTable2Ex (IPHLPAPI.@)
2030 DWORD WINAPI GetIfTable2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_TABLE2 **table )
2032 DWORD i, count, size, err;
2033 NET_LUID *keys;
2034 struct nsi_ndis_ifinfo_rw *rw;
2035 struct nsi_ndis_ifinfo_dynamic *dyn;
2036 struct nsi_ndis_ifinfo_static *stat;
2038 TRACE( "level %u, table %p\n", level, table );
2040 if (!table || level > MibIfTableNormalWithoutStatistics)
2041 return ERROR_INVALID_PARAMETER;
2043 if (level != MibIfTableNormal)
2044 FIXME("level %u not fully supported\n", level);
2046 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
2047 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2048 (void **)&stat, sizeof(*stat), &count, 0 );
2049 if (err) return err;
2051 size = FIELD_OFFSET( MIB_IF_TABLE2, Table[count] );
2053 if (!(*table = heap_alloc_zero( size )))
2055 err = ERROR_OUTOFMEMORY;
2056 goto err;
2059 (*table)->NumEntries = count;
2060 for (i = 0; i < count; i++)
2062 MIB_IF_ROW2 *row = (*table)->Table + i;
2064 row->InterfaceLuid.Value = keys[i].Value;
2065 if_row2_fill( row, rw + i, dyn + i, stat + i );
2067 err:
2068 NsiFreeTable( keys, rw, dyn, stat );
2069 return err;
2072 /******************************************************************
2073 * GetIfTable2 (IPHLPAPI.@)
2075 DWORD WINAPI GetIfTable2( MIB_IF_TABLE2 **table )
2077 TRACE( "table %p\n", table );
2078 return GetIfTable2Ex( MibIfTableNormal, table );
2081 /******************************************************************
2082 * GetInterfaceInfo (IPHLPAPI.@)
2084 * Get a list of network interface adapters.
2086 * PARAMS
2087 * pIfTable [Out] buffer for interface adapters
2088 * dwOutBufLen [Out] if buffer is too small, returns required size
2090 * RETURNS
2091 * Success: NO_ERROR
2092 * Failure: error code from winerror.h
2094 * BUGS
2095 * MSDN states this should return non-loopback interfaces only.
2097 DWORD WINAPI GetInterfaceInfo( IP_INTERFACE_INFO *table, ULONG *size )
2099 MIB_IFTABLE *if_table;
2100 DWORD err, needed, i;
2102 TRACE("table %p, size %p\n", table, size );
2103 if (!size) return ERROR_INVALID_PARAMETER;
2105 err = AllocateAndGetIfTableFromStack( &if_table, 0, GetProcessHeap(), 0 );
2106 if (err) return err;
2108 needed = FIELD_OFFSET(IP_INTERFACE_INFO, Adapter[if_table->dwNumEntries]);
2109 if (!table || *size < needed)
2111 *size = needed;
2112 heap_free( if_table );
2113 return ERROR_INSUFFICIENT_BUFFER;
2116 table->NumAdapters = if_table->dwNumEntries;
2117 for (i = 0; i < if_table->dwNumEntries; i++)
2119 table->Adapter[i].Index = if_table->table[i].dwIndex;
2120 strcpyW( table->Adapter[i].Name, if_table->table[i].wszName );
2122 heap_free( if_table );
2123 return ERROR_SUCCESS;
2127 /******************************************************************
2128 * GetIpAddrTable (IPHLPAPI.@)
2130 * Get interface-to-IP address mapping table.
2132 * PARAMS
2133 * pIpAddrTable [Out] buffer for mapping table
2134 * pdwSize [In/Out] length of output buffer
2135 * bOrder [In] whether to sort the table
2137 * RETURNS
2138 * Success: NO_ERROR
2139 * Failure: error code from winerror.h
2141 * NOTES
2142 * If pdwSize is less than required, the function will return
2143 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
2144 * size.
2145 * If bOrder is true, the returned table will be sorted by the next hop and
2146 * an assortment of arbitrary parameters.
2148 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
2150 DWORD ret;
2152 TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
2153 (DWORD)bOrder);
2154 if (!pdwSize)
2155 ret = ERROR_INVALID_PARAMETER;
2156 else {
2157 PMIB_IPADDRTABLE table;
2159 ret = getIPAddrTable(&table, GetProcessHeap(), 0);
2160 if (ret == NO_ERROR)
2162 ULONG size = FIELD_OFFSET(MIB_IPADDRTABLE, table[table->dwNumEntries]);
2164 if (!pIpAddrTable || *pdwSize < size) {
2165 *pdwSize = size;
2166 ret = ERROR_INSUFFICIENT_BUFFER;
2168 else {
2169 *pdwSize = size;
2170 memcpy(pIpAddrTable, table, size);
2171 /* sort by numeric IP value */
2172 if (bOrder)
2173 qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
2174 sizeof(MIB_IPADDRROW), IpAddrTableNumericSorter);
2175 /* sort ensuring loopback interfaces are in the end */
2176 else
2177 qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
2178 sizeof(MIB_IPADDRROW), IpAddrTableLoopbackSorter);
2179 ret = NO_ERROR;
2181 HeapFree(GetProcessHeap(), 0, table);
2184 TRACE("returning %d\n", ret);
2185 return ret;
2189 /******************************************************************
2190 * GetIpForwardTable (IPHLPAPI.@)
2192 * Get the route table.
2194 * PARAMS
2195 * pIpForwardTable [Out] buffer for route table
2196 * pdwSize [In/Out] length of output buffer
2197 * bOrder [In] whether to sort the table
2199 * RETURNS
2200 * Success: NO_ERROR
2201 * Failure: error code from winerror.h
2203 * NOTES
2204 * If pdwSize is less than required, the function will return
2205 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
2206 * size.
2207 * If bOrder is true, the returned table will be sorted by the next hop and
2208 * an assortment of arbitrary parameters.
2210 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
2212 DWORD ret;
2213 PMIB_IPFORWARDTABLE table;
2215 TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
2217 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2219 ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
2220 if (!ret) {
2221 DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
2222 if (!pIpForwardTable || *pdwSize < size) {
2223 *pdwSize = size;
2224 ret = ERROR_INSUFFICIENT_BUFFER;
2226 else {
2227 *pdwSize = size;
2228 memcpy(pIpForwardTable, table, size);
2230 HeapFree(GetProcessHeap(), 0, table);
2232 TRACE("returning %d\n", ret);
2233 return ret;
2237 /******************************************************************
2238 * GetIpNetTable (IPHLPAPI.@)
2240 * Get the IP-to-physical address mapping table.
2242 * PARAMS
2243 * pIpNetTable [Out] buffer for mapping table
2244 * pdwSize [In/Out] length of output buffer
2245 * bOrder [In] whether to sort the table
2247 * RETURNS
2248 * Success: NO_ERROR
2249 * Failure: error code from winerror.h
2251 * NOTES
2252 * If pdwSize is less than required, the function will return
2253 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
2254 * size.
2255 * If bOrder is true, the returned table will be sorted by IP address.
2257 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
2259 DWORD ret;
2260 PMIB_IPNETTABLE table;
2262 TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder);
2264 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2266 ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
2267 if (!ret) {
2268 DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] );
2269 if (!pIpNetTable || *pdwSize < size) {
2270 *pdwSize = size;
2271 ret = ERROR_INSUFFICIENT_BUFFER;
2273 else {
2274 *pdwSize = size;
2275 memcpy(pIpNetTable, table, size);
2277 HeapFree(GetProcessHeap(), 0, table);
2279 TRACE("returning %d\n", ret);
2280 return ret;
2283 /* Gets the DNS server list into the list beginning at list. Assumes that
2284 * a single server address may be placed at list if *len is at least
2285 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2286 * and assumes that all remaining DNS servers are contiguously located
2287 * beginning at firstDynamic. On input, *len is assumed to be the total number
2288 * of bytes available for all DNS servers, and is ignored if list is NULL.
2289 * On return, *len is set to the total number of bytes required for all DNS
2290 * servers.
2291 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2292 * ERROR_SUCCESS otherwise.
2294 static DWORD get_dns_server_list(PIP_ADDR_STRING list,
2295 PIP_ADDR_STRING firstDynamic, DWORD *len)
2297 DWORD size;
2298 int num = get_dns_servers( NULL, 0, TRUE );
2300 size = num * sizeof(IP_ADDR_STRING);
2301 if (!list || *len < size) {
2302 *len = size;
2303 return ERROR_BUFFER_OVERFLOW;
2305 *len = size;
2306 if (num > 0) {
2307 PIP_ADDR_STRING ptr;
2308 int i;
2309 SOCKADDR_STORAGE *addr = HeapAlloc( GetProcessHeap(), 0, num * sizeof(SOCKADDR_STORAGE) );
2311 get_dns_servers( addr, num, TRUE );
2313 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next) {
2314 RtlIpv4AddressToStringA((IN_ADDR *)&((struct sockaddr_in *)(addr + i))->sin_addr.s_addr,
2315 ptr->IpAddress.String);
2316 if (i == num - 1)
2317 ptr->Next = NULL;
2318 else if (i == 0)
2319 ptr->Next = firstDynamic;
2320 else
2321 ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
2323 HeapFree( GetProcessHeap(), 0, addr );
2325 return ERROR_SUCCESS;
2328 /******************************************************************
2329 * GetNetworkParams (IPHLPAPI.@)
2331 * Get the network parameters for the local computer.
2333 * PARAMS
2334 * pFixedInfo [Out] buffer for network parameters
2335 * pOutBufLen [In/Out] length of output buffer
2337 * RETURNS
2338 * Success: NO_ERROR
2339 * Failure: error code from winerror.h
2341 * NOTES
2342 * If pOutBufLen is less than required, the function will return
2343 * ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
2344 * size.
2346 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
2348 DWORD ret, size, serverListSize;
2349 LONG regReturn;
2350 HKEY hKey;
2352 TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
2353 if (!pOutBufLen)
2354 return ERROR_INVALID_PARAMETER;
2356 get_dns_server_list(NULL, NULL, &serverListSize);
2357 size = sizeof(FIXED_INFO) + serverListSize - sizeof(IP_ADDR_STRING);
2358 if (!pFixedInfo || *pOutBufLen < size) {
2359 *pOutBufLen = size;
2360 return ERROR_BUFFER_OVERFLOW;
2363 memset(pFixedInfo, 0, size);
2364 size = sizeof(pFixedInfo->HostName);
2365 GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
2366 size = sizeof(pFixedInfo->DomainName);
2367 GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
2368 get_dns_server_list(&pFixedInfo->DnsServerList,
2369 (PIP_ADDR_STRING)((BYTE *)pFixedInfo + sizeof(FIXED_INFO)),
2370 &serverListSize);
2371 /* Assume the first DNS server in the list is the "current" DNS server: */
2372 pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList;
2373 pFixedInfo->NodeType = HYBRID_NODETYPE;
2374 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2375 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2376 if (regReturn != ERROR_SUCCESS)
2377 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2378 "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2379 &hKey);
2380 if (regReturn == ERROR_SUCCESS)
2382 DWORD size = sizeof(pFixedInfo->ScopeId);
2384 RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
2385 RegCloseKey(hKey);
2388 /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2389 I suppose could also check for a listener on port 53 to set EnableDns */
2390 ret = NO_ERROR;
2391 TRACE("returning %d\n", ret);
2392 return ret;
2396 /******************************************************************
2397 * GetNumberOfInterfaces (IPHLPAPI.@)
2399 * Get the number of interfaces.
2401 * PARAMS
2402 * pdwNumIf [Out] number of interfaces
2404 * RETURNS
2405 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2407 DWORD WINAPI GetNumberOfInterfaces( DWORD *count )
2409 DWORD err, num;
2411 TRACE( "count %p\n", count );
2412 if (!count) return ERROR_INVALID_PARAMETER;
2414 err = NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0,
2415 NULL, 0, NULL, 0, NULL, 0, &num );
2416 *count = err ? 0 : num;
2417 return err;
2420 /******************************************************************
2421 * GetPerAdapterInfo (IPHLPAPI.@)
2423 * Get information about an adapter corresponding to an interface.
2425 * PARAMS
2426 * IfIndex [In] interface info
2427 * pPerAdapterInfo [Out] buffer for per adapter info
2428 * pOutBufLen [In/Out] length of output buffer
2430 * RETURNS
2431 * Success: NO_ERROR
2432 * Failure: error code from winerror.h
2434 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2436 ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO), serverListSize = 0;
2437 DWORD ret = NO_ERROR;
2439 TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex, pPerAdapterInfo, pOutBufLen);
2441 if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
2443 if (!isIfIndexLoopback(IfIndex)) {
2444 get_dns_server_list(NULL, NULL, &serverListSize);
2445 if (serverListSize > sizeof(IP_ADDR_STRING))
2446 bytesNeeded += serverListSize - sizeof(IP_ADDR_STRING);
2448 if (!pPerAdapterInfo || *pOutBufLen < bytesNeeded)
2450 *pOutBufLen = bytesNeeded;
2451 return ERROR_BUFFER_OVERFLOW;
2454 memset(pPerAdapterInfo, 0, bytesNeeded);
2455 if (!isIfIndexLoopback(IfIndex)) {
2456 ret = get_dns_server_list(&pPerAdapterInfo->DnsServerList,
2457 (PIP_ADDR_STRING)((PBYTE)pPerAdapterInfo + sizeof(IP_PER_ADAPTER_INFO)),
2458 &serverListSize);
2459 /* Assume the first DNS server in the list is the "current" DNS server: */
2460 pPerAdapterInfo->CurrentDnsServer = &pPerAdapterInfo->DnsServerList;
2462 return ret;
2466 /******************************************************************
2467 * GetRTTAndHopCount (IPHLPAPI.@)
2469 * Get round-trip time (RTT) and hop count.
2471 * PARAMS
2473 * DestIpAddress [In] destination address to get the info for
2474 * HopCount [Out] retrieved hop count
2475 * MaxHops [In] maximum hops to search for the destination
2476 * RTT [Out] RTT in milliseconds
2478 * RETURNS
2479 * Success: TRUE
2480 * Failure: FALSE
2482 * FIXME
2483 * Stub, returns FALSE.
2485 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2487 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2488 DestIpAddress, HopCount, MaxHops, RTT);
2489 return FALSE;
2493 /******************************************************************
2494 * GetTcpTable (IPHLPAPI.@)
2496 * Get the table of active TCP connections.
2498 * PARAMS
2499 * pTcpTable [Out] buffer for TCP connections table
2500 * pdwSize [In/Out] length of output buffer
2501 * bOrder [In] whether to order the table
2503 * RETURNS
2504 * Success: NO_ERROR
2505 * Failure: error code from winerror.h
2507 * NOTES
2508 * If pdwSize is less than required, the function will return
2509 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2510 * the required byte size.
2511 * If bOrder is true, the returned table will be sorted, first by
2512 * local address and port number, then by remote address and port
2513 * number.
2515 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2517 TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
2518 return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, WS_AF_INET, TCP_TABLE_BASIC_ALL, 0);
2521 /******************************************************************
2522 * GetExtendedTcpTable (IPHLPAPI.@)
2524 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
2525 ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
2527 DWORD ret, size;
2528 void *table;
2530 TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2531 pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2533 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2535 if (TableClass >= TCP_TABLE_OWNER_MODULE_LISTENER)
2536 FIXME("module classes not fully supported\n");
2538 switch (ulAf)
2540 case WS_AF_INET:
2541 ret = build_tcp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2542 break;
2544 case WS_AF_INET6:
2545 ret = build_tcp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2546 break;
2548 default:
2549 FIXME("ulAf = %u not supported\n", ulAf);
2550 ret = ERROR_NOT_SUPPORTED;
2553 if (ret)
2554 return ret;
2556 if (!pTcpTable || *pdwSize < size)
2558 *pdwSize = size;
2559 ret = ERROR_INSUFFICIENT_BUFFER;
2561 else
2563 *pdwSize = size;
2564 memcpy(pTcpTable, table, size);
2566 HeapFree(GetProcessHeap(), 0, table);
2567 return ret;
2570 /******************************************************************
2571 * GetUdpTable (IPHLPAPI.@)
2573 * Get a table of active UDP connections.
2575 * PARAMS
2576 * pUdpTable [Out] buffer for UDP connections table
2577 * pdwSize [In/Out] length of output buffer
2578 * bOrder [In] whether to order the table
2580 * RETURNS
2581 * Success: NO_ERROR
2582 * Failure: error code from winerror.h
2584 * NOTES
2585 * If pdwSize is less than required, the function will return
2586 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
2587 * required byte size.
2588 * If bOrder is true, the returned table will be sorted, first by
2589 * local address, then by local port number.
2591 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2593 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET, UDP_TABLE_BASIC, 0);
2596 /******************************************************************
2597 * GetUdp6Table (IPHLPAPI.@)
2599 DWORD WINAPI GetUdp6Table(PMIB_UDP6TABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2601 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET6, UDP_TABLE_BASIC, 0);
2604 /******************************************************************
2605 * GetExtendedUdpTable (IPHLPAPI.@)
2607 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
2608 ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
2610 DWORD ret, size;
2611 void *table;
2613 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2614 pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2616 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2618 if (TableClass == UDP_TABLE_OWNER_MODULE)
2619 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
2621 switch (ulAf)
2623 case WS_AF_INET:
2624 ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2625 break;
2627 case WS_AF_INET6:
2628 ret = build_udp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2629 break;
2631 default:
2632 FIXME("ulAf = %u not supported\n", ulAf);
2633 ret = ERROR_NOT_SUPPORTED;
2636 if (ret)
2637 return ret;
2639 if (!pUdpTable || *pdwSize < size)
2641 *pdwSize = size;
2642 ret = ERROR_INSUFFICIENT_BUFFER;
2644 else
2646 *pdwSize = size;
2647 memcpy(pUdpTable, table, size);
2649 HeapFree(GetProcessHeap(), 0, table);
2650 return ret;
2653 DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW *row)
2655 IP_ADAPTER_ADDRESSES *aa, *ptr;
2656 ULONG size = 0;
2657 DWORD ret;
2659 TRACE("%p\n", row);
2661 if (!row)
2662 return ERROR_INVALID_PARAMETER;
2664 ret = GetAdaptersAddresses(row->Address.si_family, 0, NULL, NULL, &size);
2665 if (ret != ERROR_BUFFER_OVERFLOW)
2666 return ret;
2667 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, size)))
2668 return ERROR_OUTOFMEMORY;
2669 if ((ret = GetAdaptersAddresses(row->Address.si_family, 0, NULL, ptr, &size)))
2671 HeapFree(GetProcessHeap(), 0, ptr);
2672 return ret;
2675 ret = ERROR_FILE_NOT_FOUND;
2676 for (aa = ptr; aa; aa = aa->Next)
2678 IP_ADAPTER_UNICAST_ADDRESS *ua;
2680 if (aa->u.s.IfIndex != row->InterfaceIndex &&
2681 memcmp(&aa->Luid, &row->InterfaceLuid, sizeof(row->InterfaceLuid)))
2682 continue;
2683 ret = ERROR_NOT_FOUND;
2685 ua = aa->FirstUnicastAddress;
2686 while (ua)
2688 SOCKADDR_INET *uaaddr = (SOCKADDR_INET *)ua->Address.lpSockaddr;
2690 if ((row->Address.si_family == WS_AF_INET6 &&
2691 !memcmp(&row->Address.Ipv6.sin6_addr, &uaaddr->Ipv6.sin6_addr, sizeof(uaaddr->Ipv6.sin6_addr))) ||
2692 (row->Address.si_family == WS_AF_INET &&
2693 row->Address.Ipv4.sin_addr.S_un.S_addr == uaaddr->Ipv4.sin_addr.S_un.S_addr))
2695 memcpy(&row->InterfaceLuid, &aa->Luid, sizeof(aa->Luid));
2696 row->InterfaceIndex = aa->u.s.IfIndex;
2697 row->PrefixOrigin = ua->PrefixOrigin;
2698 row->SuffixOrigin = ua->SuffixOrigin;
2699 row->ValidLifetime = ua->ValidLifetime;
2700 row->PreferredLifetime = ua->PreferredLifetime;
2701 row->OnLinkPrefixLength = ua->OnLinkPrefixLength;
2702 row->SkipAsSource = 0;
2703 row->DadState = ua->DadState;
2704 if (row->Address.si_family == WS_AF_INET6)
2705 row->ScopeId.u.Value = row->Address.Ipv6.sin6_scope_id;
2706 else
2707 row->ScopeId.u.Value = 0;
2708 NtQuerySystemTime(&row->CreationTimeStamp);
2709 HeapFree(GetProcessHeap(), 0, ptr);
2710 return NO_ERROR;
2712 ua = ua->Next;
2715 HeapFree(GetProcessHeap(), 0, ptr);
2717 return ret;
2720 DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY family, MIB_UNICASTIPADDRESS_TABLE **table)
2722 IP_ADAPTER_ADDRESSES *aa, *ptr;
2723 MIB_UNICASTIPADDRESS_TABLE *data;
2724 DWORD ret, count = 0;
2725 ULONG size, flags;
2727 TRACE("%u, %p\n", family, table);
2729 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2730 return ERROR_INVALID_PARAMETER;
2732 flags = GAA_FLAG_SKIP_ANYCAST |
2733 GAA_FLAG_SKIP_MULTICAST |
2734 GAA_FLAG_SKIP_DNS_SERVER |
2735 GAA_FLAG_SKIP_FRIENDLY_NAME;
2737 ret = GetAdaptersAddresses(family, flags, NULL, NULL, &size);
2738 if (ret != ERROR_BUFFER_OVERFLOW)
2739 return ret;
2740 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, size)))
2741 return ERROR_OUTOFMEMORY;
2742 if ((ret = GetAdaptersAddresses(family, flags, NULL, ptr, &size)))
2744 HeapFree(GetProcessHeap(), 0, ptr);
2745 return ret;
2748 for (aa = ptr; aa; aa = aa->Next)
2750 IP_ADAPTER_UNICAST_ADDRESS *ua = aa->FirstUnicastAddress;
2751 while (ua)
2753 count++;
2754 ua = ua->Next;
2758 if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data) + (count - 1) * sizeof(data->Table[0]))))
2760 HeapFree(GetProcessHeap(), 0, ptr);
2761 return ERROR_OUTOFMEMORY;
2764 data->NumEntries = 0;
2765 for (aa = ptr; aa; aa = aa->Next)
2767 IP_ADAPTER_UNICAST_ADDRESS *ua = aa->FirstUnicastAddress;
2768 while (ua)
2770 MIB_UNICASTIPADDRESS_ROW *row = &data->Table[data->NumEntries];
2771 memcpy(&row->Address, ua->Address.lpSockaddr, ua->Address.iSockaddrLength);
2772 memcpy(&row->InterfaceLuid, &aa->Luid, sizeof(aa->Luid));
2773 row->InterfaceIndex = aa->u.s.IfIndex;
2774 row->PrefixOrigin = ua->PrefixOrigin;
2775 row->SuffixOrigin = ua->SuffixOrigin;
2776 row->ValidLifetime = ua->ValidLifetime;
2777 row->PreferredLifetime = ua->PreferredLifetime;
2778 row->OnLinkPrefixLength = ua->OnLinkPrefixLength;
2779 row->SkipAsSource = 0;
2780 row->DadState = ua->DadState;
2781 if (row->Address.si_family == WS_AF_INET6)
2782 row->ScopeId.u.Value = row->Address.Ipv6.sin6_scope_id;
2783 else
2784 row->ScopeId.u.Value = 0;
2785 NtQuerySystemTime(&row->CreationTimeStamp);
2787 data->NumEntries++;
2788 ua = ua->Next;
2792 HeapFree(GetProcessHeap(), 0, ptr);
2794 *table = data;
2795 return ret;
2798 /******************************************************************
2799 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2801 * This is a Win98-only function to get information on "unidirectional"
2802 * adapters. Since this is pretty nonsensical in other contexts, it
2803 * never returns anything.
2805 * PARAMS
2806 * pIPIfInfo [Out] buffer for adapter infos
2807 * dwOutBufLen [Out] length of the output buffer
2809 * RETURNS
2810 * Success: NO_ERROR
2811 * Failure: error code from winerror.h
2813 * FIXME
2814 * Stub, returns ERROR_NOT_SUPPORTED.
2816 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2818 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2819 /* a unidirectional adapter?? not bloody likely! */
2820 return ERROR_NOT_SUPPORTED;
2824 /******************************************************************
2825 * IpReleaseAddress (IPHLPAPI.@)
2827 * Release an IP obtained through DHCP,
2829 * PARAMS
2830 * AdapterInfo [In] adapter to release IP address
2832 * RETURNS
2833 * Success: NO_ERROR
2834 * Failure: error code from winerror.h
2836 * NOTES
2837 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2838 * this function does nothing.
2840 * FIXME
2841 * Stub, returns ERROR_NOT_SUPPORTED.
2843 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2845 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2846 return ERROR_NOT_SUPPORTED;
2850 /******************************************************************
2851 * IpRenewAddress (IPHLPAPI.@)
2853 * Renew an IP obtained through DHCP.
2855 * PARAMS
2856 * AdapterInfo [In] adapter to renew IP address
2858 * RETURNS
2859 * Success: NO_ERROR
2860 * Failure: error code from winerror.h
2862 * NOTES
2863 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2864 * this function does nothing.
2866 * FIXME
2867 * Stub, returns ERROR_NOT_SUPPORTED.
2869 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2871 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2872 return ERROR_NOT_SUPPORTED;
2876 /******************************************************************
2877 * NotifyAddrChange (IPHLPAPI.@)
2879 * Notify caller whenever the ip-interface map is changed.
2881 * PARAMS
2882 * Handle [Out] handle usable in asynchronous notification
2883 * overlapped [In] overlapped structure that notifies the caller
2885 * RETURNS
2886 * Success: NO_ERROR
2887 * Failure: error code from winerror.h
2889 * FIXME
2890 * Stub, returns ERROR_NOT_SUPPORTED.
2892 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2894 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2895 if (Handle) *Handle = INVALID_HANDLE_VALUE;
2896 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
2897 return ERROR_IO_PENDING;
2901 /******************************************************************
2902 * NotifyIpInterfaceChange (IPHLPAPI.@)
2904 DWORD WINAPI NotifyIpInterfaceChange(ADDRESS_FAMILY family, PIPINTERFACE_CHANGE_CALLBACK callback,
2905 PVOID context, BOOLEAN init_notify, PHANDLE handle)
2907 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
2908 family, callback, context, init_notify, handle);
2909 if (handle) *handle = NULL;
2910 return NO_ERROR;
2913 /******************************************************************
2914 * NotifyRouteChange2 (IPHLPAPI.@)
2916 DWORD WINAPI NotifyRouteChange2(ADDRESS_FAMILY family, PIPFORWARD_CHANGE_CALLBACK callback, VOID* context,
2917 BOOLEAN init_notify, HANDLE* handle)
2919 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
2920 family, callback, context, init_notify, handle);
2921 if (handle) *handle = NULL;
2922 return NO_ERROR;
2926 /******************************************************************
2927 * NotifyRouteChange (IPHLPAPI.@)
2929 * Notify caller whenever the ip routing table is changed.
2931 * PARAMS
2932 * Handle [Out] handle usable in asynchronous notification
2933 * overlapped [In] overlapped structure that notifies the caller
2935 * RETURNS
2936 * Success: NO_ERROR
2937 * Failure: error code from winerror.h
2939 * FIXME
2940 * Stub, returns ERROR_NOT_SUPPORTED.
2942 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2944 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2945 return ERROR_NOT_SUPPORTED;
2949 /******************************************************************
2950 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
2952 DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback,
2953 PVOID context, BOOLEAN init_notify, PHANDLE handle)
2955 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
2956 family, callback, context, init_notify, handle);
2957 if (handle) *handle = NULL;
2959 if (init_notify)
2960 callback(context, NULL, MibInitialNotification);
2962 return NO_ERROR;
2965 /******************************************************************
2966 * SendARP (IPHLPAPI.@)
2968 * Send an ARP request.
2970 * PARAMS
2971 * DestIP [In] attempt to obtain this IP
2972 * SrcIP [In] optional sender IP address
2973 * pMacAddr [Out] buffer for the mac address
2974 * PhyAddrLen [In/Out] length of the output buffer
2976 * RETURNS
2977 * Success: NO_ERROR
2978 * Failure: error code from winerror.h
2980 * FIXME
2981 * Stub, returns ERROR_NOT_SUPPORTED.
2983 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2985 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
2986 DestIP, SrcIP, pMacAddr, PhyAddrLen);
2987 return ERROR_NOT_SUPPORTED;
2991 /******************************************************************
2992 * SetIfEntry (IPHLPAPI.@)
2994 * Set the administrative status of an interface.
2996 * PARAMS
2997 * pIfRow [In] dwAdminStatus member specifies the new status.
2999 * RETURNS
3000 * Success: NO_ERROR
3001 * Failure: error code from winerror.h
3003 * FIXME
3004 * Stub, returns ERROR_NOT_SUPPORTED.
3006 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
3008 FIXME("(pIfRow %p): stub\n", pIfRow);
3009 /* this is supposed to set an interface administratively up or down.
3010 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3011 this sort of down is indistinguishable from other sorts of down (e.g. no
3012 link). */
3013 return ERROR_NOT_SUPPORTED;
3017 /******************************************************************
3018 * SetIpForwardEntry (IPHLPAPI.@)
3020 * Modify an existing route.
3022 * PARAMS
3023 * pRoute [In] route with the new information
3025 * RETURNS
3026 * Success: NO_ERROR
3027 * Failure: error code from winerror.h
3029 * FIXME
3030 * Stub, returns NO_ERROR.
3032 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
3034 FIXME("(pRoute %p): stub\n", pRoute);
3035 /* this is to add a route entry, how's it distinguishable from
3036 CreateIpForwardEntry?
3037 could use SIOCADDRT, not sure I want to */
3038 return 0;
3042 /******************************************************************
3043 * SetIpNetEntry (IPHLPAPI.@)
3045 * Modify an existing ARP entry.
3047 * PARAMS
3048 * pArpEntry [In] ARP entry with the new information
3050 * RETURNS
3051 * Success: NO_ERROR
3052 * Failure: error code from winerror.h
3054 * FIXME
3055 * Stub, returns NO_ERROR.
3057 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3059 FIXME("(pArpEntry %p): stub\n", pArpEntry);
3060 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3061 return 0;
3065 /******************************************************************
3066 * SetIpStatistics (IPHLPAPI.@)
3068 * Toggle IP forwarding and det the default TTL value.
3070 * PARAMS
3071 * pIpStats [In] IP statistics with the new information
3073 * RETURNS
3074 * Success: NO_ERROR
3075 * Failure: error code from winerror.h
3077 * FIXME
3078 * Stub, returns NO_ERROR.
3080 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3082 FIXME("(pIpStats %p): stub\n", pIpStats);
3083 return 0;
3087 /******************************************************************
3088 * SetIpTTL (IPHLPAPI.@)
3090 * Set the default TTL value.
3092 * PARAMS
3093 * nTTL [In] new TTL value
3095 * RETURNS
3096 * Success: NO_ERROR
3097 * Failure: error code from winerror.h
3099 * FIXME
3100 * Stub, returns NO_ERROR.
3102 DWORD WINAPI SetIpTTL(UINT nTTL)
3104 FIXME("(nTTL %d): stub\n", nTTL);
3105 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
3106 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
3107 return 0;
3111 /******************************************************************
3112 * SetTcpEntry (IPHLPAPI.@)
3114 * Set the state of a TCP connection.
3116 * PARAMS
3117 * pTcpRow [In] specifies connection with new state
3119 * RETURNS
3120 * Success: NO_ERROR
3121 * Failure: error code from winerror.h
3123 * FIXME
3124 * Stub, returns NO_ERROR.
3126 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3128 FIXME("(pTcpRow %p): stub\n", pTcpRow);
3129 return 0;
3132 /******************************************************************
3133 * SetPerTcpConnectionEStats (IPHLPAPI.@)
3135 DWORD WINAPI SetPerTcpConnectionEStats(PMIB_TCPROW row, TCP_ESTATS_TYPE state, PBYTE rw,
3136 ULONG version, ULONG size, ULONG offset)
3138 FIXME("(row %p, state %d, rw %p, version %u, size %u, offset %u): stub\n",
3139 row, state, rw, version, size, offset);
3140 return ERROR_NOT_SUPPORTED;
3144 /******************************************************************
3145 * UnenableRouter (IPHLPAPI.@)
3147 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3148 * if it reaches zero.
3150 * PARAMS
3151 * pOverlapped [In/Out] should be the same as in EnableRouter()
3152 * lpdwEnableCount [Out] optional, receives reference count
3154 * RETURNS
3155 * Success: NO_ERROR
3156 * Failure: error code from winerror.h
3158 * FIXME
3159 * Stub, returns ERROR_NOT_SUPPORTED.
3161 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3163 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3164 lpdwEnableCount);
3165 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
3166 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
3168 return ERROR_NOT_SUPPORTED;
3171 /******************************************************************
3172 * PfCreateInterface (IPHLPAPI.@)
3174 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
3175 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
3177 FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
3178 return ERROR_CALL_NOT_IMPLEMENTED;
3181 /******************************************************************
3182 * PfUnBindInterface (IPHLPAPI.@)
3184 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
3186 FIXME("(%p) stub\n", interface);
3187 return ERROR_CALL_NOT_IMPLEMENTED;
3190 /******************************************************************
3191 * PfDeleteInterface(IPHLPAPI.@)
3193 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
3195 FIXME("(%p) stub\n", interface);
3196 return ERROR_CALL_NOT_IMPLEMENTED;
3199 /******************************************************************
3200 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
3202 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
3204 FIXME("(%p %d %p) stub\n", interface, type, ip);
3205 return ERROR_CALL_NOT_IMPLEMENTED;
3208 /******************************************************************
3209 * GetTcpTable2 (IPHLPAPI.@)
3211 ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
3213 FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
3214 return ERROR_NOT_SUPPORTED;
3217 /******************************************************************
3218 * GetTcp6Table (IPHLPAPI.@)
3220 ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
3222 TRACE("(table %p, size %p, order %d)\n", table, size, order);
3223 return GetExtendedTcpTable(table, size, order, WS_AF_INET6, TCP_TABLE_BASIC_ALL, 0);
3226 /******************************************************************
3227 * GetTcp6Table2 (IPHLPAPI.@)
3229 ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
3231 FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
3232 return ERROR_NOT_SUPPORTED;
3235 /******************************************************************
3236 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
3238 DWORD WINAPI ConvertInterfaceAliasToLuid( const WCHAR *alias, NET_LUID *luid )
3240 struct nsi_ndis_ifinfo_rw *data;
3241 DWORD err, count, i, len;
3242 NET_LUID *keys;
3244 TRACE( "(%s %p)\n", debugstr_w(alias), luid );
3246 if (!alias || !*alias || !luid) return ERROR_INVALID_PARAMETER;
3247 luid->Value = 0;
3248 len = strlenW( alias );
3250 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3251 (void **)&data, sizeof(*data), NULL, 0, NULL, 0, &count, 0 );
3252 if (err) return err;
3254 err = ERROR_INVALID_PARAMETER;
3255 for (i = 0; i < count; i++)
3257 if (data[i].alias.Length == len * 2 && !memcmp( data[i].alias.String, alias, len * 2 ))
3259 luid->Value = keys[i].Value;
3260 err = ERROR_SUCCESS;
3261 break;
3264 NsiFreeTable( keys, data, NULL, NULL );
3265 return err;
3268 /******************************************************************
3269 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
3271 DWORD WINAPI ConvertInterfaceGuidToLuid(const GUID *guid, NET_LUID *luid)
3273 struct nsi_ndis_ifinfo_static *data;
3274 DWORD err, count, i;
3275 NET_LUID *keys;
3277 TRACE( "(%s %p)\n", debugstr_guid(guid), luid );
3279 if (!guid || !luid) return ERROR_INVALID_PARAMETER;
3280 luid->Value = 0;
3282 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3283 NULL, 0, NULL, 0, (void **)&data, sizeof(*data), &count, 0 );
3284 if (err) return err;
3286 err = ERROR_INVALID_PARAMETER;
3287 for (i = 0; i < count; i++)
3289 if (IsEqualGUID( &data[i].if_guid, guid ))
3291 luid->Value = keys[i].Value;
3292 err = ERROR_SUCCESS;
3293 break;
3296 NsiFreeTable( keys, NULL, NULL, data );
3297 return err;
3300 /******************************************************************
3301 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
3303 DWORD WINAPI ConvertInterfaceIndexToLuid(NET_IFINDEX index, NET_LUID *luid)
3305 DWORD err;
3307 TRACE( "(%u %p)\n", index, luid );
3309 if (!luid) return ERROR_INVALID_PARAMETER;
3311 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &index, sizeof(index),
3312 NSI_PARAM_TYPE_STATIC, luid, sizeof(*luid), 0 );
3313 if (err) luid->Value = 0;
3314 return err;
3317 /******************************************************************
3318 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
3320 DWORD WINAPI ConvertInterfaceLuidToAlias( const NET_LUID *luid, WCHAR *alias, SIZE_T len )
3322 DWORD err;
3323 IF_COUNTED_STRING name;
3325 TRACE( "(%p %p %u)\n", luid, alias, (DWORD)len );
3327 if (!luid || !alias) return ERROR_INVALID_PARAMETER;
3329 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3330 NSI_PARAM_TYPE_RW, &name, sizeof(name),
3331 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw, alias) );
3332 if (err) return err;
3334 if (len <= name.Length / sizeof(WCHAR)) return ERROR_NOT_ENOUGH_MEMORY;
3335 memcpy( alias, name.String, name.Length );
3336 alias[name.Length / sizeof(WCHAR)] = '\0';
3338 return err;
3341 /******************************************************************
3342 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
3344 DWORD WINAPI ConvertInterfaceLuidToGuid(const NET_LUID *luid, GUID *guid)
3346 DWORD err;
3348 TRACE( "(%p %p)\n", luid, guid );
3350 if (!luid || !guid) return ERROR_INVALID_PARAMETER;
3352 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3353 NSI_PARAM_TYPE_STATIC, guid, sizeof(*guid),
3354 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_guid) );
3355 if (err) memset( guid, 0, sizeof(*guid) );
3356 return err;
3359 /******************************************************************
3360 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
3362 DWORD WINAPI ConvertInterfaceLuidToIndex(const NET_LUID *luid, NET_IFINDEX *index)
3364 DWORD err;
3366 TRACE( "(%p %p)\n", luid, index );
3368 if (!luid || !index) return ERROR_INVALID_PARAMETER;
3370 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3371 NSI_PARAM_TYPE_STATIC, index, sizeof(*index),
3372 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index) );
3373 if (err) *index = 0;
3374 return err;
3377 /******************************************************************
3378 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
3380 DWORD WINAPI ConvertInterfaceLuidToNameA(const NET_LUID *luid, char *name, SIZE_T len)
3382 DWORD err;
3383 WCHAR nameW[IF_MAX_STRING_SIZE + 1];
3385 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
3387 if (!luid) return ERROR_INVALID_PARAMETER;
3388 if (!name || !len) return ERROR_NOT_ENOUGH_MEMORY;
3390 err = ConvertInterfaceLuidToNameW( luid, nameW, ARRAY_SIZE(nameW) );
3391 if (err) return err;
3393 if (!WideCharToMultiByte( CP_UNIXCP, 0, nameW, -1, name, len, NULL, NULL ))
3394 err = GetLastError();
3395 return err;
3398 static const WCHAR otherW[] = {'o','t','h','e','r',0};
3399 static const WCHAR ethernetW[] = {'e','t','h','e','r','n','e','t',0};
3400 static const WCHAR tokenringW[] = {'t','o','k','e','n','r','i','n','g',0};
3401 static const WCHAR pppW[] = {'p','p','p',0};
3402 static const WCHAR loopbackW[] = {'l','o','o','p','b','a','c','k',0};
3403 static const WCHAR atmW[] = {'a','t','m',0};
3404 static const WCHAR wirelessW[] = {'w','i','r','e','l','e','s','s',0};
3405 static const WCHAR tunnelW[] = {'t','u','n','n','e','l',0};
3406 static const WCHAR ieee1394W[] = {'i','e','e','e','1','3','9','4',0};
3408 struct name_prefix
3410 const WCHAR *prefix;
3411 DWORD type;
3413 static const struct name_prefix name_prefixes[] =
3415 { otherW, IF_TYPE_OTHER },
3416 { ethernetW, IF_TYPE_ETHERNET_CSMACD },
3417 { tokenringW, IF_TYPE_ISO88025_TOKENRING },
3418 { pppW, IF_TYPE_PPP },
3419 { loopbackW, IF_TYPE_SOFTWARE_LOOPBACK },
3420 { atmW, IF_TYPE_ATM },
3421 { wirelessW, IF_TYPE_IEEE80211 },
3422 { tunnelW, IF_TYPE_TUNNEL },
3423 { ieee1394W, IF_TYPE_IEEE1394 }
3426 /******************************************************************
3427 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
3429 DWORD WINAPI ConvertInterfaceLuidToNameW(const NET_LUID *luid, WCHAR *name, SIZE_T len)
3431 DWORD i, needed;
3432 const WCHAR *prefix = NULL;
3433 WCHAR buf[IF_MAX_STRING_SIZE + 1];
3434 static const WCHAR prefix_fmt[] = {'%','s','_','%','d',0};
3435 static const WCHAR unk_fmt[] = {'i','f','t','y','p','e','%','d','_','%','d',0};
3437 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
3439 if (!luid || !name) return ERROR_INVALID_PARAMETER;
3441 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
3443 if (luid->Info.IfType == name_prefixes[i].type)
3445 prefix = name_prefixes[i].prefix;
3446 break;
3450 if (prefix) needed = snprintfW( buf, len, prefix_fmt, prefix, luid->Info.NetLuidIndex );
3451 else needed = snprintfW( buf, len, unk_fmt, luid->Info.IfType, luid->Info.NetLuidIndex );
3453 if (needed >= len) return ERROR_NOT_ENOUGH_MEMORY;
3454 memcpy( name, buf, (needed + 1) * sizeof(WCHAR) );
3455 return ERROR_SUCCESS;
3458 /******************************************************************
3459 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
3461 DWORD WINAPI ConvertInterfaceNameToLuidA(const char *name, NET_LUID *luid)
3463 WCHAR nameW[IF_MAX_STRING_SIZE];
3465 TRACE( "(%s %p)\n", debugstr_a(name), luid );
3467 if (!name) return ERROR_INVALID_NAME;
3468 if (!MultiByteToWideChar( CP_UNIXCP, 0, name, -1, nameW, ARRAY_SIZE(nameW) ))
3469 return GetLastError();
3471 return ConvertInterfaceNameToLuidW( nameW, luid );
3474 /******************************************************************
3475 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
3477 DWORD WINAPI ConvertInterfaceNameToLuidW(const WCHAR *name, NET_LUID *luid)
3479 const WCHAR *sep;
3480 static const WCHAR iftype[] = {'i','f','t','y','p','e',0};
3481 DWORD type = ~0u, i;
3482 WCHAR buf[IF_MAX_STRING_SIZE + 1];
3484 TRACE( "(%s %p)\n", debugstr_w(name), luid );
3486 if (!luid) return ERROR_INVALID_PARAMETER;
3487 memset( luid, 0, sizeof(*luid) );
3489 if (!name || !(sep = strchrW( name, '_' )) || sep >= name + ARRAY_SIZE(buf)) return ERROR_INVALID_NAME;
3490 memcpy( buf, name, (sep - name) * sizeof(WCHAR) );
3491 buf[sep - name] = '\0';
3493 if (sep - name > ARRAY_SIZE(iftype) - 1 && !memcmp( buf, iftype, (ARRAY_SIZE(iftype) - 1) * sizeof(WCHAR) ))
3495 type = atoiW( buf + ARRAY_SIZE(iftype) - 1 );
3497 else
3499 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
3501 if (!strcmpW( buf, name_prefixes[i].prefix ))
3503 type = name_prefixes[i].type;
3504 break;
3508 if (type == ~0u) return ERROR_INVALID_NAME;
3510 luid->Info.NetLuidIndex = atoiW( sep + 1 );
3511 luid->Info.IfType = type;
3512 return ERROR_SUCCESS;
3515 /******************************************************************
3516 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
3518 DWORD WINAPI ConvertLengthToIpv4Mask(ULONG mask_len, ULONG *mask)
3520 if (mask_len > 32)
3522 *mask = INADDR_NONE;
3523 return ERROR_INVALID_PARAMETER;
3526 if (mask_len == 0)
3527 *mask = 0;
3528 else
3529 *mask = htonl(~0u << (32 - mask_len));
3531 return NO_ERROR;
3534 /******************************************************************
3535 * if_nametoindex (IPHLPAPI.@)
3537 IF_INDEX WINAPI IPHLP_if_nametoindex(const char *name)
3539 IF_INDEX index;
3540 NET_LUID luid;
3541 DWORD err;
3543 TRACE( "(%s)\n", name );
3545 err = ConvertInterfaceNameToLuidA( name, &luid );
3546 if (err) return 0;
3548 err = ConvertInterfaceLuidToIndex( &luid, &index );
3549 if (err) index = 0;
3550 return index;
3553 /******************************************************************
3554 * if_indextoname (IPHLPAPI.@)
3556 char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
3558 NET_LUID luid;
3559 DWORD err;
3561 TRACE( "(%u, %p)\n", index, name );
3563 err = ConvertInterfaceIndexToLuid( index, &luid );
3564 if (err) return NULL;
3566 err = ConvertInterfaceLuidToNameA( &luid, name, IF_MAX_STRING_SIZE );
3567 if (err) return NULL;
3568 return name;
3571 /******************************************************************
3572 * GetIpForwardTable2 (IPHLPAPI.@)
3574 DWORD WINAPI GetIpForwardTable2(ADDRESS_FAMILY family, PMIB_IPFORWARD_TABLE2 *table)
3576 static int once;
3578 if (!once++) FIXME("(%u %p): stub\n", family, table);
3579 return ERROR_NOT_SUPPORTED;
3582 /******************************************************************
3583 * GetIpNetTable2 (IPHLPAPI.@)
3585 DWORD WINAPI GetIpNetTable2(ADDRESS_FAMILY family, PMIB_IPNET_TABLE2 *table)
3587 static int once;
3589 if (!once++) FIXME("(%u %p): stub\n", family, table);
3590 return ERROR_NOT_SUPPORTED;
3593 /******************************************************************
3594 * GetIpInterfaceTable (IPHLPAPI.@)
3596 DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table)
3598 FIXME("(%u %p): stub\n", family, table);
3599 return ERROR_NOT_SUPPORTED;
3602 /******************************************************************
3603 * GetBestRoute2 (IPHLPAPI.@)
3605 DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
3606 const SOCKADDR_INET *source, const SOCKADDR_INET *destination,
3607 ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
3608 SOCKADDR_INET *bestaddress)
3610 static int once;
3612 if (!once++)
3613 FIXME("(%p, %d, %p, %p, 0x%08x, %p, %p): stub\n", luid, index, source,
3614 destination, options, bestroute, bestaddress);
3616 if (!destination || !bestroute || !bestaddress)
3617 return ERROR_INVALID_PARAMETER;
3619 return ERROR_NOT_SUPPORTED;
3622 /******************************************************************
3623 * ParseNetworkString (IPHLPAPI.@)
3625 DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
3626 NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len)
3628 IN_ADDR temp_addr4;
3629 IN6_ADDR temp_addr6;
3630 ULONG temp_scope;
3631 USHORT temp_port = 0;
3632 NTSTATUS status;
3634 TRACE("(%s, %d, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len);
3636 if (!str)
3637 return ERROR_INVALID_PARAMETER;
3639 if (type & NET_STRING_IPV4_ADDRESS)
3641 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
3642 if (SUCCEEDED(status) && !temp_port)
3644 if (info)
3646 info->Format = NET_ADDRESS_IPV4;
3647 info->u.Ipv4Address.sin_addr = temp_addr4;
3648 info->u.Ipv4Address.sin_port = 0;
3650 if (port) *port = 0;
3651 if (prefix_len) *prefix_len = 255;
3652 return ERROR_SUCCESS;
3655 if (type & NET_STRING_IPV4_SERVICE)
3657 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
3658 if (SUCCEEDED(status) && temp_port)
3660 if (info)
3662 info->Format = NET_ADDRESS_IPV4;
3663 info->u.Ipv4Address.sin_addr = temp_addr4;
3664 info->u.Ipv4Address.sin_port = temp_port;
3666 if (port) *port = ntohs(temp_port);
3667 if (prefix_len) *prefix_len = 255;
3668 return ERROR_SUCCESS;
3671 if (type & NET_STRING_IPV6_ADDRESS)
3673 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
3674 if (SUCCEEDED(status) && !temp_port)
3676 if (info)
3678 info->Format = NET_ADDRESS_IPV6;
3679 info->u.Ipv6Address.sin6_addr = temp_addr6;
3680 info->u.Ipv6Address.sin6_scope_id = temp_scope;
3681 info->u.Ipv6Address.sin6_port = 0;
3683 if (port) *port = 0;
3684 if (prefix_len) *prefix_len = 255;
3685 return ERROR_SUCCESS;
3688 if (type & NET_STRING_IPV6_SERVICE)
3690 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
3691 if (SUCCEEDED(status) && temp_port)
3693 if (info)
3695 info->Format = NET_ADDRESS_IPV6;
3696 info->u.Ipv6Address.sin6_addr = temp_addr6;
3697 info->u.Ipv6Address.sin6_scope_id = temp_scope;
3698 info->u.Ipv6Address.sin6_port = temp_port;
3700 if (port) *port = ntohs(temp_port);
3701 if (prefix_len) *prefix_len = 255;
3702 return ERROR_SUCCESS;
3706 if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED;
3708 if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_ADDRESS|NET_STRING_IPV6_SERVICE))
3710 FIXME("Unimplemented type 0x%x\n", type);
3711 return ERROR_NOT_SUPPORTED;
3714 return ERROR_INVALID_PARAMETER;