nsiproxy: Implement IP compartment get_all_paramters.
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blobfe2daa0f24dd66e92641d170f6193064d4420be6
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
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #define USE_WS_PREFIX
40 #include "winsock2.h"
41 #include "winternl.h"
42 #include "ws2ipdef.h"
43 #include "windns.h"
44 #include "iphlpapi.h"
45 #include "ifenum.h"
46 #include "ipstats.h"
47 #include "ipifcons.h"
48 #include "fltdefs.h"
49 #include "ifdef.h"
50 #include "netioapi.h"
51 #include "tcpestats.h"
52 #include "ip2string.h"
53 #include "netiodef.h"
55 #include "wine/nsi.h"
56 #include "wine/debug.h"
57 #include "wine/unicode.h"
58 #include "wine/heap.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
62 #ifndef IF_NAMESIZE
63 #define IF_NAMESIZE 16
64 #endif
66 #ifndef INADDR_NONE
67 #define INADDR_NONE ~0UL
68 #endif
70 #define CHARS_IN_GUID 39
72 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags );
73 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags );
75 static const NPI_MODULEID *ip_module_id( USHORT family )
77 if (family == WS_AF_INET) return &NPI_MS_IPV4_MODULEID;
78 if (family == WS_AF_INET6) return &NPI_MS_IPV6_MODULEID;
79 return NULL;
82 DWORD WINAPI ConvertGuidToStringA( const GUID *guid, char *str, DWORD len )
84 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
85 sprintf( str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
86 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
87 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
88 return ERROR_SUCCESS;
91 DWORD WINAPI ConvertGuidToStringW( const GUID *guid, WCHAR *str, DWORD len )
93 static const WCHAR fmt[] = { '{','%','0','8','X','-','%','0','4','X','-','%','0','4','X','-',
94 '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X',
95 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','}',0 };
97 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
98 sprintfW( str, fmt,
99 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
100 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
101 return ERROR_SUCCESS;
104 DWORD WINAPI ConvertStringToGuidW( const WCHAR *str, GUID *guid )
106 UNICODE_STRING ustr;
108 RtlInitUnicodeString( &ustr, str );
109 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr, guid ) );
112 static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
114 unsigned int copy = src->Length;
116 if (copy >= len * sizeof(WCHAR)) copy = 0;
117 memcpy( dst, src->String, copy );
118 memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
121 /******************************************************************
122 * AddIPAddress (IPHLPAPI.@)
124 * Add an IP address to an adapter.
126 * PARAMS
127 * Address [In] IP address to add to the adapter
128 * IpMask [In] subnet mask for the IP address
129 * IfIndex [In] adapter index to add the address
130 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
131 * NTEInstance [Out] NTE instance for the IP address
133 * RETURNS
134 * Success: NO_ERROR
135 * Failure: error code from winerror.h
137 * FIXME
138 * Stub. Currently returns ERROR_NOT_SUPPORTED.
140 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
142 FIXME(":stub\n");
143 return ERROR_NOT_SUPPORTED;
146 /******************************************************************
147 * CancelIPChangeNotify (IPHLPAPI.@)
149 * Cancel a previous notification created by NotifyAddrChange or
150 * NotifyRouteChange.
152 * PARAMS
153 * overlapped [In] overlapped structure that notifies the caller
155 * RETURNS
156 * Success: TRUE
157 * Failure: FALSE
159 * FIXME
160 * Stub, returns FALSE.
162 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
164 FIXME("(overlapped %p): stub\n", overlapped);
165 return FALSE;
169 /******************************************************************
170 * CancelMibChangeNotify2 (IPHLPAPI.@)
172 DWORD WINAPI CancelMibChangeNotify2(HANDLE handle)
174 FIXME("(handle %p): stub\n", handle);
175 return NO_ERROR;
179 /******************************************************************
180 * CreateIpForwardEntry (IPHLPAPI.@)
182 * Create a route in the local computer's IP table.
184 * PARAMS
185 * pRoute [In] new route information
187 * RETURNS
188 * Success: NO_ERROR
189 * Failure: error code from winerror.h
191 * FIXME
192 * Stub, always returns NO_ERROR.
194 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
196 FIXME("(pRoute %p): stub\n", pRoute);
197 /* could use SIOCADDRT, not sure I want to */
198 return 0;
202 /******************************************************************
203 * CreateIpNetEntry (IPHLPAPI.@)
205 * Create entry in the ARP table.
207 * PARAMS
208 * pArpEntry [In] new ARP entry
210 * RETURNS
211 * Success: NO_ERROR
212 * Failure: error code from winerror.h
214 * FIXME
215 * Stub, always returns NO_ERROR.
217 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
219 FIXME("(pArpEntry %p)\n", pArpEntry);
220 /* could use SIOCSARP on systems that support it, not sure I want to */
221 return 0;
225 /******************************************************************
226 * CreateProxyArpEntry (IPHLPAPI.@)
228 * Create a Proxy ARP (PARP) entry for an IP address.
230 * PARAMS
231 * dwAddress [In] IP address for which this computer acts as a proxy.
232 * dwMask [In] subnet mask for dwAddress
233 * dwIfIndex [In] interface index
235 * RETURNS
236 * Success: NO_ERROR
237 * Failure: error code from winerror.h
239 * FIXME
240 * Stub, returns ERROR_NOT_SUPPORTED.
242 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
244 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
245 dwAddress, dwMask, dwIfIndex);
246 return ERROR_NOT_SUPPORTED;
249 static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf)
251 const IN6_ADDR *addr = &sin->sin6_addr;
252 char *p = buf;
253 int i;
254 BOOL in_zero = FALSE;
256 for (i = 0; i < 7; i++)
258 if (!addr->u.Word[i])
260 if (i == 0)
261 *p++ = ':';
262 if (!in_zero)
264 *p++ = ':';
265 in_zero = TRUE;
268 else
270 p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
271 in_zero = FALSE;
274 sprintf(p, "%x", ntohs(addr->u.Word[7]));
275 return buf;
278 static BOOL map_address_6to4( const SOCKADDR_IN6 *addr6, SOCKADDR_IN *addr4 )
280 ULONG i;
282 if (addr6->sin6_family != WS_AF_INET6) return FALSE;
284 for (i = 0; i < 5; i++)
285 if (addr6->sin6_addr.u.Word[i]) return FALSE;
287 if (addr6->sin6_addr.u.Word[5] != 0xffff) return FALSE;
289 addr4->sin_family = WS_AF_INET;
290 addr4->sin_port = addr6->sin6_port;
291 addr4->sin_addr.S_un.S_addr = addr6->sin6_addr.u.Word[6] << 16 | addr6->sin6_addr.u.Word[7];
292 memset( &addr4->sin_zero, 0, sizeof(addr4->sin_zero) );
294 return TRUE;
297 static BOOL find_src_address( MIB_IPADDRTABLE *table, const SOCKADDR_IN *dst, SOCKADDR_IN6 *src )
299 MIB_IPFORWARDROW row;
300 DWORD i, j;
302 if (GetBestRoute( dst->sin_addr.S_un.S_addr, 0, &row )) return FALSE;
304 for (i = 0; i < table->dwNumEntries; i++)
306 /* take the first address */
307 if (table->table[i].dwIndex == row.dwForwardIfIndex)
309 src->sin6_family = WS_AF_INET6;
310 src->sin6_port = 0;
311 src->sin6_flowinfo = 0;
312 for (j = 0; j < 5; j++) src->sin6_addr.u.Word[j] = 0;
313 src->sin6_addr.u.Word[5] = 0xffff;
314 src->sin6_addr.u.Word[6] = table->table[i].dwAddr & 0xffff;
315 src->sin6_addr.u.Word[7] = table->table[i].dwAddr >> 16;
316 return TRUE;
320 return FALSE;
323 /******************************************************************
324 * CreateSortedAddressPairs (IPHLPAPI.@)
326 DWORD WINAPI CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list, DWORD src_count,
327 const PSOCKADDR_IN6 dst_list, DWORD dst_count,
328 DWORD options, PSOCKADDR_IN6_PAIR *pair_list,
329 DWORD *pair_count )
331 DWORD i, size, ret;
332 SOCKADDR_IN6_PAIR *pairs;
333 SOCKADDR_IN6 *ptr;
334 SOCKADDR_IN addr4;
335 MIB_IPADDRTABLE *table;
337 FIXME( "(src_list %p src_count %u dst_list %p dst_count %u options %x pair_list %p pair_count %p): stub\n",
338 src_list, src_count, dst_list, dst_count, options, pair_list, pair_count );
340 if (src_list || src_count || !dst_list || !pair_list || !pair_count || dst_count > 500)
341 return ERROR_INVALID_PARAMETER;
343 for (i = 0; i < dst_count; i++)
345 if (!map_address_6to4( &dst_list[i], &addr4 ))
347 FIXME("only mapped IPv4 addresses are supported\n");
348 return ERROR_NOT_SUPPORTED;
352 size = dst_count * sizeof(*pairs);
353 size += dst_count * sizeof(SOCKADDR_IN6) * 2; /* source address + destination address */
354 if (!(pairs = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_NOT_ENOUGH_MEMORY;
355 ptr = (SOCKADDR_IN6 *)&pairs[dst_count];
357 if ((ret = AllocateAndGetIpAddrTableFromStack( &table, FALSE, GetProcessHeap(), 0 )))
359 HeapFree( GetProcessHeap(), 0, pairs );
360 return ret;
363 for (i = 0; i < dst_count; i++)
365 pairs[i].SourceAddress = ptr++;
366 if (!map_address_6to4( &dst_list[i], &addr4 ) ||
367 !find_src_address( table, &addr4, pairs[i].SourceAddress ))
369 char buf[46];
370 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list[i], buf) );
371 memset( pairs[i].SourceAddress, 0, sizeof(*pairs[i].SourceAddress) );
372 pairs[i].SourceAddress->sin6_family = WS_AF_INET6;
375 pairs[i].DestinationAddress = ptr++;
376 memcpy( pairs[i].DestinationAddress, &dst_list[i], sizeof(*pairs[i].DestinationAddress) );
378 *pair_list = pairs;
379 *pair_count = dst_count;
381 HeapFree( GetProcessHeap(), 0, table );
382 return NO_ERROR;
386 /******************************************************************
387 * DeleteIPAddress (IPHLPAPI.@)
389 * Delete an IP address added with AddIPAddress().
391 * PARAMS
392 * NTEContext [In] NTE context from AddIPAddress();
394 * RETURNS
395 * Success: NO_ERROR
396 * Failure: error code from winerror.h
398 * FIXME
399 * Stub, returns ERROR_NOT_SUPPORTED.
401 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
403 FIXME("(NTEContext %d): stub\n", NTEContext);
404 return ERROR_NOT_SUPPORTED;
408 /******************************************************************
409 * DeleteIpForwardEntry (IPHLPAPI.@)
411 * Delete a route.
413 * PARAMS
414 * pRoute [In] route to delete
416 * RETURNS
417 * Success: NO_ERROR
418 * Failure: error code from winerror.h
420 * FIXME
421 * Stub, returns NO_ERROR.
423 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
425 FIXME("(pRoute %p): stub\n", pRoute);
426 /* could use SIOCDELRT, not sure I want to */
427 return 0;
431 /******************************************************************
432 * DeleteIpNetEntry (IPHLPAPI.@)
434 * Delete an ARP entry.
436 * PARAMS
437 * pArpEntry [In] ARP entry to delete
439 * RETURNS
440 * Success: NO_ERROR
441 * Failure: error code from winerror.h
443 * FIXME
444 * Stub, returns NO_ERROR.
446 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
448 FIXME("(pArpEntry %p): stub\n", pArpEntry);
449 /* could use SIOCDARP on systems that support it, not sure I want to */
450 return 0;
454 /******************************************************************
455 * DeleteProxyArpEntry (IPHLPAPI.@)
457 * Delete a Proxy ARP entry.
459 * PARAMS
460 * dwAddress [In] IP address for which this computer acts as a proxy.
461 * dwMask [In] subnet mask for dwAddress
462 * dwIfIndex [In] interface index
464 * RETURNS
465 * Success: NO_ERROR
466 * Failure: error code from winerror.h
468 * FIXME
469 * Stub, returns ERROR_NOT_SUPPORTED.
471 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
473 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
474 dwAddress, dwMask, dwIfIndex);
475 return ERROR_NOT_SUPPORTED;
479 /******************************************************************
480 * EnableRouter (IPHLPAPI.@)
482 * Turn on ip forwarding.
484 * PARAMS
485 * pHandle [In/Out]
486 * pOverlapped [In/Out] hEvent member should contain a valid handle.
488 * RETURNS
489 * Success: ERROR_IO_PENDING
490 * Failure: error code from winerror.h
492 * FIXME
493 * Stub, returns ERROR_NOT_SUPPORTED.
495 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
497 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
498 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
499 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
501 return ERROR_NOT_SUPPORTED;
505 /******************************************************************
506 * FlushIpNetTable (IPHLPAPI.@)
508 * Delete all ARP entries of an interface
510 * PARAMS
511 * dwIfIndex [In] interface index
513 * RETURNS
514 * Success: NO_ERROR
515 * Failure: error code from winerror.h
517 * FIXME
518 * Stub, returns ERROR_NOT_SUPPORTED.
520 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
522 FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
523 /* this flushes the arp cache of the given index */
524 return ERROR_NOT_SUPPORTED;
527 /******************************************************************
528 * FreeMibTable (IPHLPAPI.@)
530 * Free buffer allocated by network functions
532 * PARAMS
533 * ptr [In] pointer to the buffer to free
536 void WINAPI FreeMibTable(void *ptr)
538 TRACE("(%p)\n", ptr);
539 HeapFree(GetProcessHeap(), 0, ptr);
542 /******************************************************************
543 * GetAdapterIndex (IPHLPAPI.@)
545 * Get interface index from its name.
547 * PARAMS
548 * adapter_name [In] unicode string with the adapter name
549 * index [Out] returns found interface index
551 * RETURNS
552 * Success: NO_ERROR
553 * Failure: error code from winerror.h
555 DWORD WINAPI GetAdapterIndex( WCHAR *adapter_name, ULONG *index )
557 MIB_IFTABLE *if_table;
558 DWORD err, i;
560 TRACE( "name %s, index %p\n", debugstr_w( adapter_name ), index );
562 err = AllocateAndGetIfTableFromStack( &if_table, 0, GetProcessHeap(), 0 );
563 if (err) return err;
565 err = ERROR_INVALID_PARAMETER;
566 for (i = 0; i < if_table->dwNumEntries; i++)
568 if (!strcmpW( adapter_name, if_table->table[i].wszName ))
570 *index = if_table->table[i].dwIndex;
571 err = ERROR_SUCCESS;
572 break;
575 heap_free( if_table );
576 return err;
579 static DWORD get_wins_servers( SOCKADDR_INET **servers )
581 HKEY key;
582 char buf[4 * 4];
583 DWORD size, i, count = 0;
584 static const char *values[] = { "WinsServer", "BackupWinsServer" };
585 IN_ADDR addrs[ARRAY_SIZE(values)];
587 *servers = NULL;
588 /* @@ Wine registry key: HKCU\Software\Wine\Network */
589 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Network", &key )) return 0;
591 for (i = 0; i < ARRAY_SIZE(values); i++)
593 size = sizeof(buf);
594 if (!RegQueryValueExA( key, values[i], NULL, NULL, (LPBYTE)buf, &size ))
595 if (!RtlIpv4StringToAddressA( buf, TRUE, NULL, addrs + count ) &&
596 addrs[count].WS_s_addr != INADDR_NONE && addrs[count].WS_s_addr != INADDR_ANY)
597 count++;
599 RegCloseKey( key );
601 if (count)
603 *servers = heap_alloc_zero( count * sizeof(**servers) );
604 if (!*servers) return 0;
605 for (i = 0; i < count; i++)
607 (*servers)[i].Ipv4.sin_family = WS_AF_INET;
608 (*servers)[i].Ipv4.sin_addr = addrs[i];
611 return count;
614 static void ip_addr_string_init( IP_ADDR_STRING *s, const IN_ADDR *addr, const IN_ADDR *mask, DWORD ctxt )
616 s->Next = NULL;
618 if (addr) RtlIpv4AddressToStringA( addr, s->IpAddress.String );
619 else s->IpAddress.String[0] = '\0';
620 if (mask) RtlIpv4AddressToStringA( mask, s->IpMask.String );
621 else s->IpMask.String[0] = '\0';
622 s->Context = ctxt;
625 /******************************************************************
626 * GetAdaptersInfo (IPHLPAPI.@)
628 * Get information about adapters.
630 * PARAMS
631 * info [Out] buffer for adapter infos
632 * size [In] length of output buffer
634 DWORD WINAPI GetAdaptersInfo( IP_ADAPTER_INFO *info, ULONG *size )
636 DWORD err, if_count, if_num = 0, uni_count, fwd_count, needed, wins_server_count;
637 DWORD len, i, uni, fwd;
638 NET_LUID *if_keys = NULL;
639 struct nsi_ndis_ifinfo_rw *if_rw = NULL;
640 struct nsi_ndis_ifinfo_dynamic *if_dyn = NULL;
641 struct nsi_ndis_ifinfo_static *if_stat = NULL;
642 struct nsi_ipv4_unicast_key *uni_keys = NULL;
643 struct nsi_ip_unicast_rw *uni_rw = NULL;
644 struct nsi_ipv4_forward_key *fwd_keys = NULL;
645 SOCKADDR_INET *wins_servers = NULL;
646 IP_ADDR_STRING *extra_ip_addrs, *cursor;
647 IN_ADDR gw, mask;
649 TRACE( "info %p, size %p\n", info, size );
650 if (!size) return ERROR_INVALID_PARAMETER;
652 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
653 (void **)&if_keys, sizeof(*if_keys), (void **)&if_rw, sizeof(*if_rw),
654 (void **)&if_dyn, sizeof(*if_dyn), (void **)&if_stat, sizeof(*if_stat), &if_count, 0 );
655 if (err) return err;
656 for (i = 0; i < if_count; i++)
658 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
659 if_num++;
662 if (!if_num)
664 err = ERROR_NO_DATA;
665 goto err;
668 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE,
669 (void **)&uni_keys, sizeof(*uni_keys), (void **)&uni_rw, sizeof(*uni_rw),
670 NULL, 0, NULL, 0, &uni_count, 0 );
671 if (err) goto err;
673 /* Slightly overestimate the needed size by assuming that all
674 unicast addresses require a separate IP_ADDR_STRING. */
676 needed = if_num * sizeof(*info) + uni_count * sizeof(IP_ADDR_STRING);
677 if (!info || *size < needed)
679 *size = needed;
680 err = ERROR_BUFFER_OVERFLOW;
681 goto err;
684 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE,
685 (void **)&fwd_keys, sizeof(*fwd_keys), NULL, 0,
686 NULL, 0, NULL, 0, &fwd_count, 0 );
687 if (err) goto err;
689 wins_server_count = get_wins_servers( &wins_servers );
691 extra_ip_addrs = (IP_ADDR_STRING *)(info + if_num);
692 for (i = 0; i < if_count; i++)
694 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
696 info->Next = info + 1;
697 info->ComboIndex = 0;
698 ConvertGuidToStringA( &if_stat[i].if_guid, info->AdapterName, sizeof(info->AdapterName) );
699 len = WideCharToMultiByte( CP_ACP, 0, if_stat[i].descr.String, if_stat[i].descr.Length / sizeof(WCHAR),
700 info->Description, sizeof(info->Description) - 1, NULL, NULL );
701 info->Description[len] = '\0';
702 info->AddressLength = if_rw[i].phys_addr.Length;
703 if (info->AddressLength > sizeof(info->Address)) info->AddressLength = 0;
704 memcpy( info->Address, if_rw[i].phys_addr.Address, info->AddressLength );
705 memset( info->Address + info->AddressLength, 0, sizeof(info->Address) - info->AddressLength );
706 info->Index = if_stat[i].if_index;
707 info->Type = if_stat[i].type;
708 info->DhcpEnabled = TRUE; /* FIXME */
709 info->CurrentIpAddress = NULL;
711 cursor = NULL;
712 for (uni = 0; uni < uni_count; uni++)
714 if (uni_keys[uni].luid.Value != if_keys[i].Value) continue;
715 if (!cursor) cursor = &info->IpAddressList;
716 else
718 cursor->Next = extra_ip_addrs++;
719 cursor = cursor->Next;
721 ConvertLengthToIpv4Mask( uni_rw[uni].on_link_prefix, &mask.WS_s_addr );
722 ip_addr_string_init( cursor, &uni_keys[uni].addr, &mask, 0 );
724 if (!cursor)
726 mask.WS_s_addr = INADDR_ANY;
727 ip_addr_string_init( &info->IpAddressList, &mask, &mask, 0 );
730 gw.WS_s_addr = INADDR_ANY;
731 mask.WS_s_addr = INADDR_NONE;
732 for (fwd = 0; fwd < fwd_count; fwd++)
733 { /* find the first router on this interface */
734 if (fwd_keys[fwd].luid.Value == if_keys[i].Value &&
735 fwd_keys[fwd].next_hop.WS_s_addr != INADDR_ANY &&
736 !fwd_keys[fwd].prefix_len)
738 gw = fwd_keys[fwd].next_hop;
739 break;
742 ip_addr_string_init( &info->GatewayList, &gw, &mask, 0 );
744 ip_addr_string_init( &info->DhcpServer, NULL, NULL, 0 );
746 info->HaveWins = !!wins_server_count;
747 ip_addr_string_init( &info->PrimaryWinsServer, NULL, NULL, 0 );
748 ip_addr_string_init( &info->SecondaryWinsServer, NULL, NULL, 0 );
749 if (info->HaveWins)
751 mask.WS_s_addr = INADDR_NONE;
752 ip_addr_string_init( &info->PrimaryWinsServer, &wins_servers[0].Ipv4.sin_addr, &mask, 0 );
753 if (wins_server_count > 1)
754 ip_addr_string_init( &info->SecondaryWinsServer, &wins_servers[1].Ipv4.sin_addr, &mask, 0 );
757 info->LeaseObtained = 0;
758 info->LeaseExpires = 0;
760 info++;
762 info[-1].Next = NULL;
764 err:
765 heap_free( wins_servers );
766 NsiFreeTable( fwd_keys, NULL, NULL, NULL );
767 NsiFreeTable( uni_keys, uni_rw, NULL, NULL );
768 NsiFreeTable( if_keys, if_rw, if_dyn, if_stat );
769 return err;
772 static void address_entry_free( void *ptr, ULONG offset, void *ctxt )
774 heap_free( ptr );
777 static void address_entry_size( void *ptr, ULONG offset, void *ctxt )
779 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
780 ULONG *total = (ULONG *)ctxt, align = sizeof(ULONGLONG) - 1;
782 *total = (*total + src_addr->u.s.Length + src_addr->Address.iSockaddrLength + align) & ~align;
785 struct address_entry_copy_params
787 IP_ADAPTER_ADDRESSES *src, *dst;
788 char *ptr;
789 void *next;
790 ULONG cur_offset;
793 static void address_entry_copy( void *ptr, ULONG offset, void *ctxt )
795 struct address_entry_copy_params *params = ctxt;
796 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
797 IP_ADAPTER_DNS_SERVER_ADDRESS *dst_addr = (IP_ADAPTER_DNS_SERVER_ADDRESS *)params->ptr;
798 ULONG align = sizeof(ULONGLONG) - 1;
800 memcpy( dst_addr, src_addr, src_addr->u.s.Length );
801 params->ptr += src_addr->u.s.Length;
802 dst_addr->Address.lpSockaddr = (SOCKADDR *)params->ptr;
803 memcpy( dst_addr->Address.lpSockaddr, src_addr->Address.lpSockaddr, src_addr->Address.iSockaddrLength );
804 params->ptr += (src_addr->Address.iSockaddrLength + align) & ~align;
806 if (params->cur_offset != offset) /* new list */
808 params->next = (BYTE *)params->dst + offset;
809 params->cur_offset = offset;
811 *(IP_ADAPTER_DNS_SERVER_ADDRESS **)params->next = dst_addr;
812 params->next = &dst_addr->Next;
815 static void address_lists_iterate( IP_ADAPTER_ADDRESSES *aa, void (*fn)(void *entry, ULONG offset, void *ctxt), void *ctxt )
817 IP_ADAPTER_UNICAST_ADDRESS *uni;
818 IP_ADAPTER_DNS_SERVER_ADDRESS *dns;
819 IP_ADAPTER_GATEWAY_ADDRESS *gw;
820 IP_ADAPTER_PREFIX *prefix;
821 void *next;
823 for (uni = aa->FirstUnicastAddress; uni; uni = next)
825 next = uni->Next;
826 fn( uni, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstUnicastAddress ), ctxt );
829 for (dns = aa->FirstDnsServerAddress; dns; dns = next)
831 next = dns->Next;
832 fn( dns, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstDnsServerAddress ), ctxt );
835 for (gw = aa->FirstGatewayAddress; gw; gw = next)
837 next = gw->Next;
838 fn( gw, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstGatewayAddress ), ctxt );
841 for (prefix = aa->FirstPrefix; prefix; prefix = next)
843 next = prefix->Next;
844 fn( prefix, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstPrefix ), ctxt );
848 void adapters_addresses_free( IP_ADAPTER_ADDRESSES *info )
850 IP_ADAPTER_ADDRESSES *aa;
852 for (aa = info; aa; aa = aa->Next)
854 address_lists_iterate( aa, address_entry_free, NULL );
856 heap_free( aa->DnsSuffix );
858 heap_free( info );
861 ULONG adapters_addresses_size( IP_ADAPTER_ADDRESSES *info )
863 IP_ADAPTER_ADDRESSES *aa;
864 ULONG size = 0, align = sizeof(ULONGLONG) - 1;
866 for (aa = info; aa; aa = aa->Next)
868 size += sizeof(*aa) + ((strlen( aa->AdapterName ) + 1 + 1) & ~1);
869 size += (strlenW( aa->Description ) + 1 + strlenW( aa->DnsSuffix ) + 1) * sizeof(WCHAR);
870 if (aa->FriendlyName) size += (strlenW(aa->FriendlyName) + 1) * sizeof(WCHAR);
871 size = (size + align) & ~align;
872 address_lists_iterate( aa, address_entry_size, &size );
874 return size;
877 void adapters_addresses_copy( IP_ADAPTER_ADDRESSES *dst, IP_ADAPTER_ADDRESSES *src )
879 char *ptr;
880 DWORD len, align = sizeof(ULONGLONG) - 1;
881 struct address_entry_copy_params params;
883 while (src)
885 ptr = (char *)(dst + 1);
886 *dst = *src;
887 dst->AdapterName = ptr;
888 len = strlen( src->AdapterName ) + 1;
889 memcpy( dst->AdapterName, src->AdapterName, len );
890 ptr += (len + 1) & ~1;
891 dst->Description = (WCHAR *)ptr;
892 len = (strlenW( src->Description ) + 1) * sizeof(WCHAR);
893 memcpy( dst->Description, src->Description, len );
894 ptr += len;
895 dst->DnsSuffix = (WCHAR *)ptr;
896 len = (strlenW( src->DnsSuffix ) + 1) * sizeof(WCHAR);
897 memcpy( dst->DnsSuffix, src->DnsSuffix, len );
898 ptr += len;
899 if (src->FriendlyName)
901 dst->FriendlyName = (WCHAR *)ptr;
902 len = (strlenW( src->FriendlyName ) + 1) * sizeof(WCHAR);
903 memcpy( dst->FriendlyName, src->FriendlyName, len );
904 ptr += len;
906 ptr = (char *)(((UINT_PTR)ptr + align) & ~align);
908 params.src = src;
909 params.dst = dst;
910 params.ptr = ptr;
911 params.next = NULL;
912 params.cur_offset = ~0u;
913 address_lists_iterate( src, address_entry_copy, &params );
914 ptr = params.ptr;
916 if (src->Next)
918 dst->Next = (IP_ADAPTER_ADDRESSES *)ptr;
919 dst = dst->Next;
921 src = src->Next;
925 static BOOL sockaddr_is_loopback( SOCKADDR *sock )
927 if (sock->sa_family == WS_AF_INET)
929 SOCKADDR_IN *sin = (SOCKADDR_IN *)sock;
930 return (sin->sin_addr.WS_s_addr & 0xff) == 127;
932 else if (sock->sa_family == WS_AF_INET6)
934 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
935 return WS_IN6_IS_ADDR_LOOPBACK( &sin6->sin6_addr );
937 return FALSE;
940 static BOOL sockaddr_is_linklocal( SOCKADDR *sock )
942 if (sock->sa_family == WS_AF_INET6)
944 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
945 return WS_IN6_IS_ADDR_LINKLOCAL( &sin6->sin6_addr );
947 return FALSE;
950 static BOOL unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS *uni )
952 return !sockaddr_is_loopback( uni->Address.lpSockaddr ) &&
953 !sockaddr_is_linklocal( uni->Address.lpSockaddr );
956 static DWORD unicast_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
958 struct nsi_ipv4_unicast_key *key4;
959 struct nsi_ipv6_unicast_key *key6;
960 struct nsi_ip_unicast_rw *rw;
961 struct nsi_ip_unicast_dynamic *dyn;
962 struct nsi_ip_unicast_static *stat;
963 IP_ADAPTER_UNICAST_ADDRESS *addr, **next;
964 DWORD err, count, i, key_size = (family == WS_AF_INET) ? sizeof(*key4) : sizeof(*key6);
965 DWORD sockaddr_size = (family == WS_AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
966 NET_LUID *luid;
967 void *key;
969 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_UNICAST_TABLE, &key, key_size,
970 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
971 (void **)&stat, sizeof(*stat), &count, 0 );
972 if (err) return err;
975 while (aa)
977 for (next = &aa->FirstUnicastAddress; *next; next = &(*next)->Next)
980 for (i = 0; i < count; i++)
982 key4 = (struct nsi_ipv4_unicast_key *)key + i;
983 key6 = (struct nsi_ipv6_unicast_key *)key + i;
984 luid = (family == WS_AF_INET) ? &key4->luid : &key6->luid;
985 if (luid->Value != aa->Luid.Value) continue;
986 addr = heap_alloc_zero( sizeof(*addr) + sockaddr_size );
987 if (!addr)
989 err = ERROR_NOT_ENOUGH_MEMORY;
990 goto err;
992 addr->u.s.Length = sizeof(*addr);
993 addr->Address.lpSockaddr = (SOCKADDR *)(addr + 1);
994 addr->Address.iSockaddrLength = sockaddr_size;
995 addr->Address.lpSockaddr->sa_family = family;
996 if (family == WS_AF_INET)
998 SOCKADDR_IN *in = (SOCKADDR_IN *)addr->Address.lpSockaddr;
999 in->sin_addr = key4->addr;
1001 else
1003 SOCKADDR_IN6 *in6 = (SOCKADDR_IN6 *)addr->Address.lpSockaddr;
1004 in6->sin6_addr = key6->addr;
1005 in6->sin6_scope_id = dyn[i].scope_id;
1007 addr->PrefixOrigin = rw[i].prefix_origin;
1008 addr->SuffixOrigin = rw[i].suffix_origin;
1009 addr->DadState = dyn[i].dad_state;
1010 addr->ValidLifetime = rw[i].valid_lifetime;
1011 addr->PreferredLifetime = rw[i].preferred_lifetime;
1012 addr->LeaseLifetime = rw[i].valid_lifetime; /* FIXME */
1013 addr->OnLinkPrefixLength = rw[i].on_link_prefix;
1014 if (unicast_is_dns_eligible( addr )) addr->u.s.Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
1016 *next = addr;
1017 next = &addr->Next;
1019 aa = aa->Next;
1022 err:
1023 NsiFreeTable( key, rw, dyn, stat );
1024 return err;
1027 static DWORD gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1029 struct nsi_ipv4_forward_key *key4;
1030 struct nsi_ipv6_forward_key *key6;
1031 IP_ADAPTER_GATEWAY_ADDRESS *gw, **gw_next;
1032 IP_ADAPTER_PREFIX *prefix, **prefix_next;
1033 DWORD err, count, i, prefix_len, key_size = (family == WS_AF_INET) ? sizeof(*key4) : sizeof(*key6);
1034 DWORD sockaddr_size = (family == WS_AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
1035 SOCKADDR_INET sockaddr;
1036 NET_LUID *luid;
1037 void *key;
1039 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_FORWARD_TABLE, &key, key_size,
1040 NULL, 0, NULL, 0, NULL, 0, &count, 0 );
1041 if (err) return err;
1043 while (aa)
1045 for (gw_next = &aa->FirstGatewayAddress; *gw_next; gw_next = &(*gw_next)->Next)
1047 for (prefix_next = &aa->FirstPrefix; *prefix_next; prefix_next = &(*prefix_next)->Next)
1050 for (i = 0; i < count; i++)
1052 key4 = (struct nsi_ipv4_forward_key *)key + i;
1053 key6 = (struct nsi_ipv6_forward_key *)key + i;
1054 luid = (family == WS_AF_INET) ? &key4->luid : &key6->luid;
1055 if (luid->Value != aa->Luid.Value) continue;
1057 if (flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
1059 memset( &sockaddr, 0, sizeof(sockaddr) );
1060 if (family == WS_AF_INET)
1062 if (key4->next_hop.WS_s_addr != 0)
1064 sockaddr.si_family = family;
1065 sockaddr.Ipv4.sin_addr = key4->next_hop;
1068 else
1070 static const IN6_ADDR zero;
1071 if (memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1073 sockaddr.si_family = family;
1074 sockaddr.Ipv6.sin6_addr = key6->next_hop;
1078 if (sockaddr.si_family)
1080 gw = heap_alloc_zero( sizeof(*gw) + sockaddr_size );
1081 if (!gw)
1083 err = ERROR_NOT_ENOUGH_MEMORY;
1084 goto err;
1086 gw->u.s.Length = sizeof(*gw);
1087 gw->Address.lpSockaddr = (SOCKADDR *)(gw + 1);
1088 gw->Address.iSockaddrLength = sockaddr_size;
1089 memcpy( gw->Address.lpSockaddr, &sockaddr, sockaddr_size );
1090 *gw_next = gw;
1091 gw_next = &gw->Next;
1095 if (flags & GAA_FLAG_INCLUDE_PREFIX)
1097 memset( &sockaddr, 0, sizeof(sockaddr) );
1098 if (family == WS_AF_INET)
1100 if (!key4->next_hop.WS_s_addr)
1102 sockaddr.si_family = family;
1103 sockaddr.Ipv4.sin_addr = key4->prefix;
1104 prefix_len = key4->prefix_len;
1107 else
1109 static const IN6_ADDR zero;
1110 if (!memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1112 sockaddr.si_family = family;
1113 sockaddr.Ipv6.sin6_addr = key6->prefix;
1114 prefix_len = key6->prefix_len;
1118 if (sockaddr.si_family)
1120 prefix = heap_alloc_zero( sizeof(*prefix) + sockaddr_size );
1121 if (!prefix)
1123 err = ERROR_NOT_ENOUGH_MEMORY;
1124 goto err;
1126 prefix->u.s.Length = sizeof(*prefix);
1127 prefix->Address.lpSockaddr = (SOCKADDR *)(prefix + 1);
1128 prefix->Address.iSockaddrLength = sockaddr_size;
1129 memcpy( prefix->Address.lpSockaddr, &sockaddr, sockaddr_size );
1130 prefix->PrefixLength = prefix_len;
1131 *prefix_next = prefix;
1132 prefix_next = &prefix->Next;
1136 aa = aa->Next;
1139 err:
1140 NsiFreeTable( key, NULL, NULL, NULL );
1141 return err;
1144 static DWORD call_families( DWORD (*fn)( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags ),
1145 IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1147 DWORD err;
1149 if (family != WS_AF_INET)
1151 err = fn( aa, WS_AF_INET6, flags );
1152 if (err) return err;
1155 if (family != WS_AF_INET6)
1157 err = fn( aa, WS_AF_INET, flags );
1158 if (err) return err;
1160 return err;
1163 static DWORD dns_servers_query_code( ULONG family )
1165 if (family == WS_AF_INET) return DnsConfigDnsServersIpv4;
1166 if (family == WS_AF_INET6) return DnsConfigDnsServersIpv6;
1167 return DnsConfigDnsServersUnspec;
1170 static DWORD dns_info_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1172 char buf[FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[3])];
1173 IP_ADAPTER_DNS_SERVER_ADDRESS *dns, **next;
1174 DWORD query = dns_servers_query_code( family );
1175 DWORD err, i, size, attempt, sockaddr_len;
1176 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
1177 DNS_ADDR_ARRAY *servers;
1178 DNS_TXT_DATAW *search;
1180 while (aa)
1182 MultiByteToWideChar( CP_ACP, 0, aa->AdapterName, -1, name, ARRAY_SIZE(name) );
1183 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1185 servers = (DNS_ADDR_ARRAY *)buf;
1186 for (attempt = 0; attempt < 5; attempt++)
1188 err = DnsQueryConfig( query, 0, name, NULL, servers, &size );
1189 if (err != ERROR_MORE_DATA) break;
1190 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1191 servers = heap_alloc( size );
1192 if (!servers)
1194 err = ERROR_NOT_ENOUGH_MEMORY;
1195 break;
1198 if (!err)
1200 next = &aa->FirstDnsServerAddress;
1201 for (i = 0; i < servers->AddrCount; i++)
1203 sockaddr_len = servers->AddrArray[i].Data.DnsAddrUserDword[0];
1204 if (sockaddr_len > sizeof(servers->AddrArray[i].MaxSa))
1205 sockaddr_len = sizeof(servers->AddrArray[i].MaxSa);
1206 dns = heap_alloc_zero( sizeof(*dns) + sockaddr_len );
1207 if (!dns)
1209 err = ERROR_NOT_ENOUGH_MEMORY;
1210 break;
1212 dns->u.s.Length = sizeof(*dns);
1213 dns->Address.lpSockaddr = (SOCKADDR *)(dns + 1);
1214 dns->Address.iSockaddrLength = sockaddr_len;
1215 memcpy( dns->Address.lpSockaddr, servers->AddrArray[i].MaxSa, sockaddr_len );
1216 *next = dns;
1217 next = &dns->Next;
1220 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1221 if (err) goto err;
1224 aa->DnsSuffix = heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH * sizeof(WCHAR) );
1225 if (!aa->DnsSuffix)
1227 err = ERROR_NOT_ENOUGH_MEMORY;
1228 goto err;
1230 aa->DnsSuffix[0] = '\0';
1232 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, NULL, &size ) &&
1233 (search = heap_alloc( size )))
1235 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, search, &size ) &&
1236 search->dwStringCount && strlenW( search->pStringArray[0] ) < MAX_DNS_SUFFIX_STRING_LENGTH)
1238 strcpyW( aa->DnsSuffix, search->pStringArray[0] );
1240 heap_free( search );
1243 aa = aa->Next;
1246 err:
1247 return err;
1250 static DWORD adapters_addresses_alloc( ULONG family, ULONG flags, IP_ADAPTER_ADDRESSES **info )
1252 IP_ADAPTER_ADDRESSES *aa;
1253 NET_LUID *luids;
1254 struct nsi_ndis_ifinfo_rw *rw;
1255 struct nsi_ndis_ifinfo_dynamic *dyn;
1256 struct nsi_ndis_ifinfo_static *stat;
1257 DWORD err, i, count, needed;
1258 GUID guid;
1259 char *str_ptr;
1261 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&luids, sizeof(*luids),
1262 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1263 (void **)&stat, sizeof(*stat), &count, 0 );
1264 if (err) return err;
1266 needed = count * (sizeof(*aa) + ((CHARS_IN_GUID + 1) & ~1) + sizeof(stat->descr.String));
1267 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME)) needed += count * sizeof(rw->alias.String);
1269 aa = heap_alloc_zero( needed );
1270 if (!aa)
1272 err = ERROR_NOT_ENOUGH_MEMORY;
1273 goto err;
1276 str_ptr = (char *)(aa + count);
1277 for (i = 0; i < count; i++)
1279 aa[i].u.s.Length = sizeof(*aa);
1280 aa[i].u.s.IfIndex = stat[i].if_index;
1281 if (i < count - 1) aa[i].Next = aa + i + 1;
1282 ConvertInterfaceLuidToGuid( luids + i, &guid );
1283 ConvertGuidToStringA( &guid, str_ptr, CHARS_IN_GUID );
1284 aa[i].AdapterName = str_ptr;
1285 str_ptr += (CHARS_IN_GUID + 1) & ~1;
1286 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(stat[i].descr.String), &stat[i].descr );
1287 aa[i].Description = (WCHAR *)str_ptr;
1288 str_ptr += sizeof(stat[i].descr.String);
1289 if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
1291 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(rw[i].alias.String), &rw[i].alias );
1292 aa[i].FriendlyName = (WCHAR *)str_ptr;
1293 str_ptr += sizeof(rw[i].alias.String);
1295 aa[i].PhysicalAddressLength = rw->phys_addr.Length;
1296 if (aa[i].PhysicalAddressLength > sizeof(aa[i].PhysicalAddress)) aa[i].PhysicalAddressLength = 0;
1297 memcpy( aa[i].PhysicalAddress, rw->phys_addr.Address, aa[i].PhysicalAddressLength );
1298 aa[i].Mtu = dyn[i].mtu;
1299 aa[i].IfType = stat[i].type;
1300 aa[i].OperStatus = dyn[i].oper_status;
1301 aa[i].TransmitLinkSpeed = dyn[i].xmit_speed;
1302 aa[i].ReceiveLinkSpeed = dyn[i].rcv_speed;
1303 aa[i].Luid = luids[i];
1304 aa[i].NetworkGuid = rw[i].network_guid;
1305 aa[i].ConnectionType = stat[i].conn_type;
1308 if (!(flags & GAA_FLAG_SKIP_UNICAST))
1310 err = call_families( unicast_addresses_alloc, aa, family, flags );
1311 if (err) goto err;
1314 if (flags & (GAA_FLAG_INCLUDE_ALL_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX))
1316 err = call_families( gateway_and_prefix_addresses_alloc, aa, family, flags );
1317 if (err) goto err;
1320 err = dns_info_alloc( aa, family, flags );
1321 if (err) goto err;
1323 err:
1324 NsiFreeTable( luids, rw, dyn, stat );
1325 if (!err) *info = aa;
1326 else adapters_addresses_free( aa );
1327 return err;
1330 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses( ULONG family, ULONG flags, void *reserved,
1331 IP_ADAPTER_ADDRESSES *aa, ULONG *size )
1333 IP_ADAPTER_ADDRESSES *info;
1334 DWORD err, needed;
1336 TRACE( "(%d, %08x, %p, %p, %p)\n", family, flags, reserved, aa, size );
1338 if (!size) return ERROR_INVALID_PARAMETER;
1340 err = adapters_addresses_alloc( family, flags, &info );
1341 if (err) return err;
1343 needed = adapters_addresses_size( info );
1344 if (!aa || *size < needed)
1346 *size = needed;
1347 err = ERROR_BUFFER_OVERFLOW;
1349 else
1350 adapters_addresses_copy( aa, info );
1352 adapters_addresses_free( info );
1353 return err;
1356 /******************************************************************
1357 * GetBestInterface (IPHLPAPI.@)
1359 * Get the interface, with the best route for the given IP address.
1361 * PARAMS
1362 * dwDestAddr [In] IP address to search the interface for
1363 * pdwBestIfIndex [Out] found best interface
1365 * RETURNS
1366 * Success: NO_ERROR
1367 * Failure: error code from winerror.h
1369 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1371 struct WS_sockaddr_in sa_in;
1372 memset(&sa_in, 0, sizeof(sa_in));
1373 sa_in.sin_family = WS_AF_INET;
1374 sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1375 return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
1378 /******************************************************************
1379 * GetBestInterfaceEx (IPHLPAPI.@)
1381 * Get the interface, with the best route for the given IP address.
1383 * PARAMS
1384 * dwDestAddr [In] IP address to search the interface for
1385 * pdwBestIfIndex [Out] found best interface
1387 * RETURNS
1388 * Success: NO_ERROR
1389 * Failure: error code from winerror.h
1391 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1393 DWORD ret;
1395 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1396 if (!pDestAddr || !pdwBestIfIndex)
1397 ret = ERROR_INVALID_PARAMETER;
1398 else {
1399 MIB_IPFORWARDROW ipRow;
1401 if (pDestAddr->sa_family == WS_AF_INET) {
1402 ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1403 if (ret == ERROR_SUCCESS)
1404 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1405 } else {
1406 FIXME("address family %d not supported\n", pDestAddr->sa_family);
1407 ret = ERROR_NOT_SUPPORTED;
1410 TRACE("returning %d\n", ret);
1411 return ret;
1415 /******************************************************************
1416 * GetBestRoute (IPHLPAPI.@)
1418 * Get the best route for the given IP address.
1420 * PARAMS
1421 * dwDestAddr [In] IP address to search the best route for
1422 * dwSourceAddr [In] optional source IP address
1423 * pBestRoute [Out] found best route
1425 * RETURNS
1426 * Success: NO_ERROR
1427 * Failure: error code from winerror.h
1429 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1431 PMIB_IPFORWARDTABLE table;
1432 DWORD ret;
1434 TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
1435 dwSourceAddr, pBestRoute);
1436 if (!pBestRoute)
1437 return ERROR_INVALID_PARAMETER;
1439 ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1440 if (!ret) {
1441 DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1443 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1444 if (table->table[ndx].u1.ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1445 (dwDestAddr & table->table[ndx].dwForwardMask) ==
1446 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1447 DWORD numShifts, mask;
1449 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1450 mask && mask & 1; mask >>= 1, numShifts++)
1452 if (numShifts > matchedBits) {
1453 matchedBits = numShifts;
1454 matchedNdx = ndx;
1456 else if (!matchedBits) {
1457 matchedNdx = ndx;
1461 if (matchedNdx < table->dwNumEntries) {
1462 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1463 ret = ERROR_SUCCESS;
1465 else {
1466 /* No route matches, which can happen if there's no default route. */
1467 ret = ERROR_HOST_UNREACHABLE;
1469 HeapFree(GetProcessHeap(), 0, table);
1471 TRACE("returning %d\n", ret);
1472 return ret;
1476 /******************************************************************
1477 * GetFriendlyIfIndex (IPHLPAPI.@)
1479 * Get a "friendly" version of IfIndex, which is one that doesn't
1480 * have the top byte set. Doesn't validate whether IfIndex is a valid
1481 * adapter index.
1483 * PARAMS
1484 * IfIndex [In] interface index to get the friendly one for
1486 * RETURNS
1487 * A friendly version of IfIndex.
1489 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1491 /* windows doesn't validate these, either, just makes sure the top byte is
1492 cleared. I assume my ifenum module never gives an index with the top
1493 byte set. */
1494 TRACE("returning %d\n", IfIndex);
1495 return IfIndex;
1498 static void if_row_fill( MIB_IFROW *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1499 struct nsi_ndis_ifinfo_static *stat )
1501 static const WCHAR name_prefix[] = {'\\','D','E','V','I','C','E','\\','T','C','P','I','P','_',0};
1503 memcpy( row->wszName, name_prefix, sizeof(name_prefix) );
1504 ConvertGuidToStringW( &stat->if_guid, row->wszName + ARRAY_SIZE(name_prefix) - 1, CHARS_IN_GUID );
1505 row->dwIndex = stat->if_index;
1506 row->dwType = stat->type;
1507 row->dwMtu = dyn->mtu;
1508 row->dwSpeed = dyn->rcv_speed;
1509 row->dwPhysAddrLen = rw->phys_addr.Length;
1510 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
1511 memcpy( row->bPhysAddr, rw->phys_addr.Address, row->dwPhysAddrLen );
1512 row->dwAdminStatus = rw->admin_status;
1513 row->dwOperStatus = (dyn->oper_status == IfOperStatusUp) ? MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_NON_OPERATIONAL;
1514 row->dwLastChange = 0;
1515 row->dwInOctets = dyn->in_octets;
1516 row->dwInUcastPkts = dyn->in_ucast_pkts;
1517 row->dwInNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1518 row->dwInDiscards = dyn->in_discards;
1519 row->dwInErrors = dyn->in_errors;
1520 row->dwInUnknownProtos = 0;
1521 row->dwOutOctets = dyn->out_octets;
1522 row->dwOutUcastPkts = dyn->out_ucast_pkts;
1523 row->dwOutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1524 row->dwOutDiscards = dyn->out_discards;
1525 row->dwOutErrors = dyn->out_errors;
1526 row->dwOutQLen = 0;
1527 row->dwDescrLen = WideCharToMultiByte( CP_ACP, 0, stat->descr.String, stat->descr.Length / sizeof(WCHAR),
1528 (char *)row->bDescr, sizeof(row->bDescr) - 1, NULL, NULL );
1529 row->bDescr[row->dwDescrLen] = '\0';
1532 /******************************************************************
1533 * GetIfEntry (IPHLPAPI.@)
1535 * Get information about an interface.
1537 * PARAMS
1538 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1539 * Out: interface information
1541 * RETURNS
1542 * Success: NO_ERROR
1543 * Failure: error code from winerror.h
1545 DWORD WINAPI GetIfEntry( MIB_IFROW *row )
1547 struct nsi_ndis_ifinfo_rw rw;
1548 struct nsi_ndis_ifinfo_dynamic dyn;
1549 struct nsi_ndis_ifinfo_static stat;
1550 NET_LUID luid;
1551 DWORD err;
1553 TRACE( "row %p\n", row );
1554 if (!row) return ERROR_INVALID_PARAMETER;
1556 err = ConvertInterfaceIndexToLuid( row->dwIndex, &luid );
1557 if (err) return err;
1559 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1560 &luid, sizeof(luid), &rw, sizeof(rw),
1561 &dyn, sizeof(dyn), &stat, sizeof(stat) );
1562 if (!err) if_row_fill( row, &rw, &dyn, &stat );
1563 return err;
1566 static int ifrow_cmp( const void *a, const void *b )
1568 return ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1571 /******************************************************************
1572 * GetIfTable (IPHLPAPI.@)
1574 * Get a table of local interfaces.
1576 * PARAMS
1577 * table [Out] buffer for local interfaces table
1578 * size [In/Out] length of output buffer
1579 * sort [In] whether to sort the table
1581 * RETURNS
1582 * Success: NO_ERROR
1583 * Failure: error code from winerror.h
1585 * NOTES
1586 * If size is less than required, the function will return
1587 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1588 * size.
1589 * If sort is true, the returned table will be sorted by interface index.
1591 DWORD WINAPI GetIfTable( MIB_IFTABLE *table, ULONG *size, BOOL sort )
1593 DWORD i, count, needed, err;
1594 NET_LUID *keys;
1595 struct nsi_ndis_ifinfo_rw *rw;
1596 struct nsi_ndis_ifinfo_dynamic *dyn;
1597 struct nsi_ndis_ifinfo_static *stat;
1599 if (!size) return ERROR_INVALID_PARAMETER;
1601 /* While this could be implemented on top of GetIfTable2(), it would require
1602 an additional copy of the data */
1603 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1604 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1605 (void **)&stat, sizeof(*stat), &count, 0 );
1606 if (err) return err;
1608 needed = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1610 if (!table || *size < needed)
1612 *size = needed;
1613 err = ERROR_INSUFFICIENT_BUFFER;
1614 goto err;
1617 table->dwNumEntries = count;
1618 for (i = 0; i < count; i++)
1620 MIB_IFROW *row = table->table + i;
1622 if_row_fill( row, rw + i, dyn + i, stat + i );
1625 if (sort) qsort( table->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1627 err:
1628 NsiFreeTable( keys, rw, dyn, stat );
1629 return err;
1632 /******************************************************************
1633 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1635 * Get table of local interfaces.
1636 * Like GetIfTable(), but allocate the returned table from heap.
1638 * PARAMS
1639 * table [Out] pointer into which the MIB_IFTABLE is
1640 * allocated and returned.
1641 * sort [In] whether to sort the table
1642 * heap [In] heap from which the table is allocated
1643 * flags [In] flags to HeapAlloc
1645 * RETURNS
1646 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1647 * GetIfTable() returns otherwise.
1649 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1651 DWORD i, count, size, err;
1652 NET_LUID *keys;
1653 struct nsi_ndis_ifinfo_rw *rw;
1654 struct nsi_ndis_ifinfo_dynamic *dyn;
1655 struct nsi_ndis_ifinfo_static *stat;
1657 if (!table) return ERROR_INVALID_PARAMETER;
1659 /* While this could be implemented on top of GetIfTable(), it would require
1660 an additional call to retrieve the size */
1661 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1662 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1663 (void **)&stat, sizeof(*stat), &count, 0 );
1664 if (err) return err;
1666 size = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1667 *table = HeapAlloc( heap, flags, size );
1668 if (!*table)
1670 err = ERROR_NOT_ENOUGH_MEMORY;
1671 goto err;
1674 (*table)->dwNumEntries = count;
1675 for (i = 0; i < count; i++)
1677 MIB_IFROW *row = (*table)->table + i;
1679 if_row_fill( row, rw + i, dyn + i, stat + i );
1681 if (sort) qsort( (*table)->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1683 err:
1684 NsiFreeTable( keys, rw, dyn, stat );
1685 return err;
1688 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1689 struct nsi_ndis_ifinfo_static *stat )
1691 row->InterfaceIndex = stat->if_index;
1692 row->InterfaceGuid = stat->if_guid;
1693 if_counted_string_copy( row->Alias, ARRAY_SIZE(row->Alias), &rw->alias );
1694 if_counted_string_copy( row->Description, ARRAY_SIZE(row->Description), &stat->descr );
1695 row->PhysicalAddressLength = rw->phys_addr.Length;
1696 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress)) row->PhysicalAddressLength = 0;
1697 memcpy( row->PhysicalAddress, rw->phys_addr.Address, row->PhysicalAddressLength );
1698 memcpy( row->PermanentPhysicalAddress, stat->perm_phys_addr.Address, row->PhysicalAddressLength );
1699 row->Mtu = dyn->mtu;
1700 row->Type = stat->type;
1701 row->TunnelType = TUNNEL_TYPE_NONE; /* fixme */
1702 row->MediaType = stat->media_type;
1703 row->PhysicalMediumType = stat->phys_medium_type;
1704 row->AccessType = stat->access_type;
1705 row->DirectionType = NET_IF_DIRECTION_SENDRECEIVE; /* fixme */
1706 row->InterfaceAndOperStatusFlags.HardwareInterface = stat->flags.hw;
1707 row->InterfaceAndOperStatusFlags.FilterInterface = stat->flags.filter;
1708 row->InterfaceAndOperStatusFlags.ConnectorPresent = !!stat->conn_present;
1709 row->InterfaceAndOperStatusFlags.NotAuthenticated = 0; /* fixme */
1710 row->InterfaceAndOperStatusFlags.NotMediaConnected = dyn->flags.not_media_conn;
1711 row->InterfaceAndOperStatusFlags.Paused = 0; /* fixme */
1712 row->InterfaceAndOperStatusFlags.LowPower = 0; /* fixme */
1713 row->InterfaceAndOperStatusFlags.EndPointInterface = 0; /* fixme */
1714 row->OperStatus = dyn->oper_status;
1715 row->AdminStatus = rw->admin_status;
1716 row->MediaConnectState = dyn->media_conn_state;
1717 row->NetworkGuid = rw->network_guid;
1718 row->ConnectionType = stat->conn_type;
1719 row->TransmitLinkSpeed = dyn->xmit_speed;
1720 row->ReceiveLinkSpeed = dyn->rcv_speed;
1721 row->InOctets = dyn->in_octets;
1722 row->InUcastPkts = dyn->in_ucast_pkts;
1723 row->InNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1724 row->InDiscards = dyn->in_discards;
1725 row->InErrors = dyn->in_errors;
1726 row->InUnknownProtos = 0; /* fixme */
1727 row->InUcastOctets = dyn->in_ucast_octs;
1728 row->InMulticastOctets = dyn->in_mcast_octs;
1729 row->InBroadcastOctets = dyn->in_bcast_octs;
1730 row->OutOctets = dyn->out_octets;
1731 row->OutUcastPkts = dyn->out_ucast_pkts;
1732 row->OutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1733 row->OutDiscards = dyn->out_discards;
1734 row->OutErrors = dyn->out_errors;
1735 row->OutUcastOctets = dyn->out_ucast_octs;
1736 row->OutMulticastOctets = dyn->out_mcast_octs;
1737 row->OutBroadcastOctets = dyn->out_bcast_octs;
1738 row->OutQLen = 0; /* fixme */
1741 /******************************************************************
1742 * GetIfEntry2Ex (IPHLPAPI.@)
1744 DWORD WINAPI GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_ROW2 *row )
1746 DWORD err;
1747 struct nsi_ndis_ifinfo_rw rw;
1748 struct nsi_ndis_ifinfo_dynamic dyn;
1749 struct nsi_ndis_ifinfo_static stat;
1751 TRACE( "(%d, %p)\n", level, row );
1753 if (level != MibIfTableNormal) FIXME( "level %u not fully supported\n", level );
1754 if (!row) return ERROR_INVALID_PARAMETER;
1756 if (!row->InterfaceLuid.Value)
1758 if (!row->InterfaceIndex) return ERROR_INVALID_PARAMETER;
1759 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
1760 if (err) return err;
1763 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1764 &row->InterfaceLuid, sizeof(row->InterfaceLuid),
1765 &rw, sizeof(rw), &dyn, sizeof(dyn), &stat, sizeof(stat) );
1766 if (!err) if_row2_fill( row, &rw, &dyn, &stat );
1767 return err;
1770 /******************************************************************
1771 * GetIfEntry2 (IPHLPAPI.@)
1773 DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row )
1775 return GetIfEntry2Ex( MibIfTableNormal, row );
1778 /******************************************************************
1779 * GetIfTable2Ex (IPHLPAPI.@)
1781 DWORD WINAPI GetIfTable2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_TABLE2 **table )
1783 DWORD i, count, size, err;
1784 NET_LUID *keys;
1785 struct nsi_ndis_ifinfo_rw *rw;
1786 struct nsi_ndis_ifinfo_dynamic *dyn;
1787 struct nsi_ndis_ifinfo_static *stat;
1789 TRACE( "level %u, table %p\n", level, table );
1791 if (!table || level > MibIfTableNormalWithoutStatistics)
1792 return ERROR_INVALID_PARAMETER;
1794 if (level != MibIfTableNormal)
1795 FIXME("level %u not fully supported\n", level);
1797 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1798 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1799 (void **)&stat, sizeof(*stat), &count, 0 );
1800 if (err) return err;
1802 size = FIELD_OFFSET( MIB_IF_TABLE2, Table[count] );
1804 if (!(*table = heap_alloc_zero( size )))
1806 err = ERROR_OUTOFMEMORY;
1807 goto err;
1810 (*table)->NumEntries = count;
1811 for (i = 0; i < count; i++)
1813 MIB_IF_ROW2 *row = (*table)->Table + i;
1815 row->InterfaceLuid.Value = keys[i].Value;
1816 if_row2_fill( row, rw + i, dyn + i, stat + i );
1818 err:
1819 NsiFreeTable( keys, rw, dyn, stat );
1820 return err;
1823 /******************************************************************
1824 * GetIfTable2 (IPHLPAPI.@)
1826 DWORD WINAPI GetIfTable2( MIB_IF_TABLE2 **table )
1828 TRACE( "table %p\n", table );
1829 return GetIfTable2Ex( MibIfTableNormal, table );
1832 /******************************************************************
1833 * GetInterfaceInfo (IPHLPAPI.@)
1835 * Get a list of network interface adapters.
1837 * PARAMS
1838 * pIfTable [Out] buffer for interface adapters
1839 * dwOutBufLen [Out] if buffer is too small, returns required size
1841 * RETURNS
1842 * Success: NO_ERROR
1843 * Failure: error code from winerror.h
1845 * BUGS
1846 * MSDN states this should return non-loopback interfaces only.
1848 DWORD WINAPI GetInterfaceInfo( IP_INTERFACE_INFO *table, ULONG *size )
1850 MIB_IFTABLE *if_table;
1851 DWORD err, needed, i;
1853 TRACE("table %p, size %p\n", table, size );
1854 if (!size) return ERROR_INVALID_PARAMETER;
1856 err = AllocateAndGetIfTableFromStack( &if_table, 0, GetProcessHeap(), 0 );
1857 if (err) return err;
1859 needed = FIELD_OFFSET(IP_INTERFACE_INFO, Adapter[if_table->dwNumEntries]);
1860 if (!table || *size < needed)
1862 *size = needed;
1863 heap_free( if_table );
1864 return ERROR_INSUFFICIENT_BUFFER;
1867 table->NumAdapters = if_table->dwNumEntries;
1868 for (i = 0; i < if_table->dwNumEntries; i++)
1870 table->Adapter[i].Index = if_table->table[i].dwIndex;
1871 strcpyW( table->Adapter[i].Name, if_table->table[i].wszName );
1873 heap_free( if_table );
1874 return ERROR_SUCCESS;
1877 static int ipaddrrow_cmp( const void *a, const void *b )
1879 return ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
1882 /******************************************************************
1883 * GetIpAddrTable (IPHLPAPI.@)
1885 * Get interface-to-IP address mapping table.
1887 * PARAMS
1888 * table [Out] buffer for mapping table
1889 * size [In/Out] length of output buffer
1890 * sort [In] whether to sort the table
1892 * RETURNS
1893 * Success: NO_ERROR
1894 * Failure: error code from winerror.h
1897 DWORD WINAPI GetIpAddrTable( MIB_IPADDRTABLE *table, ULONG *size, BOOL sort )
1899 DWORD err, count, needed, i, loopback, row_num = 0;
1900 struct nsi_ipv4_unicast_key *keys;
1901 struct nsi_ip_unicast_rw *rw;
1903 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
1904 if (!size) return ERROR_INVALID_PARAMETER;
1906 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&keys, sizeof(*keys),
1907 (void **)&rw, sizeof(*rw), NULL, 0, NULL, 0, &count, 0 );
1908 if (err) return err;
1910 needed = FIELD_OFFSET( MIB_IPADDRTABLE, table[count] );
1912 if (!table || *size < needed)
1914 *size = needed;
1915 err = ERROR_INSUFFICIENT_BUFFER;
1916 goto err;
1919 table->dwNumEntries = count;
1921 for (loopback = 0; loopback < 2; loopback++) /* Move the loopback addresses to the end */
1923 for (i = 0; i < count; i++)
1925 MIB_IPADDRROW *row = table->table + row_num;
1927 if (!!loopback != (keys[i].luid.Info.IfType == MIB_IF_TYPE_LOOPBACK)) continue;
1929 row->dwAddr = keys[i].addr.WS_s_addr;
1930 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
1931 ConvertLengthToIpv4Mask( rw[i].on_link_prefix, &row->dwMask );
1932 row->dwBCastAddr = 1;
1933 row->dwReasmSize = 0xffff;
1934 row->unused1 = 0;
1935 row->wType = MIB_IPADDR_PRIMARY;
1936 row_num++;
1940 if (sort) qsort( table->table, count, sizeof(MIB_IPADDRROW), ipaddrrow_cmp );
1941 err:
1942 NsiFreeTable( keys, rw, NULL, NULL );
1944 return err;
1948 /******************************************************************
1949 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
1951 * Get interface-to-IP address mapping table.
1952 * Like GetIpAddrTable(), but allocate the returned table from heap.
1954 * PARAMS
1955 * table [Out] pointer into which the MIB_IPADDRTABLE is
1956 * allocated and returned.
1957 * sort [In] whether to sort the table
1958 * heap [In] heap from which the table is allocated
1959 * flags [In] flags to HeapAlloc
1962 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1964 DWORD err, size = FIELD_OFFSET(MIB_IPADDRTABLE, table[2]), attempt;
1966 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
1968 for (attempt = 0; attempt < 5; attempt++)
1970 *table = HeapAlloc( heap, flags, size );
1971 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
1973 err = GetIpAddrTable( *table, &size, sort );
1974 if (!err) break;
1975 HeapFree( heap, flags, *table );
1976 if (err != ERROR_INSUFFICIENT_BUFFER) break;
1979 return err;
1982 static int ipforward_row_cmp( const void *a, const void *b )
1984 const MIB_IPFORWARDROW *rowA = a;
1985 const MIB_IPFORWARDROW *rowB = b;
1986 int ret;
1988 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1989 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
1990 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1991 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1994 /******************************************************************
1995 * GetIpForwardTable (IPHLPAPI.@)
1997 * Get the route table.
1999 * PARAMS
2000 * table [Out] buffer for route table
2001 * size [In/Out] length of output buffer
2002 * sort [In] whether to sort the table
2004 * RETURNS
2005 * Success: NO_ERROR
2006 * Failure: error code from winerror.h
2008 DWORD WINAPI GetIpForwardTable( MIB_IPFORWARDTABLE *table, ULONG *size, BOOL sort )
2010 DWORD err, count, uni_count, needed, i, addr;
2011 struct nsi_ipv4_forward_key *keys;
2012 struct nsi_ip_forward_rw *rw;
2013 struct nsi_ipv4_forward_dynamic *dyn;
2014 struct nsi_ip_forward_static *stat;
2015 struct nsi_ipv4_unicast_key *uni_keys = NULL;
2017 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2018 if (!size) return ERROR_INVALID_PARAMETER;
2020 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, (void **)&keys, sizeof(*keys),
2021 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2022 (void **)&stat, sizeof(*stat), &count, 0 );
2023 if (err) return err;
2025 needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
2027 if (!table || *size < needed)
2029 *size = needed;
2030 err = ERROR_INSUFFICIENT_BUFFER;
2031 goto err;
2034 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
2035 NULL, 0, NULL, 0, NULL, 0, &uni_count, 0 );
2036 if (err) goto err;
2038 table->dwNumEntries = count;
2039 for (i = 0; i < count; i++)
2041 MIB_IPFORWARDROW *row = table->table + i;
2043 row->dwForwardDest = keys[i].prefix.WS_s_addr;
2044 ConvertLengthToIpv4Mask( keys[i].prefix_len, &row->dwForwardMask );
2045 row->dwForwardPolicy = 0;
2046 row->dwForwardNextHop = keys[i].next_hop.WS_s_addr;
2047 row->u1.dwForwardType = row->dwForwardNextHop ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
2048 if (!row->dwForwardNextHop) /* find the interface's addr */
2050 for (addr = 0; addr < uni_count; addr++)
2052 if (uni_keys[addr].luid.Value == keys[i].luid.Value)
2054 row->dwForwardNextHop = uni_keys[addr].addr.WS_s_addr;
2055 break;
2059 row->dwForwardIfIndex = stat[i].if_index;
2060 row->u2.dwForwardProto = rw[i].protocol;
2061 row->dwForwardAge = dyn[i].age;
2062 row->dwForwardNextHopAS = 0;
2063 row->dwForwardMetric1 = rw[i].metric; /* FIXME: add interface metric */
2064 row->dwForwardMetric2 = 0;
2065 row->dwForwardMetric3 = 0;
2066 row->dwForwardMetric4 = 0;
2067 row->dwForwardMetric5 = 0;
2070 if (sort) qsort( table->table, count, sizeof(MIB_IPFORWARDROW), ipforward_row_cmp );
2071 err:
2072 NsiFreeTable( uni_keys, NULL, NULL, NULL );
2073 NsiFreeTable( keys, rw, dyn, stat );
2075 return err;
2078 /******************************************************************
2079 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2081 * Get the route table.
2082 * Like GetIpForwardTable(), but allocate the returned table from heap.
2084 * PARAMS
2085 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2086 * allocated and returned.
2087 * sort [In] whether to sort the table
2088 * heap [In] heap from which the table is allocated
2089 * flags [In] flags to HeapAlloc
2091 * RETURNS
2092 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2093 * on failure, NO_ERROR on success.
2095 DWORD WINAPI AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2097 DWORD err, size = FIELD_OFFSET(MIB_IPFORWARDTABLE, table[2]), attempt;
2099 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
2101 for (attempt = 0; attempt < 5; attempt++)
2103 *table = HeapAlloc( heap, flags, size );
2104 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2106 err = GetIpForwardTable( *table, &size, sort );
2107 if (!err) break;
2108 HeapFree( heap, flags, *table );
2109 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2112 return err;
2115 static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
2116 void *dyn, struct nsi_ip_forward_static *stat )
2118 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key;
2119 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key;
2120 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn;
2121 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn;
2123 if (fam == WS_AF_INET)
2125 row->InterfaceLuid = key4->luid;
2126 row->DestinationPrefix.Prefix.Ipv4.sin_family = fam;
2127 row->DestinationPrefix.Prefix.Ipv4.sin_port = 0;
2128 row->DestinationPrefix.Prefix.Ipv4.sin_addr = key4->prefix;
2129 memset( &row->DestinationPrefix.Prefix.Ipv4.sin_zero, 0, sizeof(row->DestinationPrefix.Prefix.Ipv4.sin_zero) );
2130 row->DestinationPrefix.PrefixLength = key4->prefix_len;
2131 row->NextHop.Ipv4.sin_family = fam;
2132 row->NextHop.Ipv4.sin_port = 0;
2133 row->NextHop.Ipv4.sin_addr = key4->next_hop;
2134 memset( &row->NextHop.Ipv4.sin_zero, 0, sizeof(row->NextHop.Ipv4.sin_zero) );
2136 row->Age = dyn4->age;
2138 else
2140 row->InterfaceLuid = key6->luid;
2142 row->DestinationPrefix.Prefix.Ipv6.sin6_family = fam;
2143 row->DestinationPrefix.Prefix.Ipv6.sin6_port = 0;
2144 row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo = 0;
2145 row->DestinationPrefix.Prefix.Ipv6.sin6_addr = key6->prefix;
2146 row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id = 0;
2147 row->DestinationPrefix.PrefixLength = key6->prefix_len;
2148 row->NextHop.Ipv6.sin6_family = fam;
2149 row->NextHop.Ipv6.sin6_port = 0;
2150 row->NextHop.Ipv6.sin6_flowinfo = 0;
2151 row->NextHop.Ipv6.sin6_addr = key6->next_hop;
2152 row->NextHop.Ipv6.sin6_scope_id = 0;
2154 row->Age = dyn6->age;
2157 row->InterfaceIndex = stat->if_index;
2159 row->SitePrefixLength = rw->site_prefix_len;
2160 row->ValidLifetime = rw->valid_lifetime;
2161 row->PreferredLifetime = rw->preferred_lifetime;
2162 row->Metric = rw->metric;
2163 row->Protocol = rw->protocol;
2164 row->Loopback = rw->loopback;
2165 row->AutoconfigureAddress = rw->autoconf;
2166 row->Publish = rw->publish;
2167 row->Immortal = rw->immortal;
2169 row->Origin = stat->origin;
2172 /******************************************************************
2173 * GetIpForwardTable2 (IPHLPAPI.@)
2175 DWORD WINAPI GetIpForwardTable2( ADDRESS_FAMILY family, MIB_IPFORWARD_TABLE2 **table )
2177 void *key[2] = { NULL, NULL };
2178 struct nsi_ip_forward_rw *rw[2] = { NULL, NULL };
2179 void *dyn[2] = { NULL, NULL };
2180 struct nsi_ip_forward_static *stat[2] = { NULL, NULL };
2181 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
2182 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ipv6_forward_key) };
2183 static const DWORD dyn_size[2] = { sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ipv6_forward_dynamic) };
2184 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2186 TRACE( "%u, %p\n", family, table );
2188 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2189 return ERROR_INVALID_PARAMETER;
2191 for (i = 0; i < 2; i++)
2193 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
2195 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_FORWARD_TABLE, key + i, key_size[i],
2196 (void **)rw + i, sizeof(**rw), dyn + i, dyn_size[i],
2197 (void **)stat + i, sizeof(**stat), count + i, 0 );
2198 if (err) count[i] = 0;
2201 size = FIELD_OFFSET(MIB_IPFORWARD_TABLE2, Table[ count[0] + count[1] ]);
2202 *table = heap_alloc( size );
2203 if (!*table)
2205 err = ERROR_NOT_ENOUGH_MEMORY;
2206 goto err;
2209 (*table)->NumEntries = count[0] + count[1];
2210 for (i = 0; i < count[0]; i++)
2212 MIB_IPFORWARD_ROW2 *row = (*table)->Table + i;
2213 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key[0];
2214 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn[0];
2216 forward_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn4 + i, stat[0] + i );
2219 for (i = 0; i < count[1]; i++)
2221 MIB_IPFORWARD_ROW2 *row = (*table)->Table + count[0] + i;
2222 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key[1];
2223 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn[1];
2225 forward_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn6 + i, stat[1] + i );
2228 err:
2229 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
2230 return err;
2233 static int ipnetrow_cmp( const void *a, const void *b )
2235 const MIB_IPNETROW *row_a = a;
2236 const MIB_IPNETROW *row_b = b;
2238 return RtlUlongByteSwap( row_a->dwAddr ) - RtlUlongByteSwap( row_b->dwAddr );
2241 /******************************************************************
2242 * GetIpNetTable (IPHLPAPI.@)
2244 * Get the IP-to-physical address mapping table.
2246 * PARAMS
2247 * table [Out] buffer for mapping table
2248 * size [In/Out] length of output buffer
2249 * sort [In] whether to sort the table
2251 * RETURNS
2252 * Success: NO_ERROR
2253 * Failure: error code from winerror.h
2256 DWORD WINAPI GetIpNetTable( MIB_IPNETTABLE *table, ULONG *size, BOOL sort )
2258 DWORD err, count, needed, i;
2259 struct nsi_ipv4_neighbour_key *keys;
2260 struct nsi_ip_neighbour_rw *rw;
2261 struct nsi_ip_neighbour_dynamic *dyn;
2263 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2265 if (!size) return ERROR_INVALID_PARAMETER;
2267 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_NEIGHBOUR_TABLE, (void **)&keys, sizeof(*keys),
2268 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2269 NULL, 0, &count, 0 );
2270 if (err) return err;
2272 needed = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
2274 if (!table || *size < needed)
2276 *size = needed;
2277 err = ERROR_INSUFFICIENT_BUFFER;
2278 goto err;
2281 table->dwNumEntries = count;
2282 for (i = 0; i < count; i++)
2284 MIB_IPNETROW *row = table->table + i;
2286 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
2287 row->dwPhysAddrLen = dyn[i].phys_addr_len;
2288 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
2289 memcpy( row->bPhysAddr, rw[i].phys_addr, row->dwPhysAddrLen );
2290 memset( row->bPhysAddr + row->dwPhysAddrLen, 0,
2291 sizeof(row->bPhysAddr) - row->dwPhysAddrLen );
2292 row->dwAddr = keys[i].addr.WS_s_addr;
2293 switch (dyn->state)
2295 case NlnsUnreachable:
2296 case NlnsIncomplete:
2297 row->u.Type = MIB_IPNET_TYPE_INVALID;
2298 break;
2299 case NlnsProbe:
2300 case NlnsDelay:
2301 case NlnsStale:
2302 case NlnsReachable:
2303 row->u.Type = MIB_IPNET_TYPE_DYNAMIC;
2304 break;
2305 case NlnsPermanent:
2306 row->u.Type = MIB_IPNET_TYPE_STATIC;
2307 break;
2308 default:
2309 row->u.Type = MIB_IPNET_TYPE_OTHER;
2313 if (sort) qsort( table->table, table->dwNumEntries, sizeof(*table->table), ipnetrow_cmp );
2315 err:
2316 NsiFreeTable( keys, rw, dyn, NULL );
2317 return err;
2320 /******************************************************************
2321 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2323 DWORD WINAPI AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2325 DWORD err, size = FIELD_OFFSET(MIB_IPNETTABLE, table[2]), attempt;
2327 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
2329 for (attempt = 0; attempt < 5; attempt++)
2331 *table = HeapAlloc( heap, flags, size );
2332 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2334 err = GetIpNetTable( *table, &size, sort );
2335 if (!err) break;
2336 HeapFree( heap, flags, *table );
2337 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2340 return err;
2343 static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw,
2344 struct nsi_ip_neighbour_dynamic *dyn )
2346 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key;
2347 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key;
2349 if (fam == WS_AF_INET)
2351 row->Address.Ipv4.sin_family = fam;
2352 row->Address.Ipv4.sin_port = 0;
2353 row->Address.Ipv4.sin_addr = key4->addr;
2354 memset( &row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
2355 row->InterfaceLuid = key4->luid;
2357 else
2359 row->Address.Ipv6.sin6_family = fam;
2360 row->Address.Ipv6.sin6_port = 0;
2361 row->Address.Ipv6.sin6_flowinfo = 0;
2362 row->Address.Ipv6.sin6_addr = key6->addr;
2363 row->Address.Ipv6.sin6_scope_id = 0;
2364 row->InterfaceLuid = key6->luid;
2367 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
2369 row->PhysicalAddressLength = dyn->phys_addr_len;
2370 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress))
2371 row->PhysicalAddressLength = 0;
2372 memcpy( row->PhysicalAddress, rw->phys_addr, row->PhysicalAddressLength );
2373 memset( row->PhysicalAddress + row->PhysicalAddressLength, 0,
2374 sizeof(row->PhysicalAddress) - row->PhysicalAddressLength );
2375 row->State = dyn->state;
2376 row->u.Flags = 0;
2377 row->u.s.IsRouter = dyn->flags.is_router;
2378 row->u.s.IsUnreachable = dyn->flags.is_unreachable;
2379 row->ReachabilityTime.LastReachable = dyn->time;
2382 /******************************************************************
2383 * GetIpNetTable2 (IPHLPAPI.@)
2385 DWORD WINAPI GetIpNetTable2( ADDRESS_FAMILY family, MIB_IPNET_TABLE2 **table )
2387 void *key[2] = { NULL, NULL };
2388 struct nsi_ip_neighbour_rw *rw[2] = { NULL, NULL };
2389 struct nsi_ip_neighbour_dynamic *dyn[2] = { NULL, NULL };
2390 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
2391 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ipv6_neighbour_key) };
2392 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2394 TRACE( "%u, %p\n", family, table );
2396 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2397 return ERROR_INVALID_PARAMETER;
2399 for (i = 0; i < 2; i++)
2401 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
2403 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_NEIGHBOUR_TABLE, key + i, key_size[i],
2404 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
2405 NULL, 0, count + i, 0 );
2406 if (err) count[i] = 0;
2409 size = FIELD_OFFSET(MIB_IPNET_TABLE2, Table[ count[0] + count[1] ]);
2410 *table = heap_alloc( size );
2411 if (!*table)
2413 err = ERROR_NOT_ENOUGH_MEMORY;
2414 goto err;
2417 (*table)->NumEntries = count[0] + count[1];
2418 for (i = 0; i < count[0]; i++)
2420 MIB_IPNET_ROW2 *row = (*table)->Table + i;
2421 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key[0];
2423 ipnet_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn[0] + i );
2426 for (i = 0; i < count[1]; i++)
2428 MIB_IPNET_ROW2 *row = (*table)->Table + count[0] + i;
2429 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key[1];
2431 ipnet_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn[1] + i );
2434 err:
2435 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], NULL );
2436 return err;
2439 /* Gets the DNS server list into the list beginning at list. Assumes that
2440 * a single server address may be placed at list if *len is at least
2441 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2442 * and assumes that all remaining DNS servers are contiguously located
2443 * beginning at second. On input, *len is assumed to be the total number
2444 * of bytes available for all DNS servers, and is ignored if list is NULL.
2445 * On return, *len is set to the total number of bytes required for all DNS
2446 * servers.
2447 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2448 * ERROR_SUCCESS otherwise.
2450 static DWORD get_dns_server_list( const NET_LUID *luid, IP_ADDR_STRING *list, IP_ADDR_STRING *second, DWORD *len )
2452 char buf[FIELD_OFFSET(IP4_ARRAY, AddrArray[3])];
2453 IP4_ARRAY *servers = (IP4_ARRAY *)buf;
2454 DWORD needed, num, err, i, array_len = sizeof(buf);
2455 IP_ADDR_STRING *ptr;
2457 if (luid && luid->Info.IfType == MIB_IF_TYPE_LOOPBACK) return ERROR_NO_DATA;
2459 for (;;)
2461 err = DnsQueryConfig( DnsConfigDnsServerList, 0, NULL, NULL, servers, &array_len );
2462 num = (array_len - FIELD_OFFSET(IP4_ARRAY, AddrArray[0])) / sizeof(IP4_ADDRESS);
2463 needed = num * sizeof(IP_ADDR_STRING);
2464 if (!list || *len < needed)
2466 *len = needed;
2467 err = ERROR_BUFFER_OVERFLOW;
2468 goto err;
2470 if (!err) break;
2472 if ((char *)servers != buf) heap_free( servers );
2473 servers = heap_alloc( array_len );
2474 if (!servers)
2476 err = ERROR_NOT_ENOUGH_MEMORY;
2477 goto err;
2481 *len = needed;
2483 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next)
2485 RtlIpv4AddressToStringA( (IN_ADDR *)&servers->AddrArray[i], ptr->IpAddress.String );
2486 if (i == num - 1) ptr->Next = NULL;
2487 else if (i == 0) ptr->Next = second;
2488 else ptr->Next = ptr + 1;
2491 err:
2492 if ((char *)servers != buf) heap_free( servers );
2493 return err;
2496 /******************************************************************
2497 * GetNetworkParams (IPHLPAPI.@)
2499 * Get the network parameters for the local computer.
2501 * PARAMS
2502 * info [Out] buffer for network parameters
2503 * size [In/Out] length of output buffer
2505 * RETURNS
2506 * Success: NO_ERROR
2507 * Failure: error code from winerror.h
2509 * NOTES
2510 * If size is less than required, the function will return
2511 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2512 * size.
2514 DWORD WINAPI GetNetworkParams( FIXED_INFO *info, ULONG *size )
2516 DWORD needed = sizeof(*info), dns_size, err;
2517 MIB_IPSTATS ip_stats;
2518 HKEY key;
2520 TRACE( "info %p, size %p\n", info, size );
2521 if (!size) return ERROR_INVALID_PARAMETER;
2523 if (get_dns_server_list( NULL, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2524 needed += dns_size - sizeof(IP_ADDR_STRING);
2525 if (!info || *size < needed)
2527 *size = needed;
2528 return ERROR_BUFFER_OVERFLOW;
2531 *size = needed;
2532 memset( info, 0, needed );
2533 needed = sizeof(info->HostName);
2534 GetComputerNameExA( ComputerNameDnsHostname, info->HostName, &needed );
2535 needed = sizeof(info->DomainName);
2536 GetComputerNameExA( ComputerNameDnsDomain, info->DomainName, &needed );
2537 get_dns_server_list( NULL, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2538 info->CurrentDnsServer = &info->DnsServerList;
2539 info->NodeType = HYBRID_NODETYPE;
2540 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2541 0, KEY_READ, &key );
2542 if (err)
2543 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2544 0, KEY_READ, &key );
2545 if (!err)
2547 needed = sizeof(info->ScopeId);
2548 RegQueryValueExA( key, "ScopeID", NULL, NULL, (BYTE *)info->ScopeId, &needed );
2549 RegCloseKey( key );
2552 if (!GetIpStatistics( &ip_stats ))
2553 info->EnableRouting = (ip_stats.u.Forwarding == MIB_IP_FORWARDING);
2555 return ERROR_SUCCESS;
2559 /******************************************************************
2560 * GetNumberOfInterfaces (IPHLPAPI.@)
2562 * Get the number of interfaces.
2564 * PARAMS
2565 * pdwNumIf [Out] number of interfaces
2567 * RETURNS
2568 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2570 DWORD WINAPI GetNumberOfInterfaces( DWORD *count )
2572 DWORD err, num;
2574 TRACE( "count %p\n", count );
2575 if (!count) return ERROR_INVALID_PARAMETER;
2577 err = NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0,
2578 NULL, 0, NULL, 0, NULL, 0, &num );
2579 *count = err ? 0 : num;
2580 return err;
2583 /******************************************************************
2584 * GetPerAdapterInfo (IPHLPAPI.@)
2586 * Get information about an adapter corresponding to an interface.
2588 * PARAMS
2589 * IfIndex [In] interface info
2590 * pPerAdapterInfo [Out] buffer for per adapter info
2591 * pOutBufLen [In/Out] length of output buffer
2593 * RETURNS
2594 * Success: NO_ERROR
2595 * Failure: error code from winerror.h
2597 DWORD WINAPI GetPerAdapterInfo( ULONG index, IP_PER_ADAPTER_INFO *info, ULONG *size )
2599 DWORD needed = sizeof(*info), dns_size;
2600 NET_LUID luid;
2602 TRACE( "(index %d, info %p, size %p)\n", index, info, size );
2604 if (!size) return ERROR_INVALID_PARAMETER;
2605 if (ConvertInterfaceIndexToLuid( index, &luid )) return ERROR_NO_DATA;
2607 if (get_dns_server_list( &luid, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2608 needed += dns_size - sizeof(IP_ADDR_STRING);
2610 if (!info || *size < needed)
2612 *size = needed;
2613 return ERROR_BUFFER_OVERFLOW;
2616 memset( info, 0, needed );
2617 get_dns_server_list( &luid, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2618 info->CurrentDnsServer = &info->DnsServerList;
2620 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2621 return ERROR_SUCCESS;
2625 /******************************************************************
2626 * GetRTTAndHopCount (IPHLPAPI.@)
2628 * Get round-trip time (RTT) and hop count.
2630 * PARAMS
2632 * DestIpAddress [In] destination address to get the info for
2633 * HopCount [Out] retrieved hop count
2634 * MaxHops [In] maximum hops to search for the destination
2635 * RTT [Out] RTT in milliseconds
2637 * RETURNS
2638 * Success: TRUE
2639 * Failure: FALSE
2641 * FIXME
2642 * Stub, returns FALSE.
2644 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2646 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2647 DestIpAddress, HopCount, MaxHops, RTT);
2648 return FALSE;
2652 /******************************************************************
2653 * GetTcpTable (IPHLPAPI.@)
2655 * Get the table of active TCP connections.
2657 * PARAMS
2658 * pTcpTable [Out] buffer for TCP connections table
2659 * pdwSize [In/Out] length of output buffer
2660 * bOrder [In] whether to order the table
2662 * RETURNS
2663 * Success: NO_ERROR
2664 * Failure: error code from winerror.h
2666 * NOTES
2667 * If pdwSize is less than required, the function will return
2668 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2669 * the required byte size.
2670 * If bOrder is true, the returned table will be sorted, first by
2671 * local address and port number, then by remote address and port
2672 * number.
2674 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2676 TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
2677 return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, WS_AF_INET, TCP_TABLE_BASIC_ALL, 0);
2680 /******************************************************************
2681 * GetExtendedTcpTable (IPHLPAPI.@)
2683 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
2684 ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
2686 DWORD ret, size;
2687 void *table;
2689 TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2690 pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2692 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2694 if (TableClass >= TCP_TABLE_OWNER_MODULE_LISTENER)
2695 FIXME("module classes not fully supported\n");
2697 switch (ulAf)
2699 case WS_AF_INET:
2700 ret = build_tcp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2701 break;
2703 case WS_AF_INET6:
2704 ret = build_tcp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2705 break;
2707 default:
2708 FIXME("ulAf = %u not supported\n", ulAf);
2709 ret = ERROR_NOT_SUPPORTED;
2712 if (ret)
2713 return ret;
2715 if (!pTcpTable || *pdwSize < size)
2717 *pdwSize = size;
2718 ret = ERROR_INSUFFICIENT_BUFFER;
2720 else
2722 *pdwSize = size;
2723 memcpy(pTcpTable, table, size);
2725 HeapFree(GetProcessHeap(), 0, table);
2726 return ret;
2729 /******************************************************************
2730 * GetUdpTable (IPHLPAPI.@)
2732 * Get a table of active UDP connections.
2734 * PARAMS
2735 * pUdpTable [Out] buffer for UDP connections table
2736 * pdwSize [In/Out] length of output buffer
2737 * bOrder [In] whether to order the table
2739 * RETURNS
2740 * Success: NO_ERROR
2741 * Failure: error code from winerror.h
2743 * NOTES
2744 * If pdwSize is less than required, the function will return
2745 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
2746 * required byte size.
2747 * If bOrder is true, the returned table will be sorted, first by
2748 * local address, then by local port number.
2750 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2752 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET, UDP_TABLE_BASIC, 0);
2755 /******************************************************************
2756 * GetUdp6Table (IPHLPAPI.@)
2758 DWORD WINAPI GetUdp6Table(PMIB_UDP6TABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2760 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET6, UDP_TABLE_BASIC, 0);
2763 /******************************************************************
2764 * GetExtendedUdpTable (IPHLPAPI.@)
2766 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
2767 ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
2769 DWORD ret, size;
2770 void *table;
2772 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
2773 pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
2775 if (!pdwSize) return ERROR_INVALID_PARAMETER;
2777 if (TableClass == UDP_TABLE_OWNER_MODULE)
2778 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
2780 switch (ulAf)
2782 case WS_AF_INET:
2783 ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2784 break;
2786 case WS_AF_INET6:
2787 ret = build_udp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
2788 break;
2790 default:
2791 FIXME("ulAf = %u not supported\n", ulAf);
2792 ret = ERROR_NOT_SUPPORTED;
2795 if (ret)
2796 return ret;
2798 if (!pUdpTable || *pdwSize < size)
2800 *pdwSize = size;
2801 ret = ERROR_INSUFFICIENT_BUFFER;
2803 else
2805 *pdwSize = size;
2806 memcpy(pUdpTable, table, size);
2808 HeapFree(GetProcessHeap(), 0, table);
2809 return ret;
2812 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW *row, USHORT fam, void *key, struct nsi_ip_unicast_rw *rw,
2813 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
2815 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key;
2816 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key;
2818 if (fam == WS_AF_INET)
2820 row->Address.Ipv4.sin_family = fam;
2821 row->Address.Ipv4.sin_port = 0;
2822 row->Address.Ipv4.sin_addr = key4->addr;
2823 memset( row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
2824 row->InterfaceLuid.Value = key4->luid.Value;
2826 else
2828 row->Address.Ipv6.sin6_family = fam;
2829 row->Address.Ipv6.sin6_port = 0;
2830 row->Address.Ipv6.sin6_flowinfo = 0;
2831 row->Address.Ipv6.sin6_addr = key6->addr;
2832 row->Address.Ipv6.sin6_scope_id = dyn->scope_id;
2833 row->InterfaceLuid.Value = key6->luid.Value;
2836 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
2837 row->PrefixOrigin = rw->prefix_origin;
2838 row->SuffixOrigin = rw->suffix_origin;
2839 row->ValidLifetime = rw->valid_lifetime;
2840 row->PreferredLifetime = rw->preferred_lifetime;
2841 row->OnLinkPrefixLength = rw->on_link_prefix;
2842 row->SkipAsSource = 0;
2843 row->DadState = dyn->dad_state;
2844 row->ScopeId.u.Value = dyn->scope_id;
2845 row->CreationTimeStamp.QuadPart = stat->creation_time;
2848 DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW *row)
2850 struct nsi_ipv4_unicast_key key4;
2851 struct nsi_ipv6_unicast_key key6;
2852 struct nsi_ip_unicast_rw rw;
2853 struct nsi_ip_unicast_dynamic dyn;
2854 struct nsi_ip_unicast_static stat;
2855 const NPI_MODULEID *mod;
2856 DWORD err, key_size;
2857 void *key;
2859 TRACE( "%p\n", row );
2861 if (!row) return ERROR_INVALID_PARAMETER;
2862 mod = ip_module_id( row->Address.si_family );
2863 if (!mod) return ERROR_INVALID_PARAMETER;
2865 if (!row->InterfaceLuid.Value)
2867 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
2868 if (err) return err;
2871 if (row->Address.si_family == WS_AF_INET)
2873 key4.luid = row->InterfaceLuid;
2874 key4.addr = row->Address.Ipv4.sin_addr;
2875 key4.pad = 0;
2876 key = &key4;
2877 key_size = sizeof(key4);
2879 else if (row->Address.si_family == WS_AF_INET6)
2881 key6.luid = row->InterfaceLuid;
2882 key6.addr = row->Address.Ipv6.sin6_addr;
2883 key = &key6;
2884 key_size = sizeof(key6);
2886 else return ERROR_INVALID_PARAMETER;
2888 err = NsiGetAllParameters( 1, mod, NSI_IP_UNICAST_TABLE, key, key_size, &rw, sizeof(rw),
2889 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2890 if (!err) unicast_row_fill( row, row->Address.si_family, key, &rw, &dyn, &stat );
2891 return err;
2894 DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY family, MIB_UNICASTIPADDRESS_TABLE **table)
2896 void *key[2] = { NULL, NULL };
2897 struct nsi_ip_unicast_rw *rw[2] = { NULL, NULL };
2898 struct nsi_ip_unicast_dynamic *dyn[2] = { NULL, NULL };
2899 struct nsi_ip_unicast_static *stat[2] = { NULL, NULL };
2900 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
2901 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ipv6_unicast_key) };
2902 DWORD err, i, size, count[2] = { 0, 0 };
2904 TRACE( "%u, %p\n", family, table );
2906 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2907 return ERROR_INVALID_PARAMETER;
2909 for (i = 0; i < 2; i++)
2911 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
2913 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_UNICAST_TABLE, key + i, key_size[i],
2914 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
2915 (void **)stat + i, sizeof(**stat), count + i, 0 );
2916 if (err) goto err;
2919 size = FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE, Table[ count[0] + count[1] ]);
2920 *table = heap_alloc( size );
2921 if (!*table)
2923 err = ERROR_NOT_ENOUGH_MEMORY;
2924 goto err;
2927 (*table)->NumEntries = count[0] + count[1];
2928 for (i = 0; i < count[0]; i++)
2930 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + i;
2931 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key[0];
2933 unicast_row_fill( row, fam[0], (void *)(key4 + i), rw[0] + i, dyn[0] + i, stat[0] + i );
2936 for (i = 0; i < count[1]; i++)
2938 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + count[0] + i;
2939 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key[1];
2941 unicast_row_fill( row, fam[1], (void *)(key6 + i), rw[1] + i, dyn[1] + i, stat[1] + i );
2944 err:
2945 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
2946 return err;
2949 /******************************************************************
2950 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2952 * This is a Win98-only function to get information on "unidirectional"
2953 * adapters. Since this is pretty nonsensical in other contexts, it
2954 * never returns anything.
2956 * PARAMS
2957 * pIPIfInfo [Out] buffer for adapter infos
2958 * dwOutBufLen [Out] length of the output buffer
2960 * RETURNS
2961 * Success: NO_ERROR
2962 * Failure: error code from winerror.h
2964 * FIXME
2965 * Stub, returns ERROR_NOT_SUPPORTED.
2967 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2969 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2970 /* a unidirectional adapter?? not bloody likely! */
2971 return ERROR_NOT_SUPPORTED;
2975 /******************************************************************
2976 * IpReleaseAddress (IPHLPAPI.@)
2978 * Release an IP obtained through DHCP,
2980 * PARAMS
2981 * AdapterInfo [In] adapter to release IP address
2983 * RETURNS
2984 * Success: NO_ERROR
2985 * Failure: error code from winerror.h
2987 * NOTES
2988 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2989 * this function does nothing.
2991 * FIXME
2992 * Stub, returns ERROR_NOT_SUPPORTED.
2994 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2996 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2997 return ERROR_NOT_SUPPORTED;
3001 /******************************************************************
3002 * IpRenewAddress (IPHLPAPI.@)
3004 * Renew an IP obtained through DHCP.
3006 * PARAMS
3007 * AdapterInfo [In] adapter to renew IP address
3009 * RETURNS
3010 * Success: NO_ERROR
3011 * Failure: error code from winerror.h
3013 * NOTES
3014 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3015 * this function does nothing.
3017 * FIXME
3018 * Stub, returns ERROR_NOT_SUPPORTED.
3020 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3022 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3023 return ERROR_NOT_SUPPORTED;
3027 /******************************************************************
3028 * NotifyAddrChange (IPHLPAPI.@)
3030 * Notify caller whenever the ip-interface map is changed.
3032 * PARAMS
3033 * Handle [Out] handle usable in asynchronous notification
3034 * overlapped [In] overlapped structure that notifies the caller
3036 * RETURNS
3037 * Success: NO_ERROR
3038 * Failure: error code from winerror.h
3040 * FIXME
3041 * Stub, returns ERROR_NOT_SUPPORTED.
3043 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3045 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3046 if (Handle) *Handle = INVALID_HANDLE_VALUE;
3047 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
3048 return ERROR_IO_PENDING;
3052 /******************************************************************
3053 * NotifyIpInterfaceChange (IPHLPAPI.@)
3055 DWORD WINAPI NotifyIpInterfaceChange(ADDRESS_FAMILY family, PIPINTERFACE_CHANGE_CALLBACK callback,
3056 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3058 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3059 family, callback, context, init_notify, handle);
3060 if (handle) *handle = NULL;
3061 return NO_ERROR;
3064 /******************************************************************
3065 * NotifyRouteChange2 (IPHLPAPI.@)
3067 DWORD WINAPI NotifyRouteChange2(ADDRESS_FAMILY family, PIPFORWARD_CHANGE_CALLBACK callback, VOID* context,
3068 BOOLEAN init_notify, HANDLE* handle)
3070 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3071 family, callback, context, init_notify, handle);
3072 if (handle) *handle = NULL;
3073 return NO_ERROR;
3077 /******************************************************************
3078 * NotifyRouteChange (IPHLPAPI.@)
3080 * Notify caller whenever the ip routing table is changed.
3082 * PARAMS
3083 * Handle [Out] handle usable in asynchronous notification
3084 * overlapped [In] overlapped structure that notifies the caller
3086 * RETURNS
3087 * Success: NO_ERROR
3088 * Failure: error code from winerror.h
3090 * FIXME
3091 * Stub, returns ERROR_NOT_SUPPORTED.
3093 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3095 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3096 return ERROR_NOT_SUPPORTED;
3100 /******************************************************************
3101 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3103 DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback,
3104 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3106 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3107 family, callback, context, init_notify, handle);
3108 if (handle) *handle = NULL;
3110 if (init_notify)
3111 callback(context, NULL, MibInitialNotification);
3113 return NO_ERROR;
3116 /******************************************************************
3117 * SendARP (IPHLPAPI.@)
3119 * Send an ARP request.
3121 * PARAMS
3122 * DestIP [In] attempt to obtain this IP
3123 * SrcIP [In] optional sender IP address
3124 * pMacAddr [Out] buffer for the mac address
3125 * PhyAddrLen [In/Out] length of the output buffer
3127 * RETURNS
3128 * Success: NO_ERROR
3129 * Failure: error code from winerror.h
3131 * FIXME
3132 * Stub, returns ERROR_NOT_SUPPORTED.
3134 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
3136 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
3137 DestIP, SrcIP, pMacAddr, PhyAddrLen);
3138 return ERROR_NOT_SUPPORTED;
3142 /******************************************************************
3143 * SetIfEntry (IPHLPAPI.@)
3145 * Set the administrative status of an interface.
3147 * PARAMS
3148 * pIfRow [In] dwAdminStatus member specifies the new status.
3150 * RETURNS
3151 * Success: NO_ERROR
3152 * Failure: error code from winerror.h
3154 * FIXME
3155 * Stub, returns ERROR_NOT_SUPPORTED.
3157 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
3159 FIXME("(pIfRow %p): stub\n", pIfRow);
3160 /* this is supposed to set an interface administratively up or down.
3161 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3162 this sort of down is indistinguishable from other sorts of down (e.g. no
3163 link). */
3164 return ERROR_NOT_SUPPORTED;
3168 /******************************************************************
3169 * SetIpForwardEntry (IPHLPAPI.@)
3171 * Modify an existing route.
3173 * PARAMS
3174 * pRoute [In] route with the new information
3176 * RETURNS
3177 * Success: NO_ERROR
3178 * Failure: error code from winerror.h
3180 * FIXME
3181 * Stub, returns NO_ERROR.
3183 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
3185 FIXME("(pRoute %p): stub\n", pRoute);
3186 /* this is to add a route entry, how's it distinguishable from
3187 CreateIpForwardEntry?
3188 could use SIOCADDRT, not sure I want to */
3189 return 0;
3193 /******************************************************************
3194 * SetIpNetEntry (IPHLPAPI.@)
3196 * Modify an existing ARP entry.
3198 * PARAMS
3199 * pArpEntry [In] ARP entry with the new information
3201 * RETURNS
3202 * Success: NO_ERROR
3203 * Failure: error code from winerror.h
3205 * FIXME
3206 * Stub, returns NO_ERROR.
3208 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3210 FIXME("(pArpEntry %p): stub\n", pArpEntry);
3211 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3212 return 0;
3216 /******************************************************************
3217 * SetIpStatistics (IPHLPAPI.@)
3219 * Toggle IP forwarding and det the default TTL value.
3221 * PARAMS
3222 * pIpStats [In] IP statistics with the new information
3224 * RETURNS
3225 * Success: NO_ERROR
3226 * Failure: error code from winerror.h
3228 * FIXME
3229 * Stub, returns NO_ERROR.
3231 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3233 FIXME("(pIpStats %p): stub\n", pIpStats);
3234 return 0;
3238 /******************************************************************
3239 * SetIpTTL (IPHLPAPI.@)
3241 * Set the default TTL value.
3243 * PARAMS
3244 * nTTL [In] new TTL value
3246 * RETURNS
3247 * Success: NO_ERROR
3248 * Failure: error code from winerror.h
3250 * FIXME
3251 * Stub, returns NO_ERROR.
3253 DWORD WINAPI SetIpTTL(UINT nTTL)
3255 FIXME("(nTTL %d): stub\n", nTTL);
3256 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
3257 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
3258 return 0;
3262 /******************************************************************
3263 * SetTcpEntry (IPHLPAPI.@)
3265 * Set the state of a TCP connection.
3267 * PARAMS
3268 * pTcpRow [In] specifies connection with new state
3270 * RETURNS
3271 * Success: NO_ERROR
3272 * Failure: error code from winerror.h
3274 * FIXME
3275 * Stub, returns NO_ERROR.
3277 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3279 FIXME("(pTcpRow %p): stub\n", pTcpRow);
3280 return 0;
3283 /******************************************************************
3284 * SetPerTcpConnectionEStats (IPHLPAPI.@)
3286 DWORD WINAPI SetPerTcpConnectionEStats(PMIB_TCPROW row, TCP_ESTATS_TYPE state, PBYTE rw,
3287 ULONG version, ULONG size, ULONG offset)
3289 FIXME("(row %p, state %d, rw %p, version %u, size %u, offset %u): stub\n",
3290 row, state, rw, version, size, offset);
3291 return ERROR_NOT_SUPPORTED;
3295 /******************************************************************
3296 * UnenableRouter (IPHLPAPI.@)
3298 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3299 * if it reaches zero.
3301 * PARAMS
3302 * pOverlapped [In/Out] should be the same as in EnableRouter()
3303 * lpdwEnableCount [Out] optional, receives reference count
3305 * RETURNS
3306 * Success: NO_ERROR
3307 * Failure: error code from winerror.h
3309 * FIXME
3310 * Stub, returns ERROR_NOT_SUPPORTED.
3312 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3314 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3315 lpdwEnableCount);
3316 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
3317 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
3319 return ERROR_NOT_SUPPORTED;
3322 /******************************************************************
3323 * PfCreateInterface (IPHLPAPI.@)
3325 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
3326 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
3328 FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
3329 return ERROR_CALL_NOT_IMPLEMENTED;
3332 /******************************************************************
3333 * PfUnBindInterface (IPHLPAPI.@)
3335 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
3337 FIXME("(%p) stub\n", interface);
3338 return ERROR_CALL_NOT_IMPLEMENTED;
3341 /******************************************************************
3342 * PfDeleteInterface(IPHLPAPI.@)
3344 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
3346 FIXME("(%p) stub\n", interface);
3347 return ERROR_CALL_NOT_IMPLEMENTED;
3350 /******************************************************************
3351 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
3353 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
3355 FIXME("(%p %d %p) stub\n", interface, type, ip);
3356 return ERROR_CALL_NOT_IMPLEMENTED;
3359 /******************************************************************
3360 * GetTcpTable2 (IPHLPAPI.@)
3362 ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
3364 FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
3365 return ERROR_NOT_SUPPORTED;
3368 /******************************************************************
3369 * GetTcp6Table (IPHLPAPI.@)
3371 ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
3373 TRACE("(table %p, size %p, order %d)\n", table, size, order);
3374 return GetExtendedTcpTable(table, size, order, WS_AF_INET6, TCP_TABLE_BASIC_ALL, 0);
3377 /******************************************************************
3378 * GetTcp6Table2 (IPHLPAPI.@)
3380 ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
3382 FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
3383 return ERROR_NOT_SUPPORTED;
3386 /******************************************************************
3387 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
3389 DWORD WINAPI ConvertInterfaceAliasToLuid( const WCHAR *alias, NET_LUID *luid )
3391 struct nsi_ndis_ifinfo_rw *data;
3392 DWORD err, count, i, len;
3393 NET_LUID *keys;
3395 TRACE( "(%s %p)\n", debugstr_w(alias), luid );
3397 if (!alias || !*alias || !luid) return ERROR_INVALID_PARAMETER;
3398 luid->Value = 0;
3399 len = strlenW( alias );
3401 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3402 (void **)&data, sizeof(*data), NULL, 0, NULL, 0, &count, 0 );
3403 if (err) return err;
3405 err = ERROR_INVALID_PARAMETER;
3406 for (i = 0; i < count; i++)
3408 if (data[i].alias.Length == len * 2 && !memcmp( data[i].alias.String, alias, len * 2 ))
3410 luid->Value = keys[i].Value;
3411 err = ERROR_SUCCESS;
3412 break;
3415 NsiFreeTable( keys, data, NULL, NULL );
3416 return err;
3419 /******************************************************************
3420 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
3422 DWORD WINAPI ConvertInterfaceGuidToLuid(const GUID *guid, NET_LUID *luid)
3424 struct nsi_ndis_ifinfo_static *data;
3425 DWORD err, count, i;
3426 NET_LUID *keys;
3428 TRACE( "(%s %p)\n", debugstr_guid(guid), luid );
3430 if (!guid || !luid) return ERROR_INVALID_PARAMETER;
3431 luid->Value = 0;
3433 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3434 NULL, 0, NULL, 0, (void **)&data, sizeof(*data), &count, 0 );
3435 if (err) return err;
3437 err = ERROR_INVALID_PARAMETER;
3438 for (i = 0; i < count; i++)
3440 if (IsEqualGUID( &data[i].if_guid, guid ))
3442 luid->Value = keys[i].Value;
3443 err = ERROR_SUCCESS;
3444 break;
3447 NsiFreeTable( keys, NULL, NULL, data );
3448 return err;
3451 /******************************************************************
3452 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
3454 DWORD WINAPI ConvertInterfaceIndexToLuid(NET_IFINDEX index, NET_LUID *luid)
3456 DWORD err;
3458 TRACE( "(%u %p)\n", index, luid );
3460 if (!luid) return ERROR_INVALID_PARAMETER;
3462 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &index, sizeof(index),
3463 NSI_PARAM_TYPE_STATIC, luid, sizeof(*luid), 0 );
3464 if (err) luid->Value = 0;
3465 return err;
3468 /******************************************************************
3469 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
3471 DWORD WINAPI ConvertInterfaceLuidToAlias( const NET_LUID *luid, WCHAR *alias, SIZE_T len )
3473 DWORD err;
3474 IF_COUNTED_STRING name;
3476 TRACE( "(%p %p %u)\n", luid, alias, (DWORD)len );
3478 if (!luid || !alias) return ERROR_INVALID_PARAMETER;
3480 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3481 NSI_PARAM_TYPE_RW, &name, sizeof(name),
3482 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw, alias) );
3483 if (err) return err;
3485 if (len <= name.Length / sizeof(WCHAR)) return ERROR_NOT_ENOUGH_MEMORY;
3486 memcpy( alias, name.String, name.Length );
3487 alias[name.Length / sizeof(WCHAR)] = '\0';
3489 return err;
3492 /******************************************************************
3493 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
3495 DWORD WINAPI ConvertInterfaceLuidToGuid(const NET_LUID *luid, GUID *guid)
3497 DWORD err;
3499 TRACE( "(%p %p)\n", luid, guid );
3501 if (!luid || !guid) return ERROR_INVALID_PARAMETER;
3503 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3504 NSI_PARAM_TYPE_STATIC, guid, sizeof(*guid),
3505 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_guid) );
3506 if (err) memset( guid, 0, sizeof(*guid) );
3507 return err;
3510 /******************************************************************
3511 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
3513 DWORD WINAPI ConvertInterfaceLuidToIndex(const NET_LUID *luid, NET_IFINDEX *index)
3515 DWORD err;
3517 TRACE( "(%p %p)\n", luid, index );
3519 if (!luid || !index) return ERROR_INVALID_PARAMETER;
3521 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
3522 NSI_PARAM_TYPE_STATIC, index, sizeof(*index),
3523 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index) );
3524 if (err) *index = 0;
3525 return err;
3528 /******************************************************************
3529 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
3531 DWORD WINAPI ConvertInterfaceLuidToNameA(const NET_LUID *luid, char *name, SIZE_T len)
3533 DWORD err;
3534 WCHAR nameW[IF_MAX_STRING_SIZE + 1];
3536 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
3538 if (!luid) return ERROR_INVALID_PARAMETER;
3539 if (!name || !len) return ERROR_NOT_ENOUGH_MEMORY;
3541 err = ConvertInterfaceLuidToNameW( luid, nameW, ARRAY_SIZE(nameW) );
3542 if (err) return err;
3544 if (!WideCharToMultiByte( CP_UNIXCP, 0, nameW, -1, name, len, NULL, NULL ))
3545 err = GetLastError();
3546 return err;
3549 static const WCHAR otherW[] = {'o','t','h','e','r',0};
3550 static const WCHAR ethernetW[] = {'e','t','h','e','r','n','e','t',0};
3551 static const WCHAR tokenringW[] = {'t','o','k','e','n','r','i','n','g',0};
3552 static const WCHAR pppW[] = {'p','p','p',0};
3553 static const WCHAR loopbackW[] = {'l','o','o','p','b','a','c','k',0};
3554 static const WCHAR atmW[] = {'a','t','m',0};
3555 static const WCHAR wirelessW[] = {'w','i','r','e','l','e','s','s',0};
3556 static const WCHAR tunnelW[] = {'t','u','n','n','e','l',0};
3557 static const WCHAR ieee1394W[] = {'i','e','e','e','1','3','9','4',0};
3559 struct name_prefix
3561 const WCHAR *prefix;
3562 DWORD type;
3564 static const struct name_prefix name_prefixes[] =
3566 { otherW, IF_TYPE_OTHER },
3567 { ethernetW, IF_TYPE_ETHERNET_CSMACD },
3568 { tokenringW, IF_TYPE_ISO88025_TOKENRING },
3569 { pppW, IF_TYPE_PPP },
3570 { loopbackW, IF_TYPE_SOFTWARE_LOOPBACK },
3571 { atmW, IF_TYPE_ATM },
3572 { wirelessW, IF_TYPE_IEEE80211 },
3573 { tunnelW, IF_TYPE_TUNNEL },
3574 { ieee1394W, IF_TYPE_IEEE1394 }
3577 /******************************************************************
3578 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
3580 DWORD WINAPI ConvertInterfaceLuidToNameW(const NET_LUID *luid, WCHAR *name, SIZE_T len)
3582 DWORD i, needed;
3583 const WCHAR *prefix = NULL;
3584 WCHAR buf[IF_MAX_STRING_SIZE + 1];
3585 static const WCHAR prefix_fmt[] = {'%','s','_','%','d',0};
3586 static const WCHAR unk_fmt[] = {'i','f','t','y','p','e','%','d','_','%','d',0};
3588 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
3590 if (!luid || !name) return ERROR_INVALID_PARAMETER;
3592 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
3594 if (luid->Info.IfType == name_prefixes[i].type)
3596 prefix = name_prefixes[i].prefix;
3597 break;
3601 if (prefix) needed = snprintfW( buf, len, prefix_fmt, prefix, luid->Info.NetLuidIndex );
3602 else needed = snprintfW( buf, len, unk_fmt, luid->Info.IfType, luid->Info.NetLuidIndex );
3604 if (needed >= len) return ERROR_NOT_ENOUGH_MEMORY;
3605 memcpy( name, buf, (needed + 1) * sizeof(WCHAR) );
3606 return ERROR_SUCCESS;
3609 /******************************************************************
3610 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
3612 DWORD WINAPI ConvertInterfaceNameToLuidA(const char *name, NET_LUID *luid)
3614 WCHAR nameW[IF_MAX_STRING_SIZE];
3616 TRACE( "(%s %p)\n", debugstr_a(name), luid );
3618 if (!name) return ERROR_INVALID_NAME;
3619 if (!MultiByteToWideChar( CP_UNIXCP, 0, name, -1, nameW, ARRAY_SIZE(nameW) ))
3620 return GetLastError();
3622 return ConvertInterfaceNameToLuidW( nameW, luid );
3625 /******************************************************************
3626 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
3628 DWORD WINAPI ConvertInterfaceNameToLuidW(const WCHAR *name, NET_LUID *luid)
3630 const WCHAR *sep;
3631 static const WCHAR iftype[] = {'i','f','t','y','p','e',0};
3632 DWORD type = ~0u, i;
3633 WCHAR buf[IF_MAX_STRING_SIZE + 1];
3635 TRACE( "(%s %p)\n", debugstr_w(name), luid );
3637 if (!luid) return ERROR_INVALID_PARAMETER;
3638 memset( luid, 0, sizeof(*luid) );
3640 if (!name || !(sep = strchrW( name, '_' )) || sep >= name + ARRAY_SIZE(buf)) return ERROR_INVALID_NAME;
3641 memcpy( buf, name, (sep - name) * sizeof(WCHAR) );
3642 buf[sep - name] = '\0';
3644 if (sep - name > ARRAY_SIZE(iftype) - 1 && !memcmp( buf, iftype, (ARRAY_SIZE(iftype) - 1) * sizeof(WCHAR) ))
3646 type = atoiW( buf + ARRAY_SIZE(iftype) - 1 );
3648 else
3650 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
3652 if (!strcmpW( buf, name_prefixes[i].prefix ))
3654 type = name_prefixes[i].type;
3655 break;
3659 if (type == ~0u) return ERROR_INVALID_NAME;
3661 luid->Info.NetLuidIndex = atoiW( sep + 1 );
3662 luid->Info.IfType = type;
3663 return ERROR_SUCCESS;
3666 /******************************************************************
3667 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
3669 DWORD WINAPI ConvertLengthToIpv4Mask(ULONG mask_len, ULONG *mask)
3671 if (mask_len > 32)
3673 *mask = INADDR_NONE;
3674 return ERROR_INVALID_PARAMETER;
3677 if (mask_len == 0)
3678 *mask = 0;
3679 else
3680 *mask = htonl(~0u << (32 - mask_len));
3682 return NO_ERROR;
3685 /******************************************************************
3686 * if_nametoindex (IPHLPAPI.@)
3688 IF_INDEX WINAPI IPHLP_if_nametoindex(const char *name)
3690 IF_INDEX index;
3691 NET_LUID luid;
3692 DWORD err;
3694 TRACE( "(%s)\n", name );
3696 err = ConvertInterfaceNameToLuidA( name, &luid );
3697 if (err) return 0;
3699 err = ConvertInterfaceLuidToIndex( &luid, &index );
3700 if (err) index = 0;
3701 return index;
3704 /******************************************************************
3705 * if_indextoname (IPHLPAPI.@)
3707 char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
3709 NET_LUID luid;
3710 DWORD err;
3712 TRACE( "(%u, %p)\n", index, name );
3714 err = ConvertInterfaceIndexToLuid( index, &luid );
3715 if (err) return NULL;
3717 err = ConvertInterfaceLuidToNameA( &luid, name, IF_MAX_STRING_SIZE );
3718 if (err) return NULL;
3719 return name;
3722 /******************************************************************
3723 * GetIpInterfaceTable (IPHLPAPI.@)
3725 DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table)
3727 FIXME("(%u %p): stub\n", family, table);
3728 return ERROR_NOT_SUPPORTED;
3731 /******************************************************************
3732 * GetBestRoute2 (IPHLPAPI.@)
3734 DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
3735 const SOCKADDR_INET *source, const SOCKADDR_INET *destination,
3736 ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
3737 SOCKADDR_INET *bestaddress)
3739 static int once;
3741 if (!once++)
3742 FIXME("(%p, %d, %p, %p, 0x%08x, %p, %p): stub\n", luid, index, source,
3743 destination, options, bestroute, bestaddress);
3745 if (!destination || !bestroute || !bestaddress)
3746 return ERROR_INVALID_PARAMETER;
3748 return ERROR_NOT_SUPPORTED;
3751 /******************************************************************
3752 * ParseNetworkString (IPHLPAPI.@)
3754 DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
3755 NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len)
3757 IN_ADDR temp_addr4;
3758 IN6_ADDR temp_addr6;
3759 ULONG temp_scope;
3760 USHORT temp_port = 0;
3761 NTSTATUS status;
3763 TRACE("(%s, %d, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len);
3765 if (!str)
3766 return ERROR_INVALID_PARAMETER;
3768 if (type & NET_STRING_IPV4_ADDRESS)
3770 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
3771 if (SUCCEEDED(status) && !temp_port)
3773 if (info)
3775 info->Format = NET_ADDRESS_IPV4;
3776 info->u.Ipv4Address.sin_addr = temp_addr4;
3777 info->u.Ipv4Address.sin_port = 0;
3779 if (port) *port = 0;
3780 if (prefix_len) *prefix_len = 255;
3781 return ERROR_SUCCESS;
3784 if (type & NET_STRING_IPV4_SERVICE)
3786 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
3787 if (SUCCEEDED(status) && temp_port)
3789 if (info)
3791 info->Format = NET_ADDRESS_IPV4;
3792 info->u.Ipv4Address.sin_addr = temp_addr4;
3793 info->u.Ipv4Address.sin_port = temp_port;
3795 if (port) *port = ntohs(temp_port);
3796 if (prefix_len) *prefix_len = 255;
3797 return ERROR_SUCCESS;
3800 if (type & NET_STRING_IPV6_ADDRESS)
3802 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
3803 if (SUCCEEDED(status) && !temp_port)
3805 if (info)
3807 info->Format = NET_ADDRESS_IPV6;
3808 info->u.Ipv6Address.sin6_addr = temp_addr6;
3809 info->u.Ipv6Address.sin6_scope_id = temp_scope;
3810 info->u.Ipv6Address.sin6_port = 0;
3812 if (port) *port = 0;
3813 if (prefix_len) *prefix_len = 255;
3814 return ERROR_SUCCESS;
3817 if (type & NET_STRING_IPV6_SERVICE)
3819 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
3820 if (SUCCEEDED(status) && temp_port)
3822 if (info)
3824 info->Format = NET_ADDRESS_IPV6;
3825 info->u.Ipv6Address.sin6_addr = temp_addr6;
3826 info->u.Ipv6Address.sin6_scope_id = temp_scope;
3827 info->u.Ipv6Address.sin6_port = temp_port;
3829 if (port) *port = ntohs(temp_port);
3830 if (prefix_len) *prefix_len = 255;
3831 return ERROR_SUCCESS;
3835 if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED;
3837 if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_ADDRESS|NET_STRING_IPV6_SERVICE))
3839 FIXME("Unimplemented type 0x%x\n", type);
3840 return ERROR_NOT_SUPPORTED;
3843 return ERROR_INVALID_PARAMETER;