iphlpapi: Implement AllocateAndGetTcp(Ex)TableFromStack() on top of nsi.
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blobe78689d8f11b98accd2413b7ef6201ffb88ad192
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 icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX *stats_ex, MIBICMPSTATS *stats )
1500 stats->dwMsgs = stats_ex->dwMsgs;
1501 stats->dwErrors = stats_ex->dwErrors;
1502 stats->dwDestUnreachs = stats_ex->rgdwTypeCount[ICMP4_DST_UNREACH];
1503 stats->dwTimeExcds = stats_ex->rgdwTypeCount[ICMP4_TIME_EXCEEDED];
1504 stats->dwParmProbs = stats_ex->rgdwTypeCount[ICMP4_PARAM_PROB];
1505 stats->dwSrcQuenchs = stats_ex->rgdwTypeCount[ICMP4_SOURCE_QUENCH];
1506 stats->dwRedirects = stats_ex->rgdwTypeCount[ICMP4_REDIRECT];
1507 stats->dwEchos = stats_ex->rgdwTypeCount[ICMP4_ECHO_REQUEST];
1508 stats->dwEchoReps = stats_ex->rgdwTypeCount[ICMP4_ECHO_REPLY];
1509 stats->dwTimestamps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST];
1510 stats->dwTimestampReps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REPLY];
1511 stats->dwAddrMasks = stats_ex->rgdwTypeCount[ICMP4_MASK_REQUEST];
1512 stats->dwAddrMaskReps = stats_ex->rgdwTypeCount[ICMP4_MASK_REPLY];
1515 /******************************************************************
1516 * GetIcmpStatistics (IPHLPAPI.@)
1518 * Get the ICMP statistics for the local computer.
1520 * PARAMS
1521 * stats [Out] buffer for ICMP statistics
1523 * RETURNS
1524 * Success: NO_ERROR
1525 * Failure: error code from winerror.h
1527 DWORD WINAPI GetIcmpStatistics( MIB_ICMP *stats )
1529 MIB_ICMP_EX stats_ex;
1530 DWORD err = GetIcmpStatisticsEx( &stats_ex, WS_AF_INET );
1532 if (err) return err;
1534 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpInStats, &stats->stats.icmpInStats );
1535 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpOutStats, &stats->stats.icmpOutStats );
1536 return err;
1539 /******************************************************************
1540 * GetIcmpStatisticsEx (IPHLPAPI.@)
1542 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1544 * PARAMS
1545 * stats [Out] buffer for ICMP statistics
1546 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1548 * RETURNS
1549 * Success: NO_ERROR
1550 * Failure: error code from winerror.h
1552 DWORD WINAPI GetIcmpStatisticsEx( MIB_ICMP_EX *stats, DWORD family )
1554 const NPI_MODULEID *mod = ip_module_id( family );
1555 struct nsi_ip_icmpstats_dynamic dyn;
1556 DWORD err;
1558 if (!stats || !mod) return ERROR_INVALID_PARAMETER;
1559 memset( stats, 0, sizeof(*stats) );
1561 err = NsiGetAllParameters( 1, mod, NSI_IP_ICMPSTATS_TABLE, NULL, 0, NULL, 0,
1562 &dyn, sizeof(dyn), NULL, 0 );
1563 if (err) return err;
1565 stats->icmpInStats.dwMsgs = dyn.in_msgs;
1566 stats->icmpInStats.dwErrors = dyn.in_errors;
1567 memcpy( stats->icmpInStats.rgdwTypeCount, dyn.in_type_counts, sizeof( dyn.in_type_counts ) );
1568 stats->icmpOutStats.dwMsgs = dyn.out_msgs;
1569 stats->icmpOutStats.dwErrors = dyn.out_errors;
1570 memcpy( stats->icmpOutStats.rgdwTypeCount, dyn.out_type_counts, sizeof( dyn.out_type_counts ) );
1572 return ERROR_SUCCESS;
1575 static void if_row_fill( MIB_IFROW *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1576 struct nsi_ndis_ifinfo_static *stat )
1578 static const WCHAR name_prefix[] = {'\\','D','E','V','I','C','E','\\','T','C','P','I','P','_',0};
1580 memcpy( row->wszName, name_prefix, sizeof(name_prefix) );
1581 ConvertGuidToStringW( &stat->if_guid, row->wszName + ARRAY_SIZE(name_prefix) - 1, CHARS_IN_GUID );
1582 row->dwIndex = stat->if_index;
1583 row->dwType = stat->type;
1584 row->dwMtu = dyn->mtu;
1585 row->dwSpeed = dyn->rcv_speed;
1586 row->dwPhysAddrLen = rw->phys_addr.Length;
1587 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
1588 memcpy( row->bPhysAddr, rw->phys_addr.Address, row->dwPhysAddrLen );
1589 row->dwAdminStatus = rw->admin_status;
1590 row->dwOperStatus = (dyn->oper_status == IfOperStatusUp) ? MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_NON_OPERATIONAL;
1591 row->dwLastChange = 0;
1592 row->dwInOctets = dyn->in_octets;
1593 row->dwInUcastPkts = dyn->in_ucast_pkts;
1594 row->dwInNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1595 row->dwInDiscards = dyn->in_discards;
1596 row->dwInErrors = dyn->in_errors;
1597 row->dwInUnknownProtos = 0;
1598 row->dwOutOctets = dyn->out_octets;
1599 row->dwOutUcastPkts = dyn->out_ucast_pkts;
1600 row->dwOutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1601 row->dwOutDiscards = dyn->out_discards;
1602 row->dwOutErrors = dyn->out_errors;
1603 row->dwOutQLen = 0;
1604 row->dwDescrLen = WideCharToMultiByte( CP_ACP, 0, stat->descr.String, stat->descr.Length / sizeof(WCHAR),
1605 (char *)row->bDescr, sizeof(row->bDescr) - 1, NULL, NULL );
1606 row->bDescr[row->dwDescrLen] = '\0';
1609 /******************************************************************
1610 * GetIfEntry (IPHLPAPI.@)
1612 * Get information about an interface.
1614 * PARAMS
1615 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1616 * Out: interface information
1618 * RETURNS
1619 * Success: NO_ERROR
1620 * Failure: error code from winerror.h
1622 DWORD WINAPI GetIfEntry( MIB_IFROW *row )
1624 struct nsi_ndis_ifinfo_rw rw;
1625 struct nsi_ndis_ifinfo_dynamic dyn;
1626 struct nsi_ndis_ifinfo_static stat;
1627 NET_LUID luid;
1628 DWORD err;
1630 TRACE( "row %p\n", row );
1631 if (!row) return ERROR_INVALID_PARAMETER;
1633 err = ConvertInterfaceIndexToLuid( row->dwIndex, &luid );
1634 if (err) return err;
1636 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1637 &luid, sizeof(luid), &rw, sizeof(rw),
1638 &dyn, sizeof(dyn), &stat, sizeof(stat) );
1639 if (!err) if_row_fill( row, &rw, &dyn, &stat );
1640 return err;
1643 static int ifrow_cmp( const void *a, const void *b )
1645 return ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1648 /******************************************************************
1649 * GetIfTable (IPHLPAPI.@)
1651 * Get a table of local interfaces.
1653 * PARAMS
1654 * table [Out] buffer for local interfaces table
1655 * size [In/Out] length of output buffer
1656 * sort [In] whether to sort the table
1658 * RETURNS
1659 * Success: NO_ERROR
1660 * Failure: error code from winerror.h
1662 * NOTES
1663 * If size is less than required, the function will return
1664 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1665 * size.
1666 * If sort is true, the returned table will be sorted by interface index.
1668 DWORD WINAPI GetIfTable( MIB_IFTABLE *table, ULONG *size, BOOL sort )
1670 DWORD i, count, needed, err;
1671 NET_LUID *keys;
1672 struct nsi_ndis_ifinfo_rw *rw;
1673 struct nsi_ndis_ifinfo_dynamic *dyn;
1674 struct nsi_ndis_ifinfo_static *stat;
1676 if (!size) return ERROR_INVALID_PARAMETER;
1678 /* While this could be implemented on top of GetIfTable2(), it would require
1679 an additional copy of the data */
1680 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1681 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1682 (void **)&stat, sizeof(*stat), &count, 0 );
1683 if (err) return err;
1685 needed = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1687 if (!table || *size < needed)
1689 *size = needed;
1690 err = ERROR_INSUFFICIENT_BUFFER;
1691 goto err;
1694 table->dwNumEntries = count;
1695 for (i = 0; i < count; i++)
1697 MIB_IFROW *row = table->table + i;
1699 if_row_fill( row, rw + i, dyn + i, stat + i );
1702 if (sort) qsort( table->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1704 err:
1705 NsiFreeTable( keys, rw, dyn, stat );
1706 return err;
1709 /******************************************************************
1710 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1712 * Get table of local interfaces.
1713 * Like GetIfTable(), but allocate the returned table from heap.
1715 * PARAMS
1716 * table [Out] pointer into which the MIB_IFTABLE is
1717 * allocated and returned.
1718 * sort [In] whether to sort the table
1719 * heap [In] heap from which the table is allocated
1720 * flags [In] flags to HeapAlloc
1722 * RETURNS
1723 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1724 * GetIfTable() returns otherwise.
1726 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1728 DWORD i, count, size, err;
1729 NET_LUID *keys;
1730 struct nsi_ndis_ifinfo_rw *rw;
1731 struct nsi_ndis_ifinfo_dynamic *dyn;
1732 struct nsi_ndis_ifinfo_static *stat;
1734 if (!table) return ERROR_INVALID_PARAMETER;
1736 /* While this could be implemented on top of GetIfTable(), it would require
1737 an additional call to retrieve the size */
1738 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1739 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1740 (void **)&stat, sizeof(*stat), &count, 0 );
1741 if (err) return err;
1743 size = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1744 *table = HeapAlloc( heap, flags, size );
1745 if (!*table)
1747 err = ERROR_NOT_ENOUGH_MEMORY;
1748 goto err;
1751 (*table)->dwNumEntries = count;
1752 for (i = 0; i < count; i++)
1754 MIB_IFROW *row = (*table)->table + i;
1756 if_row_fill( row, rw + i, dyn + i, stat + i );
1758 if (sort) qsort( (*table)->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1760 err:
1761 NsiFreeTable( keys, rw, dyn, stat );
1762 return err;
1765 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1766 struct nsi_ndis_ifinfo_static *stat )
1768 row->InterfaceIndex = stat->if_index;
1769 row->InterfaceGuid = stat->if_guid;
1770 if_counted_string_copy( row->Alias, ARRAY_SIZE(row->Alias), &rw->alias );
1771 if_counted_string_copy( row->Description, ARRAY_SIZE(row->Description), &stat->descr );
1772 row->PhysicalAddressLength = rw->phys_addr.Length;
1773 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress)) row->PhysicalAddressLength = 0;
1774 memcpy( row->PhysicalAddress, rw->phys_addr.Address, row->PhysicalAddressLength );
1775 memcpy( row->PermanentPhysicalAddress, stat->perm_phys_addr.Address, row->PhysicalAddressLength );
1776 row->Mtu = dyn->mtu;
1777 row->Type = stat->type;
1778 row->TunnelType = TUNNEL_TYPE_NONE; /* fixme */
1779 row->MediaType = stat->media_type;
1780 row->PhysicalMediumType = stat->phys_medium_type;
1781 row->AccessType = stat->access_type;
1782 row->DirectionType = NET_IF_DIRECTION_SENDRECEIVE; /* fixme */
1783 row->InterfaceAndOperStatusFlags.HardwareInterface = stat->flags.hw;
1784 row->InterfaceAndOperStatusFlags.FilterInterface = stat->flags.filter;
1785 row->InterfaceAndOperStatusFlags.ConnectorPresent = !!stat->conn_present;
1786 row->InterfaceAndOperStatusFlags.NotAuthenticated = 0; /* fixme */
1787 row->InterfaceAndOperStatusFlags.NotMediaConnected = dyn->flags.not_media_conn;
1788 row->InterfaceAndOperStatusFlags.Paused = 0; /* fixme */
1789 row->InterfaceAndOperStatusFlags.LowPower = 0; /* fixme */
1790 row->InterfaceAndOperStatusFlags.EndPointInterface = 0; /* fixme */
1791 row->OperStatus = dyn->oper_status;
1792 row->AdminStatus = rw->admin_status;
1793 row->MediaConnectState = dyn->media_conn_state;
1794 row->NetworkGuid = rw->network_guid;
1795 row->ConnectionType = stat->conn_type;
1796 row->TransmitLinkSpeed = dyn->xmit_speed;
1797 row->ReceiveLinkSpeed = dyn->rcv_speed;
1798 row->InOctets = dyn->in_octets;
1799 row->InUcastPkts = dyn->in_ucast_pkts;
1800 row->InNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1801 row->InDiscards = dyn->in_discards;
1802 row->InErrors = dyn->in_errors;
1803 row->InUnknownProtos = 0; /* fixme */
1804 row->InUcastOctets = dyn->in_ucast_octs;
1805 row->InMulticastOctets = dyn->in_mcast_octs;
1806 row->InBroadcastOctets = dyn->in_bcast_octs;
1807 row->OutOctets = dyn->out_octets;
1808 row->OutUcastPkts = dyn->out_ucast_pkts;
1809 row->OutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1810 row->OutDiscards = dyn->out_discards;
1811 row->OutErrors = dyn->out_errors;
1812 row->OutUcastOctets = dyn->out_ucast_octs;
1813 row->OutMulticastOctets = dyn->out_mcast_octs;
1814 row->OutBroadcastOctets = dyn->out_bcast_octs;
1815 row->OutQLen = 0; /* fixme */
1818 /******************************************************************
1819 * GetIfEntry2Ex (IPHLPAPI.@)
1821 DWORD WINAPI GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_ROW2 *row )
1823 DWORD err;
1824 struct nsi_ndis_ifinfo_rw rw;
1825 struct nsi_ndis_ifinfo_dynamic dyn;
1826 struct nsi_ndis_ifinfo_static stat;
1828 TRACE( "(%d, %p)\n", level, row );
1830 if (level != MibIfTableNormal) FIXME( "level %u not fully supported\n", level );
1831 if (!row) return ERROR_INVALID_PARAMETER;
1833 if (!row->InterfaceLuid.Value)
1835 if (!row->InterfaceIndex) return ERROR_INVALID_PARAMETER;
1836 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
1837 if (err) return err;
1840 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1841 &row->InterfaceLuid, sizeof(row->InterfaceLuid),
1842 &rw, sizeof(rw), &dyn, sizeof(dyn), &stat, sizeof(stat) );
1843 if (!err) if_row2_fill( row, &rw, &dyn, &stat );
1844 return err;
1847 /******************************************************************
1848 * GetIfEntry2 (IPHLPAPI.@)
1850 DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row )
1852 return GetIfEntry2Ex( MibIfTableNormal, row );
1855 /******************************************************************
1856 * GetIfTable2Ex (IPHLPAPI.@)
1858 DWORD WINAPI GetIfTable2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_TABLE2 **table )
1860 DWORD i, count, size, err;
1861 NET_LUID *keys;
1862 struct nsi_ndis_ifinfo_rw *rw;
1863 struct nsi_ndis_ifinfo_dynamic *dyn;
1864 struct nsi_ndis_ifinfo_static *stat;
1866 TRACE( "level %u, table %p\n", level, table );
1868 if (!table || level > MibIfTableNormalWithoutStatistics)
1869 return ERROR_INVALID_PARAMETER;
1871 if (level != MibIfTableNormal)
1872 FIXME("level %u not fully supported\n", level);
1874 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1875 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1876 (void **)&stat, sizeof(*stat), &count, 0 );
1877 if (err) return err;
1879 size = FIELD_OFFSET( MIB_IF_TABLE2, Table[count] );
1881 if (!(*table = heap_alloc_zero( size )))
1883 err = ERROR_OUTOFMEMORY;
1884 goto err;
1887 (*table)->NumEntries = count;
1888 for (i = 0; i < count; i++)
1890 MIB_IF_ROW2 *row = (*table)->Table + i;
1892 row->InterfaceLuid.Value = keys[i].Value;
1893 if_row2_fill( row, rw + i, dyn + i, stat + i );
1895 err:
1896 NsiFreeTable( keys, rw, dyn, stat );
1897 return err;
1900 /******************************************************************
1901 * GetIfTable2 (IPHLPAPI.@)
1903 DWORD WINAPI GetIfTable2( MIB_IF_TABLE2 **table )
1905 TRACE( "table %p\n", table );
1906 return GetIfTable2Ex( MibIfTableNormal, table );
1909 /******************************************************************
1910 * GetInterfaceInfo (IPHLPAPI.@)
1912 * Get a list of network interface adapters.
1914 * PARAMS
1915 * pIfTable [Out] buffer for interface adapters
1916 * dwOutBufLen [Out] if buffer is too small, returns required size
1918 * RETURNS
1919 * Success: NO_ERROR
1920 * Failure: error code from winerror.h
1922 * BUGS
1923 * MSDN states this should return non-loopback interfaces only.
1925 DWORD WINAPI GetInterfaceInfo( IP_INTERFACE_INFO *table, ULONG *size )
1927 MIB_IFTABLE *if_table;
1928 DWORD err, needed, i;
1930 TRACE("table %p, size %p\n", table, size );
1931 if (!size) return ERROR_INVALID_PARAMETER;
1933 err = AllocateAndGetIfTableFromStack( &if_table, 0, GetProcessHeap(), 0 );
1934 if (err) return err;
1936 needed = FIELD_OFFSET(IP_INTERFACE_INFO, Adapter[if_table->dwNumEntries]);
1937 if (!table || *size < needed)
1939 *size = needed;
1940 heap_free( if_table );
1941 return ERROR_INSUFFICIENT_BUFFER;
1944 table->NumAdapters = if_table->dwNumEntries;
1945 for (i = 0; i < if_table->dwNumEntries; i++)
1947 table->Adapter[i].Index = if_table->table[i].dwIndex;
1948 strcpyW( table->Adapter[i].Name, if_table->table[i].wszName );
1950 heap_free( if_table );
1951 return ERROR_SUCCESS;
1954 static int ipaddrrow_cmp( const void *a, const void *b )
1956 return ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
1959 /******************************************************************
1960 * GetIpAddrTable (IPHLPAPI.@)
1962 * Get interface-to-IP address mapping table.
1964 * PARAMS
1965 * table [Out] buffer for mapping table
1966 * size [In/Out] length of output buffer
1967 * sort [In] whether to sort the table
1969 * RETURNS
1970 * Success: NO_ERROR
1971 * Failure: error code from winerror.h
1974 DWORD WINAPI GetIpAddrTable( MIB_IPADDRTABLE *table, ULONG *size, BOOL sort )
1976 DWORD err, count, needed, i, loopback, row_num = 0;
1977 struct nsi_ipv4_unicast_key *keys;
1978 struct nsi_ip_unicast_rw *rw;
1980 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
1981 if (!size) return ERROR_INVALID_PARAMETER;
1983 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&keys, sizeof(*keys),
1984 (void **)&rw, sizeof(*rw), NULL, 0, NULL, 0, &count, 0 );
1985 if (err) return err;
1987 needed = FIELD_OFFSET( MIB_IPADDRTABLE, table[count] );
1989 if (!table || *size < needed)
1991 *size = needed;
1992 err = ERROR_INSUFFICIENT_BUFFER;
1993 goto err;
1996 table->dwNumEntries = count;
1998 for (loopback = 0; loopback < 2; loopback++) /* Move the loopback addresses to the end */
2000 for (i = 0; i < count; i++)
2002 MIB_IPADDRROW *row = table->table + row_num;
2004 if (!!loopback != (keys[i].luid.Info.IfType == MIB_IF_TYPE_LOOPBACK)) continue;
2006 row->dwAddr = keys[i].addr.WS_s_addr;
2007 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
2008 ConvertLengthToIpv4Mask( rw[i].on_link_prefix, &row->dwMask );
2009 row->dwBCastAddr = 1;
2010 row->dwReasmSize = 0xffff;
2011 row->unused1 = 0;
2012 row->wType = MIB_IPADDR_PRIMARY;
2013 row_num++;
2017 if (sort) qsort( table->table, count, sizeof(MIB_IPADDRROW), ipaddrrow_cmp );
2018 err:
2019 NsiFreeTable( keys, rw, NULL, NULL );
2021 return err;
2025 /******************************************************************
2026 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2028 * Get interface-to-IP address mapping table.
2029 * Like GetIpAddrTable(), but allocate the returned table from heap.
2031 * PARAMS
2032 * table [Out] pointer into which the MIB_IPADDRTABLE is
2033 * allocated and returned.
2034 * sort [In] whether to sort the table
2035 * heap [In] heap from which the table is allocated
2036 * flags [In] flags to HeapAlloc
2039 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2041 DWORD err, size = FIELD_OFFSET(MIB_IPADDRTABLE, table[2]), attempt;
2043 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
2045 for (attempt = 0; attempt < 5; attempt++)
2047 *table = HeapAlloc( heap, flags, size );
2048 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2050 err = GetIpAddrTable( *table, &size, sort );
2051 if (!err) break;
2052 HeapFree( heap, flags, *table );
2053 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2056 return err;
2059 static int ipforward_row_cmp( const void *a, const void *b )
2061 const MIB_IPFORWARDROW *rowA = a;
2062 const MIB_IPFORWARDROW *rowB = b;
2063 int ret;
2065 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
2066 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
2067 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
2068 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
2071 /******************************************************************
2072 * GetIpForwardTable (IPHLPAPI.@)
2074 * Get the route table.
2076 * PARAMS
2077 * table [Out] buffer for route table
2078 * size [In/Out] length of output buffer
2079 * sort [In] whether to sort the table
2081 * RETURNS
2082 * Success: NO_ERROR
2083 * Failure: error code from winerror.h
2085 DWORD WINAPI GetIpForwardTable( MIB_IPFORWARDTABLE *table, ULONG *size, BOOL sort )
2087 DWORD err, count, uni_count, needed, i, addr;
2088 struct nsi_ipv4_forward_key *keys;
2089 struct nsi_ip_forward_rw *rw;
2090 struct nsi_ipv4_forward_dynamic *dyn;
2091 struct nsi_ip_forward_static *stat;
2092 struct nsi_ipv4_unicast_key *uni_keys = NULL;
2094 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2095 if (!size) return ERROR_INVALID_PARAMETER;
2097 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, (void **)&keys, sizeof(*keys),
2098 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2099 (void **)&stat, sizeof(*stat), &count, 0 );
2100 if (err) return err;
2102 needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
2104 if (!table || *size < needed)
2106 *size = needed;
2107 err = ERROR_INSUFFICIENT_BUFFER;
2108 goto err;
2111 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
2112 NULL, 0, NULL, 0, NULL, 0, &uni_count, 0 );
2113 if (err) goto err;
2115 table->dwNumEntries = count;
2116 for (i = 0; i < count; i++)
2118 MIB_IPFORWARDROW *row = table->table + i;
2120 row->dwForwardDest = keys[i].prefix.WS_s_addr;
2121 ConvertLengthToIpv4Mask( keys[i].prefix_len, &row->dwForwardMask );
2122 row->dwForwardPolicy = 0;
2123 row->dwForwardNextHop = keys[i].next_hop.WS_s_addr;
2124 row->u1.dwForwardType = row->dwForwardNextHop ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
2125 if (!row->dwForwardNextHop) /* find the interface's addr */
2127 for (addr = 0; addr < uni_count; addr++)
2129 if (uni_keys[addr].luid.Value == keys[i].luid.Value)
2131 row->dwForwardNextHop = uni_keys[addr].addr.WS_s_addr;
2132 break;
2136 row->dwForwardIfIndex = stat[i].if_index;
2137 row->u2.dwForwardProto = rw[i].protocol;
2138 row->dwForwardAge = dyn[i].age;
2139 row->dwForwardNextHopAS = 0;
2140 row->dwForwardMetric1 = rw[i].metric; /* FIXME: add interface metric */
2141 row->dwForwardMetric2 = 0;
2142 row->dwForwardMetric3 = 0;
2143 row->dwForwardMetric4 = 0;
2144 row->dwForwardMetric5 = 0;
2147 if (sort) qsort( table->table, count, sizeof(MIB_IPFORWARDROW), ipforward_row_cmp );
2148 err:
2149 NsiFreeTable( uni_keys, NULL, NULL, NULL );
2150 NsiFreeTable( keys, rw, dyn, stat );
2152 return err;
2155 /******************************************************************
2156 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2158 * Get the route table.
2159 * Like GetIpForwardTable(), but allocate the returned table from heap.
2161 * PARAMS
2162 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2163 * allocated and returned.
2164 * sort [In] whether to sort the table
2165 * heap [In] heap from which the table is allocated
2166 * flags [In] flags to HeapAlloc
2168 * RETURNS
2169 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2170 * on failure, NO_ERROR on success.
2172 DWORD WINAPI AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2174 DWORD err, size = FIELD_OFFSET(MIB_IPFORWARDTABLE, table[2]), attempt;
2176 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
2178 for (attempt = 0; attempt < 5; attempt++)
2180 *table = HeapAlloc( heap, flags, size );
2181 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2183 err = GetIpForwardTable( *table, &size, sort );
2184 if (!err) break;
2185 HeapFree( heap, flags, *table );
2186 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2189 return err;
2192 static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
2193 void *dyn, struct nsi_ip_forward_static *stat )
2195 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key;
2196 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key;
2197 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn;
2198 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn;
2200 if (fam == WS_AF_INET)
2202 row->InterfaceLuid = key4->luid;
2203 row->DestinationPrefix.Prefix.Ipv4.sin_family = fam;
2204 row->DestinationPrefix.Prefix.Ipv4.sin_port = 0;
2205 row->DestinationPrefix.Prefix.Ipv4.sin_addr = key4->prefix;
2206 memset( &row->DestinationPrefix.Prefix.Ipv4.sin_zero, 0, sizeof(row->DestinationPrefix.Prefix.Ipv4.sin_zero) );
2207 row->DestinationPrefix.PrefixLength = key4->prefix_len;
2208 row->NextHop.Ipv4.sin_family = fam;
2209 row->NextHop.Ipv4.sin_port = 0;
2210 row->NextHop.Ipv4.sin_addr = key4->next_hop;
2211 memset( &row->NextHop.Ipv4.sin_zero, 0, sizeof(row->NextHop.Ipv4.sin_zero) );
2213 row->Age = dyn4->age;
2215 else
2217 row->InterfaceLuid = key6->luid;
2219 row->DestinationPrefix.Prefix.Ipv6.sin6_family = fam;
2220 row->DestinationPrefix.Prefix.Ipv6.sin6_port = 0;
2221 row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo = 0;
2222 row->DestinationPrefix.Prefix.Ipv6.sin6_addr = key6->prefix;
2223 row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id = 0;
2224 row->DestinationPrefix.PrefixLength = key6->prefix_len;
2225 row->NextHop.Ipv6.sin6_family = fam;
2226 row->NextHop.Ipv6.sin6_port = 0;
2227 row->NextHop.Ipv6.sin6_flowinfo = 0;
2228 row->NextHop.Ipv6.sin6_addr = key6->next_hop;
2229 row->NextHop.Ipv6.sin6_scope_id = 0;
2231 row->Age = dyn6->age;
2234 row->InterfaceIndex = stat->if_index;
2236 row->SitePrefixLength = rw->site_prefix_len;
2237 row->ValidLifetime = rw->valid_lifetime;
2238 row->PreferredLifetime = rw->preferred_lifetime;
2239 row->Metric = rw->metric;
2240 row->Protocol = rw->protocol;
2241 row->Loopback = rw->loopback;
2242 row->AutoconfigureAddress = rw->autoconf;
2243 row->Publish = rw->publish;
2244 row->Immortal = rw->immortal;
2246 row->Origin = stat->origin;
2249 /******************************************************************
2250 * GetIpForwardTable2 (IPHLPAPI.@)
2252 DWORD WINAPI GetIpForwardTable2( ADDRESS_FAMILY family, MIB_IPFORWARD_TABLE2 **table )
2254 void *key[2] = { NULL, NULL };
2255 struct nsi_ip_forward_rw *rw[2] = { NULL, NULL };
2256 void *dyn[2] = { NULL, NULL };
2257 struct nsi_ip_forward_static *stat[2] = { NULL, NULL };
2258 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
2259 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ipv6_forward_key) };
2260 static const DWORD dyn_size[2] = { sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ipv6_forward_dynamic) };
2261 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2263 TRACE( "%u, %p\n", family, table );
2265 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2266 return ERROR_INVALID_PARAMETER;
2268 for (i = 0; i < 2; i++)
2270 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
2272 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_FORWARD_TABLE, key + i, key_size[i],
2273 (void **)rw + i, sizeof(**rw), dyn + i, dyn_size[i],
2274 (void **)stat + i, sizeof(**stat), count + i, 0 );
2275 if (err) count[i] = 0;
2278 size = FIELD_OFFSET(MIB_IPFORWARD_TABLE2, Table[ count[0] + count[1] ]);
2279 *table = heap_alloc( size );
2280 if (!*table)
2282 err = ERROR_NOT_ENOUGH_MEMORY;
2283 goto err;
2286 (*table)->NumEntries = count[0] + count[1];
2287 for (i = 0; i < count[0]; i++)
2289 MIB_IPFORWARD_ROW2 *row = (*table)->Table + i;
2290 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key[0];
2291 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn[0];
2293 forward_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn4 + i, stat[0] + i );
2296 for (i = 0; i < count[1]; i++)
2298 MIB_IPFORWARD_ROW2 *row = (*table)->Table + count[0] + i;
2299 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key[1];
2300 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn[1];
2302 forward_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn6 + i, stat[1] + i );
2305 err:
2306 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
2307 return err;
2310 static int ipnetrow_cmp( const void *a, const void *b )
2312 const MIB_IPNETROW *row_a = a;
2313 const MIB_IPNETROW *row_b = b;
2315 return RtlUlongByteSwap( row_a->dwAddr ) - RtlUlongByteSwap( row_b->dwAddr );
2318 /******************************************************************
2319 * GetIpNetTable (IPHLPAPI.@)
2321 * Get the IP-to-physical address mapping table.
2323 * PARAMS
2324 * table [Out] buffer for mapping table
2325 * size [In/Out] length of output buffer
2326 * sort [In] whether to sort the table
2328 * RETURNS
2329 * Success: NO_ERROR
2330 * Failure: error code from winerror.h
2333 DWORD WINAPI GetIpNetTable( MIB_IPNETTABLE *table, ULONG *size, BOOL sort )
2335 DWORD err, count, needed, i;
2336 struct nsi_ipv4_neighbour_key *keys;
2337 struct nsi_ip_neighbour_rw *rw;
2338 struct nsi_ip_neighbour_dynamic *dyn;
2340 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2342 if (!size) return ERROR_INVALID_PARAMETER;
2344 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_NEIGHBOUR_TABLE, (void **)&keys, sizeof(*keys),
2345 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2346 NULL, 0, &count, 0 );
2347 if (err) return err;
2349 needed = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
2351 if (!table || *size < needed)
2353 *size = needed;
2354 err = ERROR_INSUFFICIENT_BUFFER;
2355 goto err;
2358 table->dwNumEntries = count;
2359 for (i = 0; i < count; i++)
2361 MIB_IPNETROW *row = table->table + i;
2363 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
2364 row->dwPhysAddrLen = dyn[i].phys_addr_len;
2365 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
2366 memcpy( row->bPhysAddr, rw[i].phys_addr, row->dwPhysAddrLen );
2367 memset( row->bPhysAddr + row->dwPhysAddrLen, 0,
2368 sizeof(row->bPhysAddr) - row->dwPhysAddrLen );
2369 row->dwAddr = keys[i].addr.WS_s_addr;
2370 switch (dyn->state)
2372 case NlnsUnreachable:
2373 case NlnsIncomplete:
2374 row->u.Type = MIB_IPNET_TYPE_INVALID;
2375 break;
2376 case NlnsProbe:
2377 case NlnsDelay:
2378 case NlnsStale:
2379 case NlnsReachable:
2380 row->u.Type = MIB_IPNET_TYPE_DYNAMIC;
2381 break;
2382 case NlnsPermanent:
2383 row->u.Type = MIB_IPNET_TYPE_STATIC;
2384 break;
2385 default:
2386 row->u.Type = MIB_IPNET_TYPE_OTHER;
2390 if (sort) qsort( table->table, table->dwNumEntries, sizeof(*table->table), ipnetrow_cmp );
2392 err:
2393 NsiFreeTable( keys, rw, dyn, NULL );
2394 return err;
2397 /******************************************************************
2398 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2400 DWORD WINAPI AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2402 DWORD err, size = FIELD_OFFSET(MIB_IPNETTABLE, table[2]), attempt;
2404 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
2406 for (attempt = 0; attempt < 5; attempt++)
2408 *table = HeapAlloc( heap, flags, size );
2409 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2411 err = GetIpNetTable( *table, &size, sort );
2412 if (!err) break;
2413 HeapFree( heap, flags, *table );
2414 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2417 return err;
2420 static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw,
2421 struct nsi_ip_neighbour_dynamic *dyn )
2423 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key;
2424 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key;
2426 if (fam == WS_AF_INET)
2428 row->Address.Ipv4.sin_family = fam;
2429 row->Address.Ipv4.sin_port = 0;
2430 row->Address.Ipv4.sin_addr = key4->addr;
2431 memset( &row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
2432 row->InterfaceLuid = key4->luid;
2434 else
2436 row->Address.Ipv6.sin6_family = fam;
2437 row->Address.Ipv6.sin6_port = 0;
2438 row->Address.Ipv6.sin6_flowinfo = 0;
2439 row->Address.Ipv6.sin6_addr = key6->addr;
2440 row->Address.Ipv6.sin6_scope_id = 0;
2441 row->InterfaceLuid = key6->luid;
2444 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
2446 row->PhysicalAddressLength = dyn->phys_addr_len;
2447 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress))
2448 row->PhysicalAddressLength = 0;
2449 memcpy( row->PhysicalAddress, rw->phys_addr, row->PhysicalAddressLength );
2450 memset( row->PhysicalAddress + row->PhysicalAddressLength, 0,
2451 sizeof(row->PhysicalAddress) - row->PhysicalAddressLength );
2452 row->State = dyn->state;
2453 row->u.Flags = 0;
2454 row->u.s.IsRouter = dyn->flags.is_router;
2455 row->u.s.IsUnreachable = dyn->flags.is_unreachable;
2456 row->ReachabilityTime.LastReachable = dyn->time;
2459 /******************************************************************
2460 * GetIpNetTable2 (IPHLPAPI.@)
2462 DWORD WINAPI GetIpNetTable2( ADDRESS_FAMILY family, MIB_IPNET_TABLE2 **table )
2464 void *key[2] = { NULL, NULL };
2465 struct nsi_ip_neighbour_rw *rw[2] = { NULL, NULL };
2466 struct nsi_ip_neighbour_dynamic *dyn[2] = { NULL, NULL };
2467 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
2468 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ipv6_neighbour_key) };
2469 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2471 TRACE( "%u, %p\n", family, table );
2473 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
2474 return ERROR_INVALID_PARAMETER;
2476 for (i = 0; i < 2; i++)
2478 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
2480 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_NEIGHBOUR_TABLE, key + i, key_size[i],
2481 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
2482 NULL, 0, count + i, 0 );
2483 if (err) count[i] = 0;
2486 size = FIELD_OFFSET(MIB_IPNET_TABLE2, Table[ count[0] + count[1] ]);
2487 *table = heap_alloc( size );
2488 if (!*table)
2490 err = ERROR_NOT_ENOUGH_MEMORY;
2491 goto err;
2494 (*table)->NumEntries = count[0] + count[1];
2495 for (i = 0; i < count[0]; i++)
2497 MIB_IPNET_ROW2 *row = (*table)->Table + i;
2498 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key[0];
2500 ipnet_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn[0] + i );
2503 for (i = 0; i < count[1]; i++)
2505 MIB_IPNET_ROW2 *row = (*table)->Table + count[0] + i;
2506 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key[1];
2508 ipnet_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn[1] + i );
2511 err:
2512 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], NULL );
2513 return err;
2516 /******************************************************************
2517 * GetIpStatistics (IPHLPAPI.@)
2519 * Get the IP statistics for the local computer.
2521 * PARAMS
2522 * stats [Out] buffer for IP statistics
2524 * RETURNS
2525 * Success: NO_ERROR
2526 * Failure: error code from winerror.h
2528 DWORD WINAPI GetIpStatistics( MIB_IPSTATS *stats )
2530 return GetIpStatisticsEx( stats, WS_AF_INET );
2533 /******************************************************************
2534 * GetIpStatisticsEx (IPHLPAPI.@)
2536 * Get the IPv4 and IPv6 statistics for the local computer.
2538 * PARAMS
2539 * stats [Out] buffer for IP statistics
2540 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2542 * RETURNS
2543 * Success: NO_ERROR
2544 * Failure: error code from winerror.h
2546 DWORD WINAPI GetIpStatisticsEx( MIB_IPSTATS *stats, DWORD family )
2548 struct nsi_ip_ipstats_dynamic dyn;
2549 struct nsi_ip_ipstats_static stat;
2550 struct nsi_ip_cmpt_rw cmpt_rw;
2551 struct nsi_ip_cmpt_dynamic cmpt_dyn;
2552 const NPI_MODULEID *mod;
2553 DWORD err, cmpt = 1;
2555 TRACE( "%p %d\n", stats, family );
2557 if (!stats) return ERROR_INVALID_PARAMETER;
2558 mod = ip_module_id( family );
2559 if (!mod) return ERROR_INVALID_PARAMETER;
2561 memset( stats, 0, sizeof(*stats) );
2563 err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0,
2564 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2565 if (err) return err;
2567 err = NsiGetAllParameters( 1, mod, NSI_IP_COMPARTMENT_TABLE, &cmpt, sizeof(cmpt), &cmpt_rw, sizeof(cmpt_rw),
2568 &cmpt_dyn, sizeof(cmpt_dyn), NULL, 0 );
2569 if (err) return err;
2571 stats->u.Forwarding = cmpt_rw.not_forwarding + 1;
2572 stats->dwDefaultTTL = cmpt_rw.default_ttl;
2573 stats->dwInReceives = dyn.in_recv;
2574 stats->dwInHdrErrors = dyn.in_hdr_errs;
2575 stats->dwInAddrErrors = dyn.in_addr_errs;
2576 stats->dwForwDatagrams = dyn.fwd_dgrams;
2577 stats->dwInUnknownProtos = dyn.in_unk_protos;
2578 stats->dwInDiscards = dyn.in_discards;
2579 stats->dwInDelivers = dyn.in_delivers;
2580 stats->dwOutRequests = dyn.out_reqs;
2581 stats->dwRoutingDiscards = dyn.routing_discards;
2582 stats->dwOutDiscards = dyn.out_discards;
2583 stats->dwOutNoRoutes = dyn.out_no_routes;
2584 stats->dwReasmTimeout = stat.reasm_timeout;
2585 stats->dwReasmReqds = dyn.reasm_reqds;
2586 stats->dwReasmOks = dyn.reasm_oks;
2587 stats->dwReasmFails = dyn.reasm_fails;
2588 stats->dwFragOks = dyn.frag_oks;
2589 stats->dwFragFails = dyn.frag_fails;
2590 stats->dwFragCreates = dyn.frag_creates;
2591 stats->dwNumIf = cmpt_dyn.num_ifs;
2592 stats->dwNumAddr = cmpt_dyn.num_addrs;
2593 stats->dwNumRoutes = cmpt_dyn.num_routes;
2595 return err;
2598 /* Gets the DNS server list into the list beginning at list. Assumes that
2599 * a single server address may be placed at list if *len is at least
2600 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2601 * and assumes that all remaining DNS servers are contiguously located
2602 * beginning at second. On input, *len is assumed to be the total number
2603 * of bytes available for all DNS servers, and is ignored if list is NULL.
2604 * On return, *len is set to the total number of bytes required for all DNS
2605 * servers.
2606 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2607 * ERROR_SUCCESS otherwise.
2609 static DWORD get_dns_server_list( const NET_LUID *luid, IP_ADDR_STRING *list, IP_ADDR_STRING *second, DWORD *len )
2611 char buf[FIELD_OFFSET(IP4_ARRAY, AddrArray[3])];
2612 IP4_ARRAY *servers = (IP4_ARRAY *)buf;
2613 DWORD needed, num, err, i, array_len = sizeof(buf);
2614 IP_ADDR_STRING *ptr;
2616 if (luid && luid->Info.IfType == MIB_IF_TYPE_LOOPBACK) return ERROR_NO_DATA;
2618 for (;;)
2620 err = DnsQueryConfig( DnsConfigDnsServerList, 0, NULL, NULL, servers, &array_len );
2621 num = (array_len - FIELD_OFFSET(IP4_ARRAY, AddrArray[0])) / sizeof(IP4_ADDRESS);
2622 needed = num * sizeof(IP_ADDR_STRING);
2623 if (!list || *len < needed)
2625 *len = needed;
2626 err = ERROR_BUFFER_OVERFLOW;
2627 goto err;
2629 if (!err) break;
2631 if ((char *)servers != buf) heap_free( servers );
2632 servers = heap_alloc( array_len );
2633 if (!servers)
2635 err = ERROR_NOT_ENOUGH_MEMORY;
2636 goto err;
2640 *len = needed;
2642 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next)
2644 RtlIpv4AddressToStringA( (IN_ADDR *)&servers->AddrArray[i], ptr->IpAddress.String );
2645 if (i == num - 1) ptr->Next = NULL;
2646 else if (i == 0) ptr->Next = second;
2647 else ptr->Next = ptr + 1;
2650 err:
2651 if ((char *)servers != buf) heap_free( servers );
2652 return err;
2655 /******************************************************************
2656 * GetNetworkParams (IPHLPAPI.@)
2658 * Get the network parameters for the local computer.
2660 * PARAMS
2661 * info [Out] buffer for network parameters
2662 * size [In/Out] length of output buffer
2664 * RETURNS
2665 * Success: NO_ERROR
2666 * Failure: error code from winerror.h
2668 * NOTES
2669 * If size is less than required, the function will return
2670 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2671 * size.
2673 DWORD WINAPI GetNetworkParams( FIXED_INFO *info, ULONG *size )
2675 DWORD needed = sizeof(*info), dns_size, err;
2676 MIB_IPSTATS ip_stats;
2677 HKEY key;
2679 TRACE( "info %p, size %p\n", info, size );
2680 if (!size) return ERROR_INVALID_PARAMETER;
2682 if (get_dns_server_list( NULL, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2683 needed += dns_size - sizeof(IP_ADDR_STRING);
2684 if (!info || *size < needed)
2686 *size = needed;
2687 return ERROR_BUFFER_OVERFLOW;
2690 *size = needed;
2691 memset( info, 0, needed );
2692 needed = sizeof(info->HostName);
2693 GetComputerNameExA( ComputerNameDnsHostname, info->HostName, &needed );
2694 needed = sizeof(info->DomainName);
2695 GetComputerNameExA( ComputerNameDnsDomain, info->DomainName, &needed );
2696 get_dns_server_list( NULL, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2697 info->CurrentDnsServer = &info->DnsServerList;
2698 info->NodeType = HYBRID_NODETYPE;
2699 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2700 0, KEY_READ, &key );
2701 if (err)
2702 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2703 0, KEY_READ, &key );
2704 if (!err)
2706 needed = sizeof(info->ScopeId);
2707 RegQueryValueExA( key, "ScopeID", NULL, NULL, (BYTE *)info->ScopeId, &needed );
2708 RegCloseKey( key );
2711 if (!GetIpStatistics( &ip_stats ))
2712 info->EnableRouting = (ip_stats.u.Forwarding == MIB_IP_FORWARDING);
2714 return ERROR_SUCCESS;
2718 /******************************************************************
2719 * GetNumberOfInterfaces (IPHLPAPI.@)
2721 * Get the number of interfaces.
2723 * PARAMS
2724 * pdwNumIf [Out] number of interfaces
2726 * RETURNS
2727 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2729 DWORD WINAPI GetNumberOfInterfaces( DWORD *count )
2731 DWORD err, num;
2733 TRACE( "count %p\n", count );
2734 if (!count) return ERROR_INVALID_PARAMETER;
2736 err = NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0,
2737 NULL, 0, NULL, 0, NULL, 0, &num );
2738 *count = err ? 0 : num;
2739 return err;
2742 /******************************************************************
2743 * GetPerAdapterInfo (IPHLPAPI.@)
2745 * Get information about an adapter corresponding to an interface.
2747 * PARAMS
2748 * IfIndex [In] interface info
2749 * pPerAdapterInfo [Out] buffer for per adapter info
2750 * pOutBufLen [In/Out] length of output buffer
2752 * RETURNS
2753 * Success: NO_ERROR
2754 * Failure: error code from winerror.h
2756 DWORD WINAPI GetPerAdapterInfo( ULONG index, IP_PER_ADAPTER_INFO *info, ULONG *size )
2758 DWORD needed = sizeof(*info), dns_size;
2759 NET_LUID luid;
2761 TRACE( "(index %d, info %p, size %p)\n", index, info, size );
2763 if (!size) return ERROR_INVALID_PARAMETER;
2764 if (ConvertInterfaceIndexToLuid( index, &luid )) return ERROR_NO_DATA;
2766 if (get_dns_server_list( &luid, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2767 needed += dns_size - sizeof(IP_ADDR_STRING);
2769 if (!info || *size < needed)
2771 *size = needed;
2772 return ERROR_BUFFER_OVERFLOW;
2775 memset( info, 0, needed );
2776 get_dns_server_list( &luid, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2777 info->CurrentDnsServer = &info->DnsServerList;
2779 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2780 return ERROR_SUCCESS;
2784 /******************************************************************
2785 * GetRTTAndHopCount (IPHLPAPI.@)
2787 * Get round-trip time (RTT) and hop count.
2789 * PARAMS
2791 * DestIpAddress [In] destination address to get the info for
2792 * HopCount [Out] retrieved hop count
2793 * MaxHops [In] maximum hops to search for the destination
2794 * RTT [Out] RTT in milliseconds
2796 * RETURNS
2797 * Success: TRUE
2798 * Failure: FALSE
2800 * FIXME
2801 * Stub, returns FALSE.
2803 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2805 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2806 DestIpAddress, HopCount, MaxHops, RTT);
2807 return FALSE;
2810 /******************************************************************
2811 * GetTcpStatistics (IPHLPAPI.@)
2813 * Get the TCP statistics for the local computer.
2815 * PARAMS
2816 * stats [Out] buffer for TCP statistics
2818 * RETURNS
2819 * Success: NO_ERROR
2820 * Failure: error code from winerror.h
2822 DWORD WINAPI GetTcpStatistics( MIB_TCPSTATS *stats )
2824 return GetTcpStatisticsEx( stats, WS_AF_INET );
2827 /******************************************************************
2828 * GetTcpStatisticsEx (IPHLPAPI.@)
2830 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2832 * PARAMS
2833 * stats [Out] buffer for TCP statistics
2834 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2836 * RETURNS
2837 * Success: NO_ERROR
2838 * Failure: error code from winerror.h
2840 DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
2842 struct nsi_tcp_stats_dynamic dyn;
2843 struct nsi_tcp_stats_static stat;
2844 USHORT key = (USHORT)family;
2845 DWORD err;
2847 if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
2848 memset( stats, 0, sizeof(*stats) );
2850 err = NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
2851 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2852 if (err) return err;
2854 stats->u.RtoAlgorithm = stat.rto_algo;
2855 stats->dwRtoMin = stat.rto_min;
2856 stats->dwRtoMax = stat.rto_max;
2857 stats->dwMaxConn = stat.max_conns;
2858 stats->dwActiveOpens = dyn.active_opens;
2859 stats->dwPassiveOpens = dyn.passive_opens;
2860 stats->dwAttemptFails = dyn.attempt_fails;
2861 stats->dwEstabResets = dyn.est_rsts;
2862 stats->dwCurrEstab = dyn.cur_est;
2863 stats->dwInSegs = (DWORD)dyn.in_segs;
2864 stats->dwOutSegs = (DWORD)dyn.out_segs;
2865 stats->dwRetransSegs = dyn.retrans_segs;
2866 stats->dwInErrs = dyn.in_errs;
2867 stats->dwOutRsts = dyn.out_rsts;
2868 stats->dwNumConns = dyn.num_conns;
2870 return err;
2873 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2875 static DWORD tcp_table_id( ULONG table_class )
2877 switch (table_class)
2879 case TCP_TABLE_BASIC_LISTENER:
2880 case TCP_TABLE_OWNER_PID_LISTENER:
2881 case TCP_TABLE_OWNER_MODULE_LISTENER:
2882 return NSI_TCP_LISTEN_TABLE;
2884 case TCP_TABLE_BASIC_CONNECTIONS:
2885 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2886 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2887 return NSI_TCP_ESTAB_TABLE;
2889 case TCP_TABLE_BASIC_ALL:
2890 case TCP_TABLE_OWNER_PID_ALL:
2891 case TCP_TABLE_OWNER_MODULE_ALL:
2892 case TCP_TABLE2:
2893 return NSI_TCP_ALL_TABLE;
2895 default:
2896 ERR( "unhandled class %u\n", table_class );
2897 return ~0u;
2901 static DWORD tcp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
2903 switch (table_class)
2905 case TCP_TABLE_BASIC_LISTENER:
2906 case TCP_TABLE_BASIC_CONNECTIONS:
2907 case TCP_TABLE_BASIC_ALL:
2908 *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW) : sizeof(MIB_TCP6ROW);
2909 return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE, table[row_count]) :
2910 FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
2912 case TCP_TABLE_OWNER_PID_LISTENER:
2913 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2914 case TCP_TABLE_OWNER_PID_ALL:
2915 *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW_OWNER_PID) : sizeof(MIB_TCP6ROW_OWNER_PID);
2916 return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]) :
2917 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
2919 case TCP_TABLE_OWNER_MODULE_LISTENER:
2920 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2921 case TCP_TABLE_OWNER_MODULE_ALL:
2922 *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW_OWNER_MODULE) : sizeof(MIB_TCP6ROW_OWNER_MODULE);
2923 return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]) :
2924 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
2926 case TCP_TABLE2:
2927 *row_size = (family == WS_AF_INET) ? sizeof(MIB_TCPROW2) : sizeof(MIB_TCP6ROW2);
2928 return (family == WS_AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE2, table[row_count]) :
2929 FIELD_OFFSET(MIB_TCP6TABLE2, table[row_count]);
2931 default:
2932 ERR( "unhandled class %u\n", table_class );
2933 return 0;
2937 static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
2938 struct nsi_tcp_conn_key *key, struct nsi_tcp_conn_dynamic *dyn,
2939 struct nsi_tcp_conn_static *stat )
2941 if (family == WS_AF_INET)
2943 switch (table_class)
2945 case TCP_TABLE_BASIC_LISTENER:
2946 case TCP_TABLE_BASIC_CONNECTIONS:
2947 case TCP_TABLE_BASIC_ALL:
2949 MIB_TCPROW *row = ((MIB_TCPTABLE *)table)->table + num;
2950 row->u.dwState = dyn->state;
2951 row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
2952 row->dwLocalPort = key->local.Ipv4.sin_port;
2953 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
2954 row->dwRemotePort = key->remote.Ipv4.sin_port;
2955 return;
2957 case TCP_TABLE_OWNER_PID_LISTENER:
2958 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2959 case TCP_TABLE_OWNER_PID_ALL:
2961 MIB_TCPROW_OWNER_PID *row = ((MIB_TCPTABLE_OWNER_PID *)table)->table + num;
2962 row->dwState = dyn->state;
2963 row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
2964 row->dwLocalPort = key->local.Ipv4.sin_port;
2965 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
2966 row->dwRemotePort = key->remote.Ipv4.sin_port;
2967 row->dwOwningPid = stat->pid;
2968 return;
2970 case TCP_TABLE_OWNER_MODULE_LISTENER:
2971 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2972 case TCP_TABLE_OWNER_MODULE_ALL:
2974 MIB_TCPROW_OWNER_MODULE *row = ((MIB_TCPTABLE_OWNER_MODULE *)table)->table + num;
2975 row->dwState = dyn->state;
2976 row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
2977 row->dwLocalPort = key->local.Ipv4.sin_port;
2978 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
2979 row->dwRemotePort = key->remote.Ipv4.sin_port;
2980 row->dwOwningPid = stat->pid;
2981 row->liCreateTimestamp.QuadPart = stat->create_time;
2982 row->OwningModuleInfo[0] = stat->mod_info;
2983 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
2984 return;
2986 case TCP_TABLE2:
2988 MIB_TCPROW2 *row = ((MIB_TCPTABLE2 *)table)->table + num;
2989 row->dwState = dyn->state;
2990 row->dwLocalAddr = key->local.Ipv4.sin_addr.WS_s_addr;
2991 row->dwLocalPort = key->local.Ipv4.sin_port;
2992 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.WS_s_addr;
2993 row->dwRemotePort = key->remote.Ipv4.sin_port;
2994 row->dwOwningPid = stat->pid;
2995 row->dwOffloadState = 0; /* FIXME */
2996 return;
2998 default:
2999 ERR( "Unknown class %d\n", table_class );
3000 return;
3003 else
3005 switch (table_class)
3007 case TCP_TABLE_BASIC_LISTENER:
3008 case TCP_TABLE_BASIC_CONNECTIONS:
3009 case TCP_TABLE_BASIC_ALL:
3011 MIB_TCP6ROW *row = ((MIB_TCP6TABLE *)table)->table + num;
3012 row->State = dyn->state;
3013 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
3014 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3015 row->dwLocalPort = key->local.Ipv6.sin6_port;
3016 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
3017 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3018 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3019 return;
3021 case TCP_TABLE_OWNER_PID_LISTENER:
3022 case TCP_TABLE_OWNER_PID_CONNECTIONS:
3023 case TCP_TABLE_OWNER_PID_ALL:
3025 MIB_TCP6ROW_OWNER_PID *row = ((MIB_TCP6TABLE_OWNER_PID *)table)->table + num;
3026 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3027 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3028 row->dwLocalPort = key->local.Ipv6.sin6_port;
3029 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3030 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3031 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3032 row->dwState = dyn->state;
3033 row->dwOwningPid = stat->pid;
3034 return;
3036 case TCP_TABLE_OWNER_MODULE_LISTENER:
3037 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
3038 case TCP_TABLE_OWNER_MODULE_ALL:
3040 MIB_TCP6ROW_OWNER_MODULE *row = ((MIB_TCP6TABLE_OWNER_MODULE *)table)->table + num;
3041 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3042 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3043 row->dwLocalPort = key->local.Ipv6.sin6_port;
3044 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3045 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3046 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3047 row->dwState = dyn->state;
3048 row->dwOwningPid = stat->pid;
3049 row->liCreateTimestamp.QuadPart = stat->create_time;
3050 row->OwningModuleInfo[0] = stat->mod_info;
3051 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3052 return;
3054 case TCP_TABLE2:
3056 MIB_TCP6ROW2 *row = ((MIB_TCP6TABLE2 *)table)->table + num;
3057 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
3058 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3059 row->dwLocalPort = key->local.Ipv6.sin6_port;
3060 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
3061 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3062 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3063 row->State = dyn->state;
3064 row->dwOwningPid = stat->pid;
3065 row->dwOffloadState = 0; /* FIXME */
3066 return;
3068 default:
3069 ERR( "Unknown class %d\n", table_class );
3070 return;
3073 ERR( "Unknown family %d\n", family );
3076 static int tcp_row_cmp( const void *a, const void *b )
3078 const MIB_TCPROW *rowA = a;
3079 const MIB_TCPROW *rowB = b;
3080 int ret;
3082 if ((ret = RtlUlongByteSwap( rowA->dwLocalAddr ) - RtlUlongByteSwap( rowB->dwLocalAddr )) != 0) return ret;
3083 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3084 if ((ret = RtlUlongByteSwap( rowA->dwRemoteAddr ) - RtlUlongByteSwap( rowB->dwRemoteAddr )) != 0) return ret;
3085 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3088 static int tcp6_row_basic_cmp( const void *a, const void *b )
3090 const MIB_TCP6ROW *rowA = a;
3091 const MIB_TCP6ROW *rowB = b;
3092 int ret;
3094 if ((ret = memcmp( &rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr) )) != 0) return ret;
3095 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3096 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3097 if ((ret = memcmp( &rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr) )) != 0) return ret;
3098 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3099 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3102 static int tcp6_row_owner_cmp( const void *a, const void *b )
3104 const MIB_TCP6ROW_OWNER_PID *rowA = a;
3105 const MIB_TCP6ROW_OWNER_PID *rowB = b;
3106 int ret;
3108 if ((ret = memcmp( &rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr) )) != 0) return ret;
3109 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3110 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3111 if ((ret = memcmp( &rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr) )) != 0) return ret;
3112 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3113 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3116 /*************************************************************************************
3117 * get_extended_tcp_table
3119 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3120 * corresponding to GetTcp(6)Table2()
3122 DWORD get_extended_tcp_table( void *table, DWORD *size, BOOL sort, ULONG family, ULONG table_class )
3124 DWORD err, count, needed, i, num = 0, row_size = 0;
3125 struct nsi_tcp_conn_key *key;
3126 struct nsi_tcp_conn_dynamic *dyn;
3127 struct nsi_tcp_conn_static *stat;
3129 if (!size) return ERROR_INVALID_PARAMETER;
3131 err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
3132 NULL, 0, (void **)&dyn, sizeof(*dyn),
3133 (void **)&stat, sizeof(*stat), &count, 0 );
3134 if (err) return err;
3136 for (i = 0; i < count; i++)
3137 if (key[i].local.si_family == family)
3138 num++;
3140 needed = tcp_table_size( family, table_class, num, &row_size );
3141 if (!table || *size < needed)
3143 *size = needed;
3144 err = ERROR_INSUFFICIENT_BUFFER;
3146 else
3148 *size = needed;
3149 *(DWORD *)table = num;
3150 num = 0;
3151 for (i = 0; i < count; i++)
3153 if (key[i].local.si_family != family) continue;
3154 tcp_row_fill( table, num++, family, table_class, key + i, dyn + i, stat + i );
3158 if (!err && sort)
3160 int (*fn)(const void *, const void *);
3161 DWORD offset;
3163 if (family == WS_AF_INET) fn = tcp_row_cmp;
3164 else if (row_size == sizeof(MIB_TCP6ROW)) fn = tcp6_row_basic_cmp;
3165 else fn = tcp6_row_owner_cmp;
3167 offset = tcp_table_size( family, table_class, 0, &row_size );
3168 qsort( (BYTE *)table + offset, num, row_size, fn );
3171 NsiFreeTable( key, NULL, dyn, stat );
3172 return err;
3175 /******************************************************************
3176 * GetExtendedTcpTable (IPHLPAPI.@)
3178 DWORD WINAPI GetExtendedTcpTable( void *table, DWORD *size, BOOL sort, ULONG family,
3179 TCP_TABLE_CLASS table_class, ULONG reserved )
3181 TRACE( "table %p, size %p, sort %d, family %u, class %u, reserved %u\n",
3182 table, size, sort, family, table_class, reserved );
3184 if (!ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3185 return get_extended_tcp_table( table, size, sort, family, table_class );
3188 /******************************************************************
3189 * GetTcpTable (IPHLPAPI.@)
3191 * Get the table of active TCP connections.
3193 * PARAMS
3194 * table [Out] buffer for TCP connections table
3195 * size [In/Out] length of output buffer
3196 * sort [In] whether to order the table
3198 * RETURNS
3199 * Success: NO_ERROR
3200 * Failure: error code from winerror.h
3202 * NOTES
3203 * If size is less than required, the function will return
3204 * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
3205 * the required byte size.
3206 * If sort is true, the returned table will be sorted, first by
3207 * local address and port number, then by remote address and port
3208 * number.
3210 DWORD WINAPI GetTcpTable( MIB_TCPTABLE *table, DWORD *size, BOOL sort )
3212 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3213 return get_extended_tcp_table( table, size, sort, WS_AF_INET, TCP_TABLE_BASIC_ALL );
3216 /******************************************************************
3217 * GetTcp6Table (IPHLPAPI.@)
3219 ULONG WINAPI GetTcp6Table( MIB_TCP6TABLE *table, ULONG *size, BOOL sort )
3221 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3222 return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE_BASIC_ALL );
3225 /******************************************************************
3226 * GetTcpTable2 (IPHLPAPI.@)
3228 ULONG WINAPI GetTcpTable2( MIB_TCPTABLE2 *table, ULONG *size, BOOL sort )
3230 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3231 return get_extended_tcp_table( table, size, sort, WS_AF_INET, TCP_TABLE2 );
3234 /******************************************************************
3235 * GetTcp6Table2 (IPHLPAPI.@)
3237 ULONG WINAPI GetTcp6Table2( MIB_TCP6TABLE2 *table, ULONG *size, BOOL sort )
3239 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3240 return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE2 );
3243 static DWORD allocate_tcp_table( void **table, BOOL sort, HANDLE heap, DWORD flags,
3244 ULONG family, ULONG table_class )
3246 DWORD err, size = 0x100, attempt;
3248 for (attempt = 0; attempt < 5; attempt++)
3250 *table = HeapAlloc( heap, flags, size );
3251 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
3252 err = get_extended_tcp_table( *table, &size, sort, family, table_class );
3253 if (!err) break;
3254 HeapFree( heap, flags, *table );
3255 *table = NULL;
3256 if (err != ERROR_INSUFFICIENT_BUFFER) break;
3258 return err;
3261 /******************************************************************
3262 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
3264 DWORD WINAPI AllocateAndGetTcpTableFromStack( MIB_TCPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
3266 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
3268 if (!table) return ERROR_INVALID_PARAMETER;
3270 return allocate_tcp_table( (void **)table, sort, heap, flags, WS_AF_INET, TCP_TABLE_BASIC_ALL );
3273 /******************************************************************
3274 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
3276 DWORD WINAPI AllocateAndGetTcpExTableFromStack( void **table, BOOL sort, HANDLE heap, DWORD flags, DWORD family )
3278 TRACE( "table %p, sort %d, heap %p, flags 0x%08x, family %u\n", table, sort, heap, flags, family );
3280 if (!table || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3281 if (family == WS_AF_INET6) return ERROR_NOT_SUPPORTED;
3283 return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
3286 /******************************************************************
3287 * GetUdpTable (IPHLPAPI.@)
3289 * Get a table of active UDP connections.
3291 * PARAMS
3292 * pUdpTable [Out] buffer for UDP connections table
3293 * pdwSize [In/Out] length of output buffer
3294 * bOrder [In] whether to order the table
3296 * RETURNS
3297 * Success: NO_ERROR
3298 * Failure: error code from winerror.h
3300 * NOTES
3301 * If pdwSize is less than required, the function will return
3302 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
3303 * required byte size.
3304 * If bOrder is true, the returned table will be sorted, first by
3305 * local address, then by local port number.
3307 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
3309 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET, UDP_TABLE_BASIC, 0);
3312 /******************************************************************
3313 * GetUdp6Table (IPHLPAPI.@)
3315 DWORD WINAPI GetUdp6Table(PMIB_UDP6TABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
3317 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, WS_AF_INET6, UDP_TABLE_BASIC, 0);
3320 /******************************************************************
3321 * GetExtendedUdpTable (IPHLPAPI.@)
3323 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
3324 ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
3326 DWORD ret, size;
3327 void *table;
3329 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
3330 pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
3332 if (!pdwSize) return ERROR_INVALID_PARAMETER;
3334 if (TableClass == UDP_TABLE_OWNER_MODULE)
3335 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
3337 switch (ulAf)
3339 case WS_AF_INET:
3340 ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
3341 break;
3343 case WS_AF_INET6:
3344 ret = build_udp6_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size);
3345 break;
3347 default:
3348 FIXME("ulAf = %u not supported\n", ulAf);
3349 ret = ERROR_NOT_SUPPORTED;
3352 if (ret)
3353 return ret;
3355 if (!pUdpTable || *pdwSize < size)
3357 *pdwSize = size;
3358 ret = ERROR_INSUFFICIENT_BUFFER;
3360 else
3362 *pdwSize = size;
3363 memcpy(pUdpTable, table, size);
3365 HeapFree(GetProcessHeap(), 0, table);
3366 return ret;
3369 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW *row, USHORT fam, void *key, struct nsi_ip_unicast_rw *rw,
3370 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
3372 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key;
3373 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key;
3375 if (fam == WS_AF_INET)
3377 row->Address.Ipv4.sin_family = fam;
3378 row->Address.Ipv4.sin_port = 0;
3379 row->Address.Ipv4.sin_addr = key4->addr;
3380 memset( row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
3381 row->InterfaceLuid.Value = key4->luid.Value;
3383 else
3385 row->Address.Ipv6.sin6_family = fam;
3386 row->Address.Ipv6.sin6_port = 0;
3387 row->Address.Ipv6.sin6_flowinfo = 0;
3388 row->Address.Ipv6.sin6_addr = key6->addr;
3389 row->Address.Ipv6.sin6_scope_id = dyn->scope_id;
3390 row->InterfaceLuid.Value = key6->luid.Value;
3393 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
3394 row->PrefixOrigin = rw->prefix_origin;
3395 row->SuffixOrigin = rw->suffix_origin;
3396 row->ValidLifetime = rw->valid_lifetime;
3397 row->PreferredLifetime = rw->preferred_lifetime;
3398 row->OnLinkPrefixLength = rw->on_link_prefix;
3399 row->SkipAsSource = 0;
3400 row->DadState = dyn->dad_state;
3401 row->ScopeId.u.Value = dyn->scope_id;
3402 row->CreationTimeStamp.QuadPart = stat->creation_time;
3405 DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW *row)
3407 struct nsi_ipv4_unicast_key key4;
3408 struct nsi_ipv6_unicast_key key6;
3409 struct nsi_ip_unicast_rw rw;
3410 struct nsi_ip_unicast_dynamic dyn;
3411 struct nsi_ip_unicast_static stat;
3412 const NPI_MODULEID *mod;
3413 DWORD err, key_size;
3414 void *key;
3416 TRACE( "%p\n", row );
3418 if (!row) return ERROR_INVALID_PARAMETER;
3419 mod = ip_module_id( row->Address.si_family );
3420 if (!mod) return ERROR_INVALID_PARAMETER;
3422 if (!row->InterfaceLuid.Value)
3424 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
3425 if (err) return err;
3428 if (row->Address.si_family == WS_AF_INET)
3430 key4.luid = row->InterfaceLuid;
3431 key4.addr = row->Address.Ipv4.sin_addr;
3432 key4.pad = 0;
3433 key = &key4;
3434 key_size = sizeof(key4);
3436 else if (row->Address.si_family == WS_AF_INET6)
3438 key6.luid = row->InterfaceLuid;
3439 key6.addr = row->Address.Ipv6.sin6_addr;
3440 key = &key6;
3441 key_size = sizeof(key6);
3443 else return ERROR_INVALID_PARAMETER;
3445 err = NsiGetAllParameters( 1, mod, NSI_IP_UNICAST_TABLE, key, key_size, &rw, sizeof(rw),
3446 &dyn, sizeof(dyn), &stat, sizeof(stat) );
3447 if (!err) unicast_row_fill( row, row->Address.si_family, key, &rw, &dyn, &stat );
3448 return err;
3451 DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY family, MIB_UNICASTIPADDRESS_TABLE **table)
3453 void *key[2] = { NULL, NULL };
3454 struct nsi_ip_unicast_rw *rw[2] = { NULL, NULL };
3455 struct nsi_ip_unicast_dynamic *dyn[2] = { NULL, NULL };
3456 struct nsi_ip_unicast_static *stat[2] = { NULL, NULL };
3457 static const USHORT fam[2] = { WS_AF_INET, WS_AF_INET6 };
3458 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ipv6_unicast_key) };
3459 DWORD err, i, size, count[2] = { 0, 0 };
3461 TRACE( "%u, %p\n", family, table );
3463 if (!table || (family != WS_AF_INET && family != WS_AF_INET6 && family != WS_AF_UNSPEC))
3464 return ERROR_INVALID_PARAMETER;
3466 for (i = 0; i < 2; i++)
3468 if (family != WS_AF_UNSPEC && family != fam[i]) continue;
3470 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_UNICAST_TABLE, key + i, key_size[i],
3471 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
3472 (void **)stat + i, sizeof(**stat), count + i, 0 );
3473 if (err) goto err;
3476 size = FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE, Table[ count[0] + count[1] ]);
3477 *table = heap_alloc( size );
3478 if (!*table)
3480 err = ERROR_NOT_ENOUGH_MEMORY;
3481 goto err;
3484 (*table)->NumEntries = count[0] + count[1];
3485 for (i = 0; i < count[0]; i++)
3487 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + i;
3488 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key[0];
3490 unicast_row_fill( row, fam[0], (void *)(key4 + i), rw[0] + i, dyn[0] + i, stat[0] + i );
3493 for (i = 0; i < count[1]; i++)
3495 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + count[0] + i;
3496 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key[1];
3498 unicast_row_fill( row, fam[1], (void *)(key6 + i), rw[1] + i, dyn[1] + i, stat[1] + i );
3501 err:
3502 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
3503 return err;
3506 /******************************************************************
3507 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3509 * This is a Win98-only function to get information on "unidirectional"
3510 * adapters. Since this is pretty nonsensical in other contexts, it
3511 * never returns anything.
3513 * PARAMS
3514 * pIPIfInfo [Out] buffer for adapter infos
3515 * dwOutBufLen [Out] length of the output buffer
3517 * RETURNS
3518 * Success: NO_ERROR
3519 * Failure: error code from winerror.h
3521 * FIXME
3522 * Stub, returns ERROR_NOT_SUPPORTED.
3524 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
3526 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
3527 /* a unidirectional adapter?? not bloody likely! */
3528 return ERROR_NOT_SUPPORTED;
3532 /******************************************************************
3533 * IpReleaseAddress (IPHLPAPI.@)
3535 * Release an IP obtained through DHCP,
3537 * PARAMS
3538 * AdapterInfo [In] adapter to release IP address
3540 * RETURNS
3541 * Success: NO_ERROR
3542 * Failure: error code from winerror.h
3544 * NOTES
3545 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3546 * this function does nothing.
3548 * FIXME
3549 * Stub, returns ERROR_NOT_SUPPORTED.
3551 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3553 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3554 return ERROR_NOT_SUPPORTED;
3558 /******************************************************************
3559 * IpRenewAddress (IPHLPAPI.@)
3561 * Renew an IP obtained through DHCP.
3563 * PARAMS
3564 * AdapterInfo [In] adapter to renew IP address
3566 * RETURNS
3567 * Success: NO_ERROR
3568 * Failure: error code from winerror.h
3570 * NOTES
3571 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3572 * this function does nothing.
3574 * FIXME
3575 * Stub, returns ERROR_NOT_SUPPORTED.
3577 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3579 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3580 return ERROR_NOT_SUPPORTED;
3584 /******************************************************************
3585 * NotifyAddrChange (IPHLPAPI.@)
3587 * Notify caller whenever the ip-interface map is changed.
3589 * PARAMS
3590 * Handle [Out] handle usable in asynchronous notification
3591 * overlapped [In] overlapped structure that notifies the caller
3593 * RETURNS
3594 * Success: NO_ERROR
3595 * Failure: error code from winerror.h
3597 * FIXME
3598 * Stub, returns ERROR_NOT_SUPPORTED.
3600 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3602 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3603 if (Handle) *Handle = INVALID_HANDLE_VALUE;
3604 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
3605 return ERROR_IO_PENDING;
3609 /******************************************************************
3610 * NotifyIpInterfaceChange (IPHLPAPI.@)
3612 DWORD WINAPI NotifyIpInterfaceChange(ADDRESS_FAMILY family, PIPINTERFACE_CHANGE_CALLBACK callback,
3613 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3615 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3616 family, callback, context, init_notify, handle);
3617 if (handle) *handle = NULL;
3618 return NO_ERROR;
3621 /******************************************************************
3622 * NotifyRouteChange2 (IPHLPAPI.@)
3624 DWORD WINAPI NotifyRouteChange2(ADDRESS_FAMILY family, PIPFORWARD_CHANGE_CALLBACK callback, VOID* context,
3625 BOOLEAN init_notify, HANDLE* handle)
3627 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3628 family, callback, context, init_notify, handle);
3629 if (handle) *handle = NULL;
3630 return NO_ERROR;
3634 /******************************************************************
3635 * NotifyRouteChange (IPHLPAPI.@)
3637 * Notify caller whenever the ip routing table is changed.
3639 * PARAMS
3640 * Handle [Out] handle usable in asynchronous notification
3641 * overlapped [In] overlapped structure that notifies the caller
3643 * RETURNS
3644 * Success: NO_ERROR
3645 * Failure: error code from winerror.h
3647 * FIXME
3648 * Stub, returns ERROR_NOT_SUPPORTED.
3650 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3652 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3653 return ERROR_NOT_SUPPORTED;
3657 /******************************************************************
3658 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3660 DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback,
3661 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3663 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3664 family, callback, context, init_notify, handle);
3665 if (handle) *handle = NULL;
3667 if (init_notify)
3668 callback(context, NULL, MibInitialNotification);
3670 return NO_ERROR;
3673 /******************************************************************
3674 * SendARP (IPHLPAPI.@)
3676 * Send an ARP request.
3678 * PARAMS
3679 * DestIP [In] attempt to obtain this IP
3680 * SrcIP [In] optional sender IP address
3681 * pMacAddr [Out] buffer for the mac address
3682 * PhyAddrLen [In/Out] length of the output buffer
3684 * RETURNS
3685 * Success: NO_ERROR
3686 * Failure: error code from winerror.h
3688 * FIXME
3689 * Stub, returns ERROR_NOT_SUPPORTED.
3691 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
3693 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
3694 DestIP, SrcIP, pMacAddr, PhyAddrLen);
3695 return ERROR_NOT_SUPPORTED;
3699 /******************************************************************
3700 * SetIfEntry (IPHLPAPI.@)
3702 * Set the administrative status of an interface.
3704 * PARAMS
3705 * pIfRow [In] dwAdminStatus member specifies the new status.
3707 * RETURNS
3708 * Success: NO_ERROR
3709 * Failure: error code from winerror.h
3711 * FIXME
3712 * Stub, returns ERROR_NOT_SUPPORTED.
3714 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
3716 FIXME("(pIfRow %p): stub\n", pIfRow);
3717 /* this is supposed to set an interface administratively up or down.
3718 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3719 this sort of down is indistinguishable from other sorts of down (e.g. no
3720 link). */
3721 return ERROR_NOT_SUPPORTED;
3725 /******************************************************************
3726 * SetIpForwardEntry (IPHLPAPI.@)
3728 * Modify an existing route.
3730 * PARAMS
3731 * pRoute [In] route with the new information
3733 * RETURNS
3734 * Success: NO_ERROR
3735 * Failure: error code from winerror.h
3737 * FIXME
3738 * Stub, returns NO_ERROR.
3740 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
3742 FIXME("(pRoute %p): stub\n", pRoute);
3743 /* this is to add a route entry, how's it distinguishable from
3744 CreateIpForwardEntry?
3745 could use SIOCADDRT, not sure I want to */
3746 return 0;
3750 /******************************************************************
3751 * SetIpNetEntry (IPHLPAPI.@)
3753 * Modify an existing ARP entry.
3755 * PARAMS
3756 * pArpEntry [In] ARP entry with the new information
3758 * RETURNS
3759 * Success: NO_ERROR
3760 * Failure: error code from winerror.h
3762 * FIXME
3763 * Stub, returns NO_ERROR.
3765 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3767 FIXME("(pArpEntry %p): stub\n", pArpEntry);
3768 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3769 return 0;
3773 /******************************************************************
3774 * SetIpStatistics (IPHLPAPI.@)
3776 * Toggle IP forwarding and det the default TTL value.
3778 * PARAMS
3779 * pIpStats [In] IP statistics with the new information
3781 * RETURNS
3782 * Success: NO_ERROR
3783 * Failure: error code from winerror.h
3785 * FIXME
3786 * Stub, returns NO_ERROR.
3788 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3790 FIXME("(pIpStats %p): stub\n", pIpStats);
3791 return 0;
3795 /******************************************************************
3796 * SetIpTTL (IPHLPAPI.@)
3798 * Set the default TTL value.
3800 * PARAMS
3801 * nTTL [In] new TTL value
3803 * RETURNS
3804 * Success: NO_ERROR
3805 * Failure: error code from winerror.h
3807 * FIXME
3808 * Stub, returns NO_ERROR.
3810 DWORD WINAPI SetIpTTL(UINT nTTL)
3812 FIXME("(nTTL %d): stub\n", nTTL);
3813 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
3814 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
3815 return 0;
3819 /******************************************************************
3820 * SetTcpEntry (IPHLPAPI.@)
3822 * Set the state of a TCP connection.
3824 * PARAMS
3825 * pTcpRow [In] specifies connection with new state
3827 * RETURNS
3828 * Success: NO_ERROR
3829 * Failure: error code from winerror.h
3831 * FIXME
3832 * Stub, returns NO_ERROR.
3834 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3836 FIXME("(pTcpRow %p): stub\n", pTcpRow);
3837 return 0;
3840 /******************************************************************
3841 * SetPerTcpConnectionEStats (IPHLPAPI.@)
3843 DWORD WINAPI SetPerTcpConnectionEStats(PMIB_TCPROW row, TCP_ESTATS_TYPE state, PBYTE rw,
3844 ULONG version, ULONG size, ULONG offset)
3846 FIXME("(row %p, state %d, rw %p, version %u, size %u, offset %u): stub\n",
3847 row, state, rw, version, size, offset);
3848 return ERROR_NOT_SUPPORTED;
3852 /******************************************************************
3853 * UnenableRouter (IPHLPAPI.@)
3855 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3856 * if it reaches zero.
3858 * PARAMS
3859 * pOverlapped [In/Out] should be the same as in EnableRouter()
3860 * lpdwEnableCount [Out] optional, receives reference count
3862 * RETURNS
3863 * Success: NO_ERROR
3864 * Failure: error code from winerror.h
3866 * FIXME
3867 * Stub, returns ERROR_NOT_SUPPORTED.
3869 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3871 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3872 lpdwEnableCount);
3873 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
3874 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
3876 return ERROR_NOT_SUPPORTED;
3879 /******************************************************************
3880 * PfCreateInterface (IPHLPAPI.@)
3882 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
3883 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
3885 FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
3886 return ERROR_CALL_NOT_IMPLEMENTED;
3889 /******************************************************************
3890 * PfUnBindInterface (IPHLPAPI.@)
3892 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
3894 FIXME("(%p) stub\n", interface);
3895 return ERROR_CALL_NOT_IMPLEMENTED;
3898 /******************************************************************
3899 * PfDeleteInterface(IPHLPAPI.@)
3901 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
3903 FIXME("(%p) stub\n", interface);
3904 return ERROR_CALL_NOT_IMPLEMENTED;
3907 /******************************************************************
3908 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
3910 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
3912 FIXME("(%p %d %p) stub\n", interface, type, ip);
3913 return ERROR_CALL_NOT_IMPLEMENTED;
3916 /******************************************************************
3917 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
3919 DWORD WINAPI ConvertInterfaceAliasToLuid( const WCHAR *alias, NET_LUID *luid )
3921 struct nsi_ndis_ifinfo_rw *data;
3922 DWORD err, count, i, len;
3923 NET_LUID *keys;
3925 TRACE( "(%s %p)\n", debugstr_w(alias), luid );
3927 if (!alias || !*alias || !luid) return ERROR_INVALID_PARAMETER;
3928 luid->Value = 0;
3929 len = strlenW( alias );
3931 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3932 (void **)&data, sizeof(*data), NULL, 0, NULL, 0, &count, 0 );
3933 if (err) return err;
3935 err = ERROR_INVALID_PARAMETER;
3936 for (i = 0; i < count; i++)
3938 if (data[i].alias.Length == len * 2 && !memcmp( data[i].alias.String, alias, len * 2 ))
3940 luid->Value = keys[i].Value;
3941 err = ERROR_SUCCESS;
3942 break;
3945 NsiFreeTable( keys, data, NULL, NULL );
3946 return err;
3949 /******************************************************************
3950 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
3952 DWORD WINAPI ConvertInterfaceGuidToLuid(const GUID *guid, NET_LUID *luid)
3954 struct nsi_ndis_ifinfo_static *data;
3955 DWORD err, count, i;
3956 NET_LUID *keys;
3958 TRACE( "(%s %p)\n", debugstr_guid(guid), luid );
3960 if (!guid || !luid) return ERROR_INVALID_PARAMETER;
3961 luid->Value = 0;
3963 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
3964 NULL, 0, NULL, 0, (void **)&data, sizeof(*data), &count, 0 );
3965 if (err) return err;
3967 err = ERROR_INVALID_PARAMETER;
3968 for (i = 0; i < count; i++)
3970 if (IsEqualGUID( &data[i].if_guid, guid ))
3972 luid->Value = keys[i].Value;
3973 err = ERROR_SUCCESS;
3974 break;
3977 NsiFreeTable( keys, NULL, NULL, data );
3978 return err;
3981 /******************************************************************
3982 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
3984 DWORD WINAPI ConvertInterfaceIndexToLuid(NET_IFINDEX index, NET_LUID *luid)
3986 DWORD err;
3988 TRACE( "(%u %p)\n", index, luid );
3990 if (!luid) return ERROR_INVALID_PARAMETER;
3992 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &index, sizeof(index),
3993 NSI_PARAM_TYPE_STATIC, luid, sizeof(*luid), 0 );
3994 if (err) luid->Value = 0;
3995 return err;
3998 /******************************************************************
3999 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4001 DWORD WINAPI ConvertInterfaceLuidToAlias( const NET_LUID *luid, WCHAR *alias, SIZE_T len )
4003 DWORD err;
4004 IF_COUNTED_STRING name;
4006 TRACE( "(%p %p %u)\n", luid, alias, (DWORD)len );
4008 if (!luid || !alias) return ERROR_INVALID_PARAMETER;
4010 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4011 NSI_PARAM_TYPE_RW, &name, sizeof(name),
4012 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw, alias) );
4013 if (err) return err;
4015 if (len <= name.Length / sizeof(WCHAR)) return ERROR_NOT_ENOUGH_MEMORY;
4016 memcpy( alias, name.String, name.Length );
4017 alias[name.Length / sizeof(WCHAR)] = '\0';
4019 return err;
4022 /******************************************************************
4023 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4025 DWORD WINAPI ConvertInterfaceLuidToGuid(const NET_LUID *luid, GUID *guid)
4027 DWORD err;
4029 TRACE( "(%p %p)\n", luid, guid );
4031 if (!luid || !guid) return ERROR_INVALID_PARAMETER;
4033 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4034 NSI_PARAM_TYPE_STATIC, guid, sizeof(*guid),
4035 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_guid) );
4036 if (err) memset( guid, 0, sizeof(*guid) );
4037 return err;
4040 /******************************************************************
4041 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4043 DWORD WINAPI ConvertInterfaceLuidToIndex(const NET_LUID *luid, NET_IFINDEX *index)
4045 DWORD err;
4047 TRACE( "(%p %p)\n", luid, index );
4049 if (!luid || !index) return ERROR_INVALID_PARAMETER;
4051 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4052 NSI_PARAM_TYPE_STATIC, index, sizeof(*index),
4053 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index) );
4054 if (err) *index = 0;
4055 return err;
4058 /******************************************************************
4059 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4061 DWORD WINAPI ConvertInterfaceLuidToNameA(const NET_LUID *luid, char *name, SIZE_T len)
4063 DWORD err;
4064 WCHAR nameW[IF_MAX_STRING_SIZE + 1];
4066 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
4068 if (!luid) return ERROR_INVALID_PARAMETER;
4069 if (!name || !len) return ERROR_NOT_ENOUGH_MEMORY;
4071 err = ConvertInterfaceLuidToNameW( luid, nameW, ARRAY_SIZE(nameW) );
4072 if (err) return err;
4074 if (!WideCharToMultiByte( CP_UNIXCP, 0, nameW, -1, name, len, NULL, NULL ))
4075 err = GetLastError();
4076 return err;
4079 static const WCHAR otherW[] = {'o','t','h','e','r',0};
4080 static const WCHAR ethernetW[] = {'e','t','h','e','r','n','e','t',0};
4081 static const WCHAR tokenringW[] = {'t','o','k','e','n','r','i','n','g',0};
4082 static const WCHAR pppW[] = {'p','p','p',0};
4083 static const WCHAR loopbackW[] = {'l','o','o','p','b','a','c','k',0};
4084 static const WCHAR atmW[] = {'a','t','m',0};
4085 static const WCHAR wirelessW[] = {'w','i','r','e','l','e','s','s',0};
4086 static const WCHAR tunnelW[] = {'t','u','n','n','e','l',0};
4087 static const WCHAR ieee1394W[] = {'i','e','e','e','1','3','9','4',0};
4089 struct name_prefix
4091 const WCHAR *prefix;
4092 DWORD type;
4094 static const struct name_prefix name_prefixes[] =
4096 { otherW, IF_TYPE_OTHER },
4097 { ethernetW, IF_TYPE_ETHERNET_CSMACD },
4098 { tokenringW, IF_TYPE_ISO88025_TOKENRING },
4099 { pppW, IF_TYPE_PPP },
4100 { loopbackW, IF_TYPE_SOFTWARE_LOOPBACK },
4101 { atmW, IF_TYPE_ATM },
4102 { wirelessW, IF_TYPE_IEEE80211 },
4103 { tunnelW, IF_TYPE_TUNNEL },
4104 { ieee1394W, IF_TYPE_IEEE1394 }
4107 /******************************************************************
4108 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4110 DWORD WINAPI ConvertInterfaceLuidToNameW(const NET_LUID *luid, WCHAR *name, SIZE_T len)
4112 DWORD i, needed;
4113 const WCHAR *prefix = NULL;
4114 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4115 static const WCHAR prefix_fmt[] = {'%','s','_','%','d',0};
4116 static const WCHAR unk_fmt[] = {'i','f','t','y','p','e','%','d','_','%','d',0};
4118 TRACE( "(%p %p %u)\n", luid, name, (DWORD)len );
4120 if (!luid || !name) return ERROR_INVALID_PARAMETER;
4122 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4124 if (luid->Info.IfType == name_prefixes[i].type)
4126 prefix = name_prefixes[i].prefix;
4127 break;
4131 if (prefix) needed = snprintfW( buf, len, prefix_fmt, prefix, luid->Info.NetLuidIndex );
4132 else needed = snprintfW( buf, len, unk_fmt, luid->Info.IfType, luid->Info.NetLuidIndex );
4134 if (needed >= len) return ERROR_NOT_ENOUGH_MEMORY;
4135 memcpy( name, buf, (needed + 1) * sizeof(WCHAR) );
4136 return ERROR_SUCCESS;
4139 /******************************************************************
4140 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4142 DWORD WINAPI ConvertInterfaceNameToLuidA(const char *name, NET_LUID *luid)
4144 WCHAR nameW[IF_MAX_STRING_SIZE];
4146 TRACE( "(%s %p)\n", debugstr_a(name), luid );
4148 if (!name) return ERROR_INVALID_NAME;
4149 if (!MultiByteToWideChar( CP_UNIXCP, 0, name, -1, nameW, ARRAY_SIZE(nameW) ))
4150 return GetLastError();
4152 return ConvertInterfaceNameToLuidW( nameW, luid );
4155 /******************************************************************
4156 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4158 DWORD WINAPI ConvertInterfaceNameToLuidW(const WCHAR *name, NET_LUID *luid)
4160 const WCHAR *sep;
4161 static const WCHAR iftype[] = {'i','f','t','y','p','e',0};
4162 DWORD type = ~0u, i;
4163 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4165 TRACE( "(%s %p)\n", debugstr_w(name), luid );
4167 if (!luid) return ERROR_INVALID_PARAMETER;
4168 memset( luid, 0, sizeof(*luid) );
4170 if (!name || !(sep = strchrW( name, '_' )) || sep >= name + ARRAY_SIZE(buf)) return ERROR_INVALID_NAME;
4171 memcpy( buf, name, (sep - name) * sizeof(WCHAR) );
4172 buf[sep - name] = '\0';
4174 if (sep - name > ARRAY_SIZE(iftype) - 1 && !memcmp( buf, iftype, (ARRAY_SIZE(iftype) - 1) * sizeof(WCHAR) ))
4176 type = atoiW( buf + ARRAY_SIZE(iftype) - 1 );
4178 else
4180 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4182 if (!strcmpW( buf, name_prefixes[i].prefix ))
4184 type = name_prefixes[i].type;
4185 break;
4189 if (type == ~0u) return ERROR_INVALID_NAME;
4191 luid->Info.NetLuidIndex = atoiW( sep + 1 );
4192 luid->Info.IfType = type;
4193 return ERROR_SUCCESS;
4196 /******************************************************************
4197 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4199 DWORD WINAPI ConvertLengthToIpv4Mask(ULONG mask_len, ULONG *mask)
4201 if (mask_len > 32)
4203 *mask = INADDR_NONE;
4204 return ERROR_INVALID_PARAMETER;
4207 if (mask_len == 0)
4208 *mask = 0;
4209 else
4210 *mask = htonl(~0u << (32 - mask_len));
4212 return NO_ERROR;
4215 /******************************************************************
4216 * if_nametoindex (IPHLPAPI.@)
4218 IF_INDEX WINAPI IPHLP_if_nametoindex(const char *name)
4220 IF_INDEX index;
4221 NET_LUID luid;
4222 DWORD err;
4224 TRACE( "(%s)\n", name );
4226 err = ConvertInterfaceNameToLuidA( name, &luid );
4227 if (err) return 0;
4229 err = ConvertInterfaceLuidToIndex( &luid, &index );
4230 if (err) index = 0;
4231 return index;
4234 /******************************************************************
4235 * if_indextoname (IPHLPAPI.@)
4237 char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
4239 NET_LUID luid;
4240 DWORD err;
4242 TRACE( "(%u, %p)\n", index, name );
4244 err = ConvertInterfaceIndexToLuid( index, &luid );
4245 if (err) return NULL;
4247 err = ConvertInterfaceLuidToNameA( &luid, name, IF_MAX_STRING_SIZE );
4248 if (err) return NULL;
4249 return name;
4252 /******************************************************************
4253 * GetIpInterfaceTable (IPHLPAPI.@)
4255 DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table)
4257 FIXME("(%u %p): stub\n", family, table);
4258 return ERROR_NOT_SUPPORTED;
4261 /******************************************************************
4262 * GetBestRoute2 (IPHLPAPI.@)
4264 DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
4265 const SOCKADDR_INET *source, const SOCKADDR_INET *destination,
4266 ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
4267 SOCKADDR_INET *bestaddress)
4269 static int once;
4271 if (!once++)
4272 FIXME("(%p, %d, %p, %p, 0x%08x, %p, %p): stub\n", luid, index, source,
4273 destination, options, bestroute, bestaddress);
4275 if (!destination || !bestroute || !bestaddress)
4276 return ERROR_INVALID_PARAMETER;
4278 return ERROR_NOT_SUPPORTED;
4281 /******************************************************************
4282 * ParseNetworkString (IPHLPAPI.@)
4284 DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
4285 NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len)
4287 IN_ADDR temp_addr4;
4288 IN6_ADDR temp_addr6;
4289 ULONG temp_scope;
4290 USHORT temp_port = 0;
4291 NTSTATUS status;
4293 TRACE("(%s, %d, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len);
4295 if (!str)
4296 return ERROR_INVALID_PARAMETER;
4298 if (type & NET_STRING_IPV4_ADDRESS)
4300 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4301 if (SUCCEEDED(status) && !temp_port)
4303 if (info)
4305 info->Format = NET_ADDRESS_IPV4;
4306 info->u.Ipv4Address.sin_addr = temp_addr4;
4307 info->u.Ipv4Address.sin_port = 0;
4309 if (port) *port = 0;
4310 if (prefix_len) *prefix_len = 255;
4311 return ERROR_SUCCESS;
4314 if (type & NET_STRING_IPV4_SERVICE)
4316 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4317 if (SUCCEEDED(status) && temp_port)
4319 if (info)
4321 info->Format = NET_ADDRESS_IPV4;
4322 info->u.Ipv4Address.sin_addr = temp_addr4;
4323 info->u.Ipv4Address.sin_port = temp_port;
4325 if (port) *port = ntohs(temp_port);
4326 if (prefix_len) *prefix_len = 255;
4327 return ERROR_SUCCESS;
4330 if (type & NET_STRING_IPV6_ADDRESS)
4332 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4333 if (SUCCEEDED(status) && !temp_port)
4335 if (info)
4337 info->Format = NET_ADDRESS_IPV6;
4338 info->u.Ipv6Address.sin6_addr = temp_addr6;
4339 info->u.Ipv6Address.sin6_scope_id = temp_scope;
4340 info->u.Ipv6Address.sin6_port = 0;
4342 if (port) *port = 0;
4343 if (prefix_len) *prefix_len = 255;
4344 return ERROR_SUCCESS;
4347 if (type & NET_STRING_IPV6_SERVICE)
4349 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4350 if (SUCCEEDED(status) && temp_port)
4352 if (info)
4354 info->Format = NET_ADDRESS_IPV6;
4355 info->u.Ipv6Address.sin6_addr = temp_addr6;
4356 info->u.Ipv6Address.sin6_scope_id = temp_scope;
4357 info->u.Ipv6Address.sin6_port = temp_port;
4359 if (port) *port = ntohs(temp_port);
4360 if (prefix_len) *prefix_len = 255;
4361 return ERROR_SUCCESS;
4365 if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED;
4367 if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_ADDRESS|NET_STRING_IPV6_SERVICE))
4369 FIXME("Unimplemented type 0x%x\n", type);
4370 return ERROR_NOT_SUPPORTED;
4373 return ERROR_INVALID_PARAMETER;