iphlpapi: Handle errors from DnsQueryConfig(DnsConfigDnsServerList).
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blobf8fb5de3f0e32433f6d4c7a38fc6b408bc144981
1 /*
2 * iphlpapi dll implementation
4 * Copyright (C) 2003,2006 Juan Lang
5 * Copyright 2021 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winsock2.h"
27 #include "winternl.h"
28 #include "ws2ipdef.h"
29 #include "windns.h"
30 #include "iphlpapi.h"
31 #include "ipifcons.h"
32 #include "fltdefs.h"
33 #include "ifdef.h"
34 #include "netioapi.h"
35 #include "tcpestats.h"
36 #include "ip2string.h"
37 #include "netiodef.h"
38 #include "icmpapi.h"
40 #include "wine/nsi.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
46 #define CHARS_IN_GUID 39
48 static const WCHAR *device_tcpip = L"\\DEVICE\\TCPIP_";
50 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags );
52 static const NPI_MODULEID *ip_module_id( USHORT family )
54 if (family == AF_INET) return &NPI_MS_IPV4_MODULEID;
55 if (family == AF_INET6) return &NPI_MS_IPV6_MODULEID;
56 return NULL;
59 DWORD WINAPI ConvertGuidToStringA( const GUID *guid, char *str, DWORD len )
61 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
62 sprintf( str, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
63 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
64 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
65 return ERROR_SUCCESS;
68 DWORD WINAPI ConvertGuidToStringW( const GUID *guid, WCHAR *str, DWORD len )
70 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
71 swprintf( str, len, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
72 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
73 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
74 return ERROR_SUCCESS;
77 DWORD WINAPI ConvertStringToGuidW( const WCHAR *str, GUID *guid )
79 UNICODE_STRING ustr;
81 RtlInitUnicodeString( &ustr, str );
82 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr, guid ) );
85 static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
87 unsigned int copy = src->Length;
89 if (copy >= len * sizeof(WCHAR)) copy = 0;
90 memcpy( dst, src->String, copy );
91 memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
94 /******************************************************************
95 * AddIPAddress (IPHLPAPI.@)
97 * Add an IP address to an adapter.
99 * PARAMS
100 * Address [In] IP address to add to the adapter
101 * IpMask [In] subnet mask for the IP address
102 * IfIndex [In] adapter index to add the address
103 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
104 * NTEInstance [Out] NTE instance for the IP address
106 * RETURNS
107 * Success: NO_ERROR
108 * Failure: error code from winerror.h
110 * FIXME
111 * Stub. Currently returns ERROR_NOT_SUPPORTED.
113 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
115 FIXME(":stub\n");
116 return ERROR_NOT_SUPPORTED;
119 /******************************************************************
120 * CancelIPChangeNotify (IPHLPAPI.@)
122 * Cancel a previous notification created by NotifyAddrChange or
123 * NotifyRouteChange.
125 * PARAMS
126 * overlapped [In] overlapped structure that notifies the caller
128 * RETURNS
129 * Success: TRUE
130 * Failure: FALSE
132 * FIXME
133 * Stub, returns FALSE.
135 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
137 FIXME("(overlapped %p): stub\n", overlapped);
138 return FALSE;
142 /******************************************************************
143 * CancelMibChangeNotify2 (IPHLPAPI.@)
145 DWORD WINAPI CancelMibChangeNotify2(HANDLE handle)
147 FIXME("(handle %p): stub\n", handle);
148 return NO_ERROR;
152 /******************************************************************
153 * CreateIpForwardEntry (IPHLPAPI.@)
155 * Create a route in the local computer's IP table.
157 * PARAMS
158 * pRoute [In] new route information
160 * RETURNS
161 * Success: NO_ERROR
162 * Failure: error code from winerror.h
164 * FIXME
165 * Stub, always returns NO_ERROR.
167 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
169 FIXME("(pRoute %p): stub\n", pRoute);
170 /* could use SIOCADDRT, not sure I want to */
171 return 0;
175 /******************************************************************
176 * CreateIpNetEntry (IPHLPAPI.@)
178 * Create entry in the ARP table.
180 * PARAMS
181 * pArpEntry [In] new ARP entry
183 * RETURNS
184 * Success: NO_ERROR
185 * Failure: error code from winerror.h
187 * FIXME
188 * Stub, always returns NO_ERROR.
190 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
192 FIXME("(pArpEntry %p)\n", pArpEntry);
193 /* could use SIOCSARP on systems that support it, not sure I want to */
194 return 0;
198 /******************************************************************
199 * CreateProxyArpEntry (IPHLPAPI.@)
201 * Create a Proxy ARP (PARP) entry for an IP address.
203 * PARAMS
204 * dwAddress [In] IP address for which this computer acts as a proxy.
205 * dwMask [In] subnet mask for dwAddress
206 * dwIfIndex [In] interface index
208 * RETURNS
209 * Success: NO_ERROR
210 * Failure: error code from winerror.h
212 * FIXME
213 * Stub, returns ERROR_NOT_SUPPORTED.
215 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
217 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
218 dwAddress, dwMask, dwIfIndex);
219 return ERROR_NOT_SUPPORTED;
222 static char *debugstr_ipv6(const struct sockaddr_in6 *sin, char *buf)
224 const IN6_ADDR *addr = &sin->sin6_addr;
225 char *p = buf;
226 int i;
227 BOOL in_zero = FALSE;
229 for (i = 0; i < 7; i++)
231 if (!addr->u.Word[i])
233 if (i == 0)
234 *p++ = ':';
235 if (!in_zero)
237 *p++ = ':';
238 in_zero = TRUE;
241 else
243 p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
244 in_zero = FALSE;
247 sprintf(p, "%x", ntohs(addr->u.Word[7]));
248 return buf;
251 static BOOL map_address_6to4( const SOCKADDR_IN6 *addr6, SOCKADDR_IN *addr4 )
253 ULONG i;
255 if (addr6->sin6_family != AF_INET6) return FALSE;
257 for (i = 0; i < 5; i++)
258 if (addr6->sin6_addr.u.Word[i]) return FALSE;
260 if (addr6->sin6_addr.u.Word[5] != 0xffff) return FALSE;
262 addr4->sin_family = AF_INET;
263 addr4->sin_port = addr6->sin6_port;
264 addr4->sin_addr.S_un.S_addr = addr6->sin6_addr.u.Word[6] << 16 | addr6->sin6_addr.u.Word[7];
265 memset( &addr4->sin_zero, 0, sizeof(addr4->sin_zero) );
267 return TRUE;
270 static BOOL find_src_address( MIB_IPADDRTABLE *table, const SOCKADDR_IN *dst, SOCKADDR_IN6 *src )
272 MIB_IPFORWARDROW row;
273 DWORD i, j;
275 if (GetBestRoute( dst->sin_addr.S_un.S_addr, 0, &row )) return FALSE;
277 for (i = 0; i < table->dwNumEntries; i++)
279 /* take the first address */
280 if (table->table[i].dwIndex == row.dwForwardIfIndex)
282 src->sin6_family = AF_INET6;
283 src->sin6_port = 0;
284 src->sin6_flowinfo = 0;
285 for (j = 0; j < 5; j++) src->sin6_addr.u.Word[j] = 0;
286 src->sin6_addr.u.Word[5] = 0xffff;
287 src->sin6_addr.u.Word[6] = table->table[i].dwAddr & 0xffff;
288 src->sin6_addr.u.Word[7] = table->table[i].dwAddr >> 16;
289 return TRUE;
293 return FALSE;
296 /******************************************************************
297 * CreateSortedAddressPairs (IPHLPAPI.@)
299 DWORD WINAPI CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list, DWORD src_count,
300 const PSOCKADDR_IN6 dst_list, DWORD dst_count,
301 DWORD options, PSOCKADDR_IN6_PAIR *pair_list,
302 DWORD *pair_count )
304 DWORD i, size, ret;
305 SOCKADDR_IN6_PAIR *pairs;
306 SOCKADDR_IN6 *ptr;
307 SOCKADDR_IN addr4;
308 MIB_IPADDRTABLE *table;
310 FIXME( "(src_list %p src_count %lu dst_list %p dst_count %lu options %lx pair_list %p pair_count %p): stub\n",
311 src_list, src_count, dst_list, dst_count, options, pair_list, pair_count );
313 if (src_list || src_count || !dst_list || !pair_list || !pair_count || dst_count > 500)
314 return ERROR_INVALID_PARAMETER;
316 for (i = 0; i < dst_count; i++)
318 if (!map_address_6to4( &dst_list[i], &addr4 ))
320 FIXME("only mapped IPv4 addresses are supported\n");
321 return ERROR_NOT_SUPPORTED;
325 size = dst_count * sizeof(*pairs);
326 size += dst_count * sizeof(SOCKADDR_IN6) * 2; /* source address + destination address */
327 if (!(pairs = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_NOT_ENOUGH_MEMORY;
328 ptr = (SOCKADDR_IN6 *)&pairs[dst_count];
330 if ((ret = AllocateAndGetIpAddrTableFromStack( &table, FALSE, GetProcessHeap(), 0 )))
332 HeapFree( GetProcessHeap(), 0, pairs );
333 return ret;
336 for (i = 0; i < dst_count; i++)
338 pairs[i].SourceAddress = ptr++;
339 if (!map_address_6to4( &dst_list[i], &addr4 ) ||
340 !find_src_address( table, &addr4, pairs[i].SourceAddress ))
342 char buf[46];
343 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list[i], buf) );
344 memset( pairs[i].SourceAddress, 0, sizeof(*pairs[i].SourceAddress) );
345 pairs[i].SourceAddress->sin6_family = AF_INET6;
348 pairs[i].DestinationAddress = ptr++;
349 memcpy( pairs[i].DestinationAddress, &dst_list[i], sizeof(*pairs[i].DestinationAddress) );
351 *pair_list = pairs;
352 *pair_count = dst_count;
354 HeapFree( GetProcessHeap(), 0, table );
355 return NO_ERROR;
359 /******************************************************************
360 * DeleteIPAddress (IPHLPAPI.@)
362 * Delete an IP address added with AddIPAddress().
364 * PARAMS
365 * NTEContext [In] NTE context from AddIPAddress();
367 * RETURNS
368 * Success: NO_ERROR
369 * Failure: error code from winerror.h
371 * FIXME
372 * Stub, returns ERROR_NOT_SUPPORTED.
374 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
376 FIXME("(NTEContext %ld): stub\n", NTEContext);
377 return ERROR_NOT_SUPPORTED;
381 /******************************************************************
382 * DeleteIpForwardEntry (IPHLPAPI.@)
384 * Delete a route.
386 * PARAMS
387 * pRoute [In] route to delete
389 * RETURNS
390 * Success: NO_ERROR
391 * Failure: error code from winerror.h
393 * FIXME
394 * Stub, returns NO_ERROR.
396 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
398 FIXME("(pRoute %p): stub\n", pRoute);
399 /* could use SIOCDELRT, not sure I want to */
400 return 0;
404 /******************************************************************
405 * DeleteIpNetEntry (IPHLPAPI.@)
407 * Delete an ARP entry.
409 * PARAMS
410 * pArpEntry [In] ARP entry to delete
412 * RETURNS
413 * Success: NO_ERROR
414 * Failure: error code from winerror.h
416 * FIXME
417 * Stub, returns NO_ERROR.
419 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
421 FIXME("(pArpEntry %p): stub\n", pArpEntry);
422 /* could use SIOCDARP on systems that support it, not sure I want to */
423 return 0;
427 /******************************************************************
428 * DeleteProxyArpEntry (IPHLPAPI.@)
430 * Delete a Proxy ARP entry.
432 * PARAMS
433 * dwAddress [In] IP address for which this computer acts as a proxy.
434 * dwMask [In] subnet mask for dwAddress
435 * dwIfIndex [In] interface index
437 * RETURNS
438 * Success: NO_ERROR
439 * Failure: error code from winerror.h
441 * FIXME
442 * Stub, returns ERROR_NOT_SUPPORTED.
444 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
446 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
447 dwAddress, dwMask, dwIfIndex);
448 return ERROR_NOT_SUPPORTED;
452 /******************************************************************
453 * EnableRouter (IPHLPAPI.@)
455 * Turn on ip forwarding.
457 * PARAMS
458 * pHandle [In/Out]
459 * pOverlapped [In/Out] hEvent member should contain a valid handle.
461 * RETURNS
462 * Success: ERROR_IO_PENDING
463 * Failure: error code from winerror.h
465 * FIXME
466 * Stub, returns ERROR_NOT_SUPPORTED.
468 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
470 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
471 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
472 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
474 return ERROR_NOT_SUPPORTED;
478 /******************************************************************
479 * FlushIpNetTable (IPHLPAPI.@)
481 * Delete all ARP entries of an interface
483 * PARAMS
484 * dwIfIndex [In] interface index
486 * RETURNS
487 * Success: NO_ERROR
488 * Failure: error code from winerror.h
490 * FIXME
491 * Stub, returns ERROR_NOT_SUPPORTED.
493 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
495 FIXME("(dwIfIndex 0x%08lx): stub\n", dwIfIndex);
496 /* this flushes the arp cache of the given index */
497 return ERROR_NOT_SUPPORTED;
500 /******************************************************************
501 * FreeMibTable (IPHLPAPI.@)
503 * Free buffer allocated by network functions
505 * PARAMS
506 * ptr [In] pointer to the buffer to free
509 void WINAPI FreeMibTable( void *ptr )
511 TRACE( "(%p)\n", ptr );
512 heap_free( ptr );
515 /******************************************************************
516 * GetAdapterIndex (IPHLPAPI.@)
518 * Get interface index from its name.
520 * PARAMS
521 * adapter_name [In] unicode string with the adapter name
522 * index [Out] returns found interface index
524 DWORD WINAPI GetAdapterIndex( WCHAR *adapter_name, ULONG *index )
526 NET_LUID luid;
527 GUID guid;
528 DWORD err;
530 TRACE( "name %s, index %p\n", debugstr_w( adapter_name ), index );
532 if (wcslen( adapter_name ) < wcslen( device_tcpip )) return ERROR_INVALID_PARAMETER;
533 err = ConvertStringToGuidW( adapter_name + wcslen( device_tcpip ), &guid );
534 if (err) return err;
535 err = ConvertInterfaceGuidToLuid( &guid, &luid );
536 if (err) return err;
537 return ConvertInterfaceLuidToIndex( &luid, index );
540 static DWORD get_wins_servers( SOCKADDR_INET **servers )
542 HKEY key;
543 char buf[4 * 4];
544 DWORD size, i, count = 0;
545 static const char *values[] = { "WinsServer", "BackupWinsServer" };
546 IN_ADDR addrs[ARRAY_SIZE(values)];
548 *servers = NULL;
549 /* @@ Wine registry key: HKCU\Software\Wine\Network */
550 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Network", &key )) return 0;
552 for (i = 0; i < ARRAY_SIZE(values); i++)
554 size = sizeof(buf);
555 if (!RegQueryValueExA( key, values[i], NULL, NULL, (LPBYTE)buf, &size ))
556 if (!RtlIpv4StringToAddressA( buf, TRUE, NULL, addrs + count ) &&
557 addrs[count].s_addr != INADDR_NONE && addrs[count].s_addr != INADDR_ANY)
558 count++;
560 RegCloseKey( key );
562 if (count)
564 *servers = heap_alloc_zero( count * sizeof(**servers) );
565 if (!*servers) return 0;
566 for (i = 0; i < count; i++)
568 (*servers)[i].Ipv4.sin_family = AF_INET;
569 (*servers)[i].Ipv4.sin_addr = addrs[i];
572 return count;
575 static void ip_addr_string_init( IP_ADDR_STRING *s, const IN_ADDR *addr, const IN_ADDR *mask, DWORD ctxt )
577 s->Next = NULL;
579 if (addr) RtlIpv4AddressToStringA( addr, s->IpAddress.String );
580 else s->IpAddress.String[0] = '\0';
581 if (mask) RtlIpv4AddressToStringA( mask, s->IpMask.String );
582 else s->IpMask.String[0] = '\0';
583 s->Context = ctxt;
586 /******************************************************************
587 * GetAdaptersInfo (IPHLPAPI.@)
589 * Get information about adapters.
591 * PARAMS
592 * info [Out] buffer for adapter infos
593 * size [In] length of output buffer
595 DWORD WINAPI GetAdaptersInfo( IP_ADAPTER_INFO *info, ULONG *size )
597 DWORD err, if_count, if_num = 0, uni_count, fwd_count, needed, wins_server_count;
598 DWORD len, i, uni, fwd;
599 NET_LUID *if_keys = NULL;
600 struct nsi_ndis_ifinfo_rw *if_rw = NULL;
601 struct nsi_ndis_ifinfo_static *if_stat = NULL;
602 struct nsi_ipv4_unicast_key *uni_keys = NULL;
603 struct nsi_ip_unicast_rw *uni_rw = NULL;
604 struct nsi_ipv4_forward_key *fwd_keys = NULL;
605 SOCKADDR_INET *wins_servers = NULL;
606 IP_ADDR_STRING *extra_ip_addrs, *cursor;
607 IN_ADDR gw, mask;
609 TRACE( "info %p, size %p\n", info, size );
610 if (!size) return ERROR_INVALID_PARAMETER;
612 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
613 (void **)&if_keys, sizeof(*if_keys), (void **)&if_rw, sizeof(*if_rw),
614 NULL, 0, (void **)&if_stat, sizeof(*if_stat), &if_count, 0 );
616 if (err) return err;
617 for (i = 0; i < if_count; i++)
619 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
620 if_num++;
623 if (!if_num)
625 err = ERROR_NO_DATA;
626 goto err;
629 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE,
630 (void **)&uni_keys, sizeof(*uni_keys), (void **)&uni_rw, sizeof(*uni_rw),
631 NULL, 0, NULL, 0, &uni_count, 0 );
632 if (err) goto err;
634 /* Slightly overestimate the needed size by assuming that all
635 unicast addresses require a separate IP_ADDR_STRING. */
637 needed = if_num * sizeof(*info) + uni_count * sizeof(IP_ADDR_STRING);
638 if (!info || *size < needed)
640 *size = needed;
641 err = ERROR_BUFFER_OVERFLOW;
642 goto err;
645 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE,
646 (void **)&fwd_keys, sizeof(*fwd_keys), NULL, 0,
647 NULL, 0, NULL, 0, &fwd_count, 0 );
648 if (err) goto err;
650 wins_server_count = get_wins_servers( &wins_servers );
652 extra_ip_addrs = (IP_ADDR_STRING *)(info + if_num);
653 for (i = 0; i < if_count; i++)
655 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
657 info->Next = info + 1;
658 info->ComboIndex = 0;
659 ConvertGuidToStringA( &if_stat[i].if_guid, info->AdapterName, sizeof(info->AdapterName) );
660 len = WideCharToMultiByte( CP_ACP, 0, if_stat[i].descr.String, if_stat[i].descr.Length / sizeof(WCHAR),
661 info->Description, sizeof(info->Description) - 1, NULL, NULL );
662 info->Description[len] = '\0';
663 info->AddressLength = if_rw[i].phys_addr.Length;
664 if (info->AddressLength > sizeof(info->Address)) info->AddressLength = 0;
665 memcpy( info->Address, if_rw[i].phys_addr.Address, info->AddressLength );
666 memset( info->Address + info->AddressLength, 0, sizeof(info->Address) - info->AddressLength );
667 info->Index = if_stat[i].if_index;
668 info->Type = if_stat[i].type;
669 info->DhcpEnabled = TRUE; /* FIXME */
670 info->CurrentIpAddress = NULL;
672 cursor = NULL;
673 for (uni = 0; uni < uni_count; uni++)
675 if (uni_keys[uni].luid.Value != if_keys[i].Value) continue;
676 if (!cursor) cursor = &info->IpAddressList;
677 else
679 cursor->Next = extra_ip_addrs++;
680 cursor = cursor->Next;
682 ConvertLengthToIpv4Mask( uni_rw[uni].on_link_prefix, &mask.s_addr );
683 ip_addr_string_init( cursor, &uni_keys[uni].addr, &mask, 0 );
685 if (!cursor)
687 mask.s_addr = INADDR_ANY;
688 ip_addr_string_init( &info->IpAddressList, &mask, &mask, 0 );
691 gw.s_addr = INADDR_ANY;
692 mask.s_addr = INADDR_NONE;
693 for (fwd = 0; fwd < fwd_count; fwd++)
694 { /* find the first router on this interface */
695 if (fwd_keys[fwd].luid.Value == if_keys[i].Value &&
696 fwd_keys[fwd].next_hop.s_addr != INADDR_ANY &&
697 !fwd_keys[fwd].prefix_len)
699 gw = fwd_keys[fwd].next_hop;
700 break;
703 ip_addr_string_init( &info->GatewayList, &gw, &mask, 0 );
705 ip_addr_string_init( &info->DhcpServer, NULL, NULL, 0 );
707 info->HaveWins = !!wins_server_count;
708 ip_addr_string_init( &info->PrimaryWinsServer, NULL, NULL, 0 );
709 ip_addr_string_init( &info->SecondaryWinsServer, NULL, NULL, 0 );
710 if (info->HaveWins)
712 mask.s_addr = INADDR_NONE;
713 ip_addr_string_init( &info->PrimaryWinsServer, &wins_servers[0].Ipv4.sin_addr, &mask, 0 );
714 if (wins_server_count > 1)
715 ip_addr_string_init( &info->SecondaryWinsServer, &wins_servers[1].Ipv4.sin_addr, &mask, 0 );
718 info->LeaseObtained = 0;
719 info->LeaseExpires = 0;
721 info++;
723 info[-1].Next = NULL;
725 err:
726 heap_free( wins_servers );
727 NsiFreeTable( fwd_keys, NULL, NULL, NULL );
728 NsiFreeTable( uni_keys, uni_rw, NULL, NULL );
729 NsiFreeTable( if_keys, if_rw, NULL, if_stat );
730 return err;
733 static void address_entry_free( void *ptr, ULONG offset, void *ctxt )
735 heap_free( ptr );
738 static void address_entry_size( void *ptr, ULONG offset, void *ctxt )
740 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
741 ULONG *total = (ULONG *)ctxt, align = sizeof(ULONGLONG) - 1;
743 *total = (*total + src_addr->Length + src_addr->Address.iSockaddrLength + align) & ~align;
746 struct address_entry_copy_params
748 IP_ADAPTER_ADDRESSES *src, *dst;
749 char *ptr;
750 void *next;
751 ULONG cur_offset;
754 static void address_entry_copy( void *ptr, ULONG offset, void *ctxt )
756 struct address_entry_copy_params *params = ctxt;
757 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
758 IP_ADAPTER_DNS_SERVER_ADDRESS *dst_addr = (IP_ADAPTER_DNS_SERVER_ADDRESS *)params->ptr;
759 ULONG align = sizeof(ULONGLONG) - 1;
761 memcpy( dst_addr, src_addr, src_addr->Length );
762 params->ptr += src_addr->Length;
763 dst_addr->Address.lpSockaddr = (SOCKADDR *)params->ptr;
764 memcpy( dst_addr->Address.lpSockaddr, src_addr->Address.lpSockaddr, src_addr->Address.iSockaddrLength );
765 params->ptr += (src_addr->Address.iSockaddrLength + align) & ~align;
767 if (params->cur_offset != offset) /* new list */
769 params->next = (BYTE *)params->dst + offset;
770 params->cur_offset = offset;
772 *(IP_ADAPTER_DNS_SERVER_ADDRESS **)params->next = dst_addr;
773 params->next = &dst_addr->Next;
776 static void address_lists_iterate( IP_ADAPTER_ADDRESSES *aa, void (*fn)(void *entry, ULONG offset, void *ctxt), void *ctxt )
778 IP_ADAPTER_UNICAST_ADDRESS *uni;
779 IP_ADAPTER_DNS_SERVER_ADDRESS *dns;
780 IP_ADAPTER_GATEWAY_ADDRESS *gw;
781 IP_ADAPTER_PREFIX *prefix;
782 void *next;
784 for (uni = aa->FirstUnicastAddress; uni; uni = next)
786 next = uni->Next;
787 fn( uni, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstUnicastAddress ), ctxt );
790 for (dns = aa->FirstDnsServerAddress; dns; dns = next)
792 next = dns->Next;
793 fn( dns, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstDnsServerAddress ), ctxt );
796 for (gw = aa->FirstGatewayAddress; gw; gw = next)
798 next = gw->Next;
799 fn( gw, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstGatewayAddress ), ctxt );
802 for (prefix = aa->FirstPrefix; prefix; prefix = next)
804 next = prefix->Next;
805 fn( prefix, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstPrefix ), ctxt );
809 static void adapters_addresses_free( IP_ADAPTER_ADDRESSES *info )
811 IP_ADAPTER_ADDRESSES *aa;
813 for (aa = info; aa; aa = aa->Next)
815 address_lists_iterate( aa, address_entry_free, NULL );
817 heap_free( aa->DnsSuffix );
819 heap_free( info );
822 static ULONG adapters_addresses_size( IP_ADAPTER_ADDRESSES *info )
824 IP_ADAPTER_ADDRESSES *aa;
825 ULONG size = 0, align = sizeof(ULONGLONG) - 1;
827 for (aa = info; aa; aa = aa->Next)
829 size += sizeof(*aa) + ((strlen( aa->AdapterName ) + 1 + 1) & ~1);
830 size += (wcslen( aa->Description ) + 1 + wcslen( aa->DnsSuffix ) + 1) * sizeof(WCHAR);
831 if (aa->FriendlyName) size += (wcslen( aa->FriendlyName ) + 1) * sizeof(WCHAR);
832 size = (size + align) & ~align;
833 address_lists_iterate( aa, address_entry_size, &size );
835 return size;
838 static void adapters_addresses_copy( IP_ADAPTER_ADDRESSES *dst, IP_ADAPTER_ADDRESSES *src )
840 char *ptr;
841 DWORD len;
842 UINT_PTR align = sizeof(ULONGLONG) - 1;
843 struct address_entry_copy_params params;
845 while (src)
847 ptr = (char *)(dst + 1);
848 *dst = *src;
849 dst->AdapterName = ptr;
850 len = strlen( src->AdapterName ) + 1;
851 memcpy( dst->AdapterName, src->AdapterName, len );
852 ptr += (len + 1) & ~1;
853 dst->Description = (WCHAR *)ptr;
854 len = (wcslen( src->Description ) + 1) * sizeof(WCHAR);
855 memcpy( dst->Description, src->Description, len );
856 ptr += len;
857 dst->DnsSuffix = (WCHAR *)ptr;
858 len = (wcslen( src->DnsSuffix ) + 1) * sizeof(WCHAR);
859 memcpy( dst->DnsSuffix, src->DnsSuffix, len );
860 ptr += len;
861 if (src->FriendlyName)
863 dst->FriendlyName = (WCHAR *)ptr;
864 len = (wcslen( src->FriendlyName ) + 1) * sizeof(WCHAR);
865 memcpy( dst->FriendlyName, src->FriendlyName, len );
866 ptr += len;
868 ptr = (char *)(((UINT_PTR)ptr + align) & ~align);
870 params.src = src;
871 params.dst = dst;
872 params.ptr = ptr;
873 params.next = NULL;
874 params.cur_offset = ~0u;
875 address_lists_iterate( src, address_entry_copy, &params );
876 ptr = params.ptr;
878 if (src->Next)
880 dst->Next = (IP_ADAPTER_ADDRESSES *)ptr;
881 dst = dst->Next;
883 src = src->Next;
887 static BOOL sockaddr_is_loopback( SOCKADDR *sock )
889 if (sock->sa_family == AF_INET)
891 SOCKADDR_IN *sin = (SOCKADDR_IN *)sock;
892 return (sin->sin_addr.s_addr & 0xff) == 127;
894 else if (sock->sa_family == AF_INET6)
896 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
897 return IN6_IS_ADDR_LOOPBACK( &sin6->sin6_addr );
899 return FALSE;
902 static BOOL sockaddr_is_linklocal( SOCKADDR *sock )
904 if (sock->sa_family == AF_INET6)
906 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
907 return IN6_IS_ADDR_LINKLOCAL( &sin6->sin6_addr );
909 return FALSE;
912 static BOOL unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS *uni )
914 return !sockaddr_is_loopback( uni->Address.lpSockaddr ) &&
915 !sockaddr_is_linklocal( uni->Address.lpSockaddr );
918 static DWORD unicast_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
920 struct nsi_ipv4_unicast_key *key4;
921 struct nsi_ipv6_unicast_key *key6;
922 struct nsi_ip_unicast_rw *rw;
923 struct nsi_ip_unicast_dynamic *dyn;
924 struct nsi_ip_unicast_static *stat;
925 IP_ADAPTER_UNICAST_ADDRESS *addr, **next;
926 DWORD err, count, i, key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
927 DWORD sockaddr_size = (family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
928 NET_LUID *luid;
929 void *key;
931 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_UNICAST_TABLE, &key, key_size,
932 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
933 (void **)&stat, sizeof(*stat), &count, 0 );
934 if (err) return err;
937 while (aa)
939 for (next = &aa->FirstUnicastAddress; *next; next = &(*next)->Next)
942 for (i = 0; i < count; i++)
944 key4 = (struct nsi_ipv4_unicast_key *)key + i;
945 key6 = (struct nsi_ipv6_unicast_key *)key + i;
946 luid = (family == AF_INET) ? &key4->luid : &key6->luid;
947 if (luid->Value != aa->Luid.Value) continue;
948 addr = heap_alloc_zero( sizeof(*addr) + sockaddr_size );
949 if (!addr)
951 err = ERROR_NOT_ENOUGH_MEMORY;
952 goto err;
954 addr->Length = sizeof(*addr);
955 addr->Address.lpSockaddr = (SOCKADDR *)(addr + 1);
956 addr->Address.iSockaddrLength = sockaddr_size;
957 addr->Address.lpSockaddr->sa_family = family;
958 if (family == AF_INET)
960 SOCKADDR_IN *in = (SOCKADDR_IN *)addr->Address.lpSockaddr;
961 in->sin_addr = key4->addr;
963 else
965 SOCKADDR_IN6 *in6 = (SOCKADDR_IN6 *)addr->Address.lpSockaddr;
966 in6->sin6_addr = key6->addr;
967 in6->sin6_scope_id = dyn[i].scope_id;
969 addr->PrefixOrigin = rw[i].prefix_origin;
970 addr->SuffixOrigin = rw[i].suffix_origin;
971 addr->DadState = dyn[i].dad_state;
972 addr->ValidLifetime = rw[i].valid_lifetime;
973 addr->PreferredLifetime = rw[i].preferred_lifetime;
974 addr->LeaseLifetime = rw[i].valid_lifetime; /* FIXME */
975 addr->OnLinkPrefixLength = rw[i].on_link_prefix;
976 if (unicast_is_dns_eligible( addr )) addr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
978 *next = addr;
979 next = &addr->Next;
981 aa = aa->Next;
984 err:
985 NsiFreeTable( key, rw, dyn, stat );
986 return err;
989 static DWORD gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
991 struct nsi_ipv4_forward_key *key4;
992 struct nsi_ipv6_forward_key *key6;
993 IP_ADAPTER_GATEWAY_ADDRESS *gw, **gw_next;
994 IP_ADAPTER_PREFIX *prefix, **prefix_next;
995 DWORD err, count, i, prefix_len, key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
996 DWORD sockaddr_size = (family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
997 SOCKADDR_INET sockaddr;
998 NET_LUID *luid;
999 void *key;
1001 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_FORWARD_TABLE, &key, key_size,
1002 NULL, 0, NULL, 0, NULL, 0, &count, 0 );
1003 if (err) return err;
1005 while (aa)
1007 for (gw_next = &aa->FirstGatewayAddress; *gw_next; gw_next = &(*gw_next)->Next)
1009 for (prefix_next = &aa->FirstPrefix; *prefix_next; prefix_next = &(*prefix_next)->Next)
1012 for (i = 0; i < count; i++)
1014 key4 = (struct nsi_ipv4_forward_key *)key + i;
1015 key6 = (struct nsi_ipv6_forward_key *)key + i;
1016 luid = (family == AF_INET) ? &key4->luid : &key6->luid;
1017 if (luid->Value != aa->Luid.Value) continue;
1019 if (flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
1021 memset( &sockaddr, 0, sizeof(sockaddr) );
1022 if (family == AF_INET)
1024 if (key4->next_hop.s_addr != 0)
1026 sockaddr.si_family = family;
1027 sockaddr.Ipv4.sin_addr = key4->next_hop;
1030 else
1032 static const IN6_ADDR zero;
1033 if (memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1035 sockaddr.si_family = family;
1036 sockaddr.Ipv6.sin6_addr = key6->next_hop;
1040 if (sockaddr.si_family)
1042 gw = heap_alloc_zero( sizeof(*gw) + sockaddr_size );
1043 if (!gw)
1045 err = ERROR_NOT_ENOUGH_MEMORY;
1046 goto err;
1048 gw->Length = sizeof(*gw);
1049 gw->Address.lpSockaddr = (SOCKADDR *)(gw + 1);
1050 gw->Address.iSockaddrLength = sockaddr_size;
1051 memcpy( gw->Address.lpSockaddr, &sockaddr, sockaddr_size );
1052 *gw_next = gw;
1053 gw_next = &gw->Next;
1057 if (flags & GAA_FLAG_INCLUDE_PREFIX)
1059 memset( &sockaddr, 0, sizeof(sockaddr) );
1060 prefix_len = 0;
1061 if (family == AF_INET)
1063 if (!key4->next_hop.s_addr)
1065 sockaddr.si_family = family;
1066 sockaddr.Ipv4.sin_addr = key4->prefix;
1067 prefix_len = key4->prefix_len;
1070 else
1072 static const IN6_ADDR zero;
1073 if (!memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1075 sockaddr.si_family = family;
1076 sockaddr.Ipv6.sin6_addr = key6->prefix;
1077 prefix_len = key6->prefix_len;
1081 if (sockaddr.si_family)
1083 prefix = heap_alloc_zero( sizeof(*prefix) + sockaddr_size );
1084 if (!prefix)
1086 err = ERROR_NOT_ENOUGH_MEMORY;
1087 goto err;
1089 prefix->Length = sizeof(*prefix);
1090 prefix->Address.lpSockaddr = (SOCKADDR *)(prefix + 1);
1091 prefix->Address.iSockaddrLength = sockaddr_size;
1092 memcpy( prefix->Address.lpSockaddr, &sockaddr, sockaddr_size );
1093 prefix->PrefixLength = prefix_len;
1094 *prefix_next = prefix;
1095 prefix_next = &prefix->Next;
1099 aa = aa->Next;
1102 err:
1103 NsiFreeTable( key, NULL, NULL, NULL );
1104 return err;
1107 static DWORD call_families( DWORD (*fn)( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags ),
1108 IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1110 DWORD err;
1112 if (family != AF_INET)
1114 err = fn( aa, AF_INET6, flags );
1115 if (err) return err;
1118 if (family != AF_INET6)
1120 err = fn( aa, AF_INET, flags );
1121 if (err) return err;
1123 return err;
1126 static DWORD dns_servers_query_code( ULONG family )
1128 if (family == AF_INET) return DnsConfigDnsServersIpv4;
1129 if (family == AF_INET6) return DnsConfigDnsServersIpv6;
1130 return DnsConfigDnsServersUnspec;
1133 static DWORD dns_info_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1135 char buf[FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[3])];
1136 IP_ADAPTER_DNS_SERVER_ADDRESS *dns, **next;
1137 DWORD query = dns_servers_query_code( family );
1138 DWORD err, i, size, attempt, sockaddr_len;
1139 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
1140 DNS_ADDR_ARRAY *servers;
1141 WCHAR *search;
1143 while (aa)
1145 MultiByteToWideChar( CP_ACP, 0, aa->AdapterName, -1, name, ARRAY_SIZE(name) );
1146 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1148 servers = (DNS_ADDR_ARRAY *)buf;
1149 for (attempt = 0; attempt < 5; attempt++)
1151 err = DnsQueryConfig( query, 0, name, NULL, servers, &size );
1152 if (err != ERROR_MORE_DATA) break;
1153 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1154 servers = heap_alloc( size );
1155 if (!servers)
1157 err = ERROR_NOT_ENOUGH_MEMORY;
1158 break;
1161 if (!err)
1163 next = &aa->FirstDnsServerAddress;
1164 for (i = 0; i < servers->AddrCount; i++)
1166 sockaddr_len = servers->AddrArray[i].Data.DnsAddrUserDword[0];
1167 if (sockaddr_len > sizeof(servers->AddrArray[i].MaxSa))
1168 sockaddr_len = sizeof(servers->AddrArray[i].MaxSa);
1169 dns = heap_alloc_zero( sizeof(*dns) + sockaddr_len );
1170 if (!dns)
1172 err = ERROR_NOT_ENOUGH_MEMORY;
1173 break;
1175 dns->Length = sizeof(*dns);
1176 dns->Address.lpSockaddr = (SOCKADDR *)(dns + 1);
1177 dns->Address.iSockaddrLength = sockaddr_len;
1178 memcpy( dns->Address.lpSockaddr, servers->AddrArray[i].MaxSa, sockaddr_len );
1179 *next = dns;
1180 next = &dns->Next;
1183 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1184 if (err) return err;
1187 aa->DnsSuffix = heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH * sizeof(WCHAR) );
1188 if (!aa->DnsSuffix) return ERROR_NOT_ENOUGH_MEMORY;
1189 aa->DnsSuffix[0] = '\0';
1191 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, NULL, &size ) &&
1192 (search = heap_alloc( size )))
1194 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, search, &size ) &&
1195 search[0] && wcslen( search ) < MAX_DNS_SUFFIX_STRING_LENGTH)
1197 wcscpy( aa->DnsSuffix, search );
1199 heap_free( search );
1202 aa = aa->Next;
1205 return ERROR_SUCCESS;
1208 static DWORD adapters_addresses_alloc( ULONG family, ULONG flags, IP_ADAPTER_ADDRESSES **info )
1210 IP_ADAPTER_ADDRESSES *aa;
1211 NET_LUID *luids;
1212 struct nsi_ndis_ifinfo_rw *rw;
1213 struct nsi_ndis_ifinfo_dynamic *dyn;
1214 struct nsi_ndis_ifinfo_static *stat;
1215 DWORD err, i, count, needed;
1216 GUID guid;
1217 char *str_ptr;
1219 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&luids, sizeof(*luids),
1220 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1221 (void **)&stat, sizeof(*stat), &count, 0 );
1222 if (err) return err;
1224 needed = count * (sizeof(*aa) + ((CHARS_IN_GUID + 1) & ~1) + sizeof(stat->descr.String));
1225 needed += count * sizeof(rw->alias.String); /* GAA_FLAG_SKIP_FRIENDLY_NAME is ignored */
1227 aa = heap_alloc_zero( needed );
1228 if (!aa)
1230 err = ERROR_NOT_ENOUGH_MEMORY;
1231 goto err;
1234 str_ptr = (char *)(aa + count);
1235 for (i = 0; i < count; i++)
1237 aa[i].Length = sizeof(*aa);
1238 aa[i].IfIndex = stat[i].if_index;
1239 if (i < count - 1) aa[i].Next = aa + i + 1;
1240 ConvertInterfaceLuidToGuid( luids + i, &guid );
1241 ConvertGuidToStringA( &guid, str_ptr, CHARS_IN_GUID );
1242 aa[i].AdapterName = str_ptr;
1243 str_ptr += (CHARS_IN_GUID + 1) & ~1;
1244 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(stat[i].descr.String), &stat[i].descr );
1245 aa[i].Description = (WCHAR *)str_ptr;
1246 str_ptr += sizeof(stat[i].descr.String);
1247 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(rw[i].alias.String), &rw[i].alias );
1248 aa[i].FriendlyName = (WCHAR *)str_ptr;
1249 str_ptr += sizeof(rw[i].alias.String);
1250 aa[i].PhysicalAddressLength = rw[i].phys_addr.Length;
1251 if (aa[i].PhysicalAddressLength > sizeof(aa[i].PhysicalAddress)) aa[i].PhysicalAddressLength = 0;
1252 memcpy( aa[i].PhysicalAddress, rw[i].phys_addr.Address, aa[i].PhysicalAddressLength );
1253 aa[i].Mtu = dyn[i].mtu;
1254 aa[i].IfType = stat[i].type;
1255 aa[i].OperStatus = dyn[i].oper_status;
1256 aa[i].TransmitLinkSpeed = dyn[i].xmit_speed;
1257 aa[i].ReceiveLinkSpeed = dyn[i].rcv_speed;
1258 aa[i].Luid = luids[i];
1259 aa[i].NetworkGuid = rw[i].network_guid;
1260 aa[i].ConnectionType = stat[i].conn_type;
1263 if (!(flags & GAA_FLAG_SKIP_UNICAST))
1265 err = call_families( unicast_addresses_alloc, aa, family, flags );
1266 if (err) goto err;
1269 if (flags & (GAA_FLAG_INCLUDE_ALL_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX))
1271 err = call_families( gateway_and_prefix_addresses_alloc, aa, family, flags );
1272 if (err) goto err;
1275 err = dns_info_alloc( aa, family, flags );
1276 if (err) goto err;
1278 err:
1279 NsiFreeTable( luids, rw, dyn, stat );
1280 if (!err) *info = aa;
1281 else adapters_addresses_free( aa );
1282 return err;
1285 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses( ULONG family, ULONG flags, void *reserved,
1286 IP_ADAPTER_ADDRESSES *aa, ULONG *size )
1288 IP_ADAPTER_ADDRESSES *info;
1289 DWORD err, needed;
1291 TRACE( "(%ld, %08lx, %p, %p, %p)\n", family, flags, reserved, aa, size );
1293 if (!size) return ERROR_INVALID_PARAMETER;
1295 err = adapters_addresses_alloc( family, flags, &info );
1296 if (err) return err;
1298 needed = adapters_addresses_size( info );
1299 if (!aa || *size < needed)
1301 *size = needed;
1302 err = ERROR_BUFFER_OVERFLOW;
1304 else
1305 adapters_addresses_copy( aa, info );
1307 adapters_addresses_free( info );
1308 return err;
1311 /******************************************************************
1312 * GetBestInterface (IPHLPAPI.@)
1314 * Get the interface, with the best route for the given IP address.
1316 * PARAMS
1317 * dwDestAddr [In] IP address to search the interface for
1318 * pdwBestIfIndex [Out] found best interface
1320 * RETURNS
1321 * Success: NO_ERROR
1322 * Failure: error code from winerror.h
1324 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1326 struct sockaddr_in sa_in;
1327 memset(&sa_in, 0, sizeof(sa_in));
1328 sa_in.sin_family = AF_INET;
1329 sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1330 return GetBestInterfaceEx((struct sockaddr *)&sa_in, pdwBestIfIndex);
1333 /******************************************************************
1334 * GetBestInterfaceEx (IPHLPAPI.@)
1336 * Get the interface, with the best route for the given IP address.
1338 * PARAMS
1339 * dwDestAddr [In] IP address to search the interface for
1340 * pdwBestIfIndex [Out] found best interface
1342 * RETURNS
1343 * Success: NO_ERROR
1344 * Failure: error code from winerror.h
1346 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1348 DWORD ret;
1350 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1351 if (!pDestAddr || !pdwBestIfIndex)
1352 ret = ERROR_INVALID_PARAMETER;
1353 else {
1354 MIB_IPFORWARDROW ipRow;
1356 if (pDestAddr->sa_family == AF_INET) {
1357 ret = GetBestRoute(((struct sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1358 if (ret == ERROR_SUCCESS)
1359 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1360 } else {
1361 FIXME("address family %d not supported\n", pDestAddr->sa_family);
1362 ret = ERROR_NOT_SUPPORTED;
1365 TRACE("returning %ld\n", ret);
1366 return ret;
1370 /******************************************************************
1371 * GetBestRoute (IPHLPAPI.@)
1373 * Get the best route for the given IP address.
1375 * PARAMS
1376 * dwDestAddr [In] IP address to search the best route for
1377 * dwSourceAddr [In] optional source IP address
1378 * pBestRoute [Out] found best route
1380 * RETURNS
1381 * Success: NO_ERROR
1382 * Failure: error code from winerror.h
1384 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1386 PMIB_IPFORWARDTABLE table;
1387 DWORD ret;
1389 TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
1390 dwSourceAddr, pBestRoute);
1391 if (!pBestRoute)
1392 return ERROR_INVALID_PARAMETER;
1394 ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1395 if (!ret) {
1396 DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1398 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1399 if (table->table[ndx].ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1400 (dwDestAddr & table->table[ndx].dwForwardMask) ==
1401 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1402 DWORD numShifts, mask;
1404 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1405 mask && mask & 1; mask >>= 1, numShifts++)
1407 if (numShifts > matchedBits) {
1408 matchedBits = numShifts;
1409 matchedNdx = ndx;
1411 else if (!matchedBits) {
1412 matchedNdx = ndx;
1416 if (matchedNdx < table->dwNumEntries) {
1417 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1418 ret = ERROR_SUCCESS;
1420 else {
1421 /* No route matches, which can happen if there's no default route. */
1422 ret = ERROR_HOST_UNREACHABLE;
1424 HeapFree(GetProcessHeap(), 0, table);
1426 TRACE("returning %ld\n", ret);
1427 return ret;
1431 /******************************************************************
1432 * GetFriendlyIfIndex (IPHLPAPI.@)
1434 * Get a "friendly" version of IfIndex, which is one that doesn't
1435 * have the top byte set. Doesn't validate whether IfIndex is a valid
1436 * adapter index.
1438 * PARAMS
1439 * IfIndex [In] interface index to get the friendly one for
1441 * RETURNS
1442 * A friendly version of IfIndex.
1444 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1446 /* windows doesn't validate these, either, just makes sure the top byte is
1447 cleared. I assume my ifenum module never gives an index with the top
1448 byte set. */
1449 TRACE("returning %ld\n", IfIndex);
1450 return IfIndex;
1453 static void icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX *stats_ex, MIBICMPSTATS *stats )
1455 stats->dwMsgs = stats_ex->dwMsgs;
1456 stats->dwErrors = stats_ex->dwErrors;
1457 stats->dwDestUnreachs = stats_ex->rgdwTypeCount[ICMP4_DST_UNREACH];
1458 stats->dwTimeExcds = stats_ex->rgdwTypeCount[ICMP4_TIME_EXCEEDED];
1459 stats->dwParmProbs = stats_ex->rgdwTypeCount[ICMP4_PARAM_PROB];
1460 stats->dwSrcQuenchs = stats_ex->rgdwTypeCount[ICMP4_SOURCE_QUENCH];
1461 stats->dwRedirects = stats_ex->rgdwTypeCount[ICMP4_REDIRECT];
1462 stats->dwEchos = stats_ex->rgdwTypeCount[ICMP4_ECHO_REQUEST];
1463 stats->dwEchoReps = stats_ex->rgdwTypeCount[ICMP4_ECHO_REPLY];
1464 stats->dwTimestamps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST];
1465 stats->dwTimestampReps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REPLY];
1466 stats->dwAddrMasks = stats_ex->rgdwTypeCount[ICMP4_MASK_REQUEST];
1467 stats->dwAddrMaskReps = stats_ex->rgdwTypeCount[ICMP4_MASK_REPLY];
1470 /******************************************************************
1471 * GetIcmpStatistics (IPHLPAPI.@)
1473 * Get the ICMP statistics for the local computer.
1475 * PARAMS
1476 * stats [Out] buffer for ICMP statistics
1478 * RETURNS
1479 * Success: NO_ERROR
1480 * Failure: error code from winerror.h
1482 DWORD WINAPI GetIcmpStatistics( MIB_ICMP *stats )
1484 MIB_ICMP_EX stats_ex;
1485 DWORD err = GetIcmpStatisticsEx( &stats_ex, AF_INET );
1487 if (err) return err;
1489 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpInStats, &stats->stats.icmpInStats );
1490 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpOutStats, &stats->stats.icmpOutStats );
1491 return err;
1494 /******************************************************************
1495 * GetIcmpStatisticsEx (IPHLPAPI.@)
1497 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1499 * PARAMS
1500 * stats [Out] buffer for ICMP statistics
1501 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1503 * RETURNS
1504 * Success: NO_ERROR
1505 * Failure: error code from winerror.h
1507 DWORD WINAPI GetIcmpStatisticsEx( MIB_ICMP_EX *stats, DWORD family )
1509 const NPI_MODULEID *mod = ip_module_id( family );
1510 struct nsi_ip_icmpstats_dynamic dyn;
1511 DWORD err;
1513 if (!stats || !mod) return ERROR_INVALID_PARAMETER;
1514 memset( stats, 0, sizeof(*stats) );
1516 err = NsiGetAllParameters( 1, mod, NSI_IP_ICMPSTATS_TABLE, NULL, 0, NULL, 0,
1517 &dyn, sizeof(dyn), NULL, 0 );
1518 if (err) return err;
1520 stats->icmpInStats.dwMsgs = dyn.in_msgs;
1521 stats->icmpInStats.dwErrors = dyn.in_errors;
1522 memcpy( stats->icmpInStats.rgdwTypeCount, dyn.in_type_counts, sizeof( dyn.in_type_counts ) );
1523 stats->icmpOutStats.dwMsgs = dyn.out_msgs;
1524 stats->icmpOutStats.dwErrors = dyn.out_errors;
1525 memcpy( stats->icmpOutStats.rgdwTypeCount, dyn.out_type_counts, sizeof( dyn.out_type_counts ) );
1527 return ERROR_SUCCESS;
1530 static void if_row_fill( MIB_IFROW *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1531 struct nsi_ndis_ifinfo_static *stat )
1533 wcscpy( row->wszName, device_tcpip );
1534 ConvertGuidToStringW( &stat->if_guid, row->wszName + wcslen( device_tcpip ), CHARS_IN_GUID );
1535 row->dwIndex = stat->if_index;
1536 row->dwType = stat->type;
1537 row->dwMtu = dyn->mtu;
1538 row->dwSpeed = dyn->rcv_speed;
1539 row->dwPhysAddrLen = rw->phys_addr.Length;
1540 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
1541 memcpy( row->bPhysAddr, rw->phys_addr.Address, row->dwPhysAddrLen );
1542 row->dwAdminStatus = rw->admin_status;
1543 row->dwOperStatus = (dyn->oper_status == IfOperStatusUp) ? MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_NON_OPERATIONAL;
1544 row->dwLastChange = 0;
1545 row->dwInOctets = dyn->in_octets;
1546 row->dwInUcastPkts = dyn->in_ucast_pkts;
1547 row->dwInNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1548 row->dwInDiscards = dyn->in_discards;
1549 row->dwInErrors = dyn->in_errors;
1550 row->dwInUnknownProtos = 0;
1551 row->dwOutOctets = dyn->out_octets;
1552 row->dwOutUcastPkts = dyn->out_ucast_pkts;
1553 row->dwOutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1554 row->dwOutDiscards = dyn->out_discards;
1555 row->dwOutErrors = dyn->out_errors;
1556 row->dwOutQLen = 0;
1557 row->dwDescrLen = WideCharToMultiByte( CP_ACP, 0, stat->descr.String, stat->descr.Length / sizeof(WCHAR),
1558 (char *)row->bDescr, sizeof(row->bDescr) - 1, NULL, NULL );
1559 row->bDescr[row->dwDescrLen] = '\0';
1562 /******************************************************************
1563 * GetIfEntry (IPHLPAPI.@)
1565 * Get information about an interface.
1567 * PARAMS
1568 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1569 * Out: interface information
1571 * RETURNS
1572 * Success: NO_ERROR
1573 * Failure: error code from winerror.h
1575 DWORD WINAPI GetIfEntry( MIB_IFROW *row )
1577 struct nsi_ndis_ifinfo_rw rw;
1578 struct nsi_ndis_ifinfo_dynamic dyn;
1579 struct nsi_ndis_ifinfo_static stat;
1580 NET_LUID luid;
1581 DWORD err;
1583 TRACE( "row %p\n", row );
1584 if (!row) return ERROR_INVALID_PARAMETER;
1586 err = ConvertInterfaceIndexToLuid( row->dwIndex, &luid );
1587 if (err) return err;
1589 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1590 &luid, sizeof(luid), &rw, sizeof(rw),
1591 &dyn, sizeof(dyn), &stat, sizeof(stat) );
1592 if (!err) if_row_fill( row, &rw, &dyn, &stat );
1593 return err;
1596 static int DWORD_cmp( DWORD a, DWORD b )
1598 return a < b ? -1 : a > b ? 1 : 0; /* a subtraction would overflow */
1601 static int ifrow_cmp( const void *a, const void *b )
1603 const MIB_IFROW *rowA = a, *rowB = b;
1604 return DWORD_cmp(rowA->dwIndex, rowB->dwIndex);
1607 /******************************************************************
1608 * GetIfTable (IPHLPAPI.@)
1610 * Get a table of local interfaces.
1612 * PARAMS
1613 * table [Out] buffer for local interfaces table
1614 * size [In/Out] length of output buffer
1615 * sort [In] whether to sort the table
1617 * RETURNS
1618 * Success: NO_ERROR
1619 * Failure: error code from winerror.h
1621 * NOTES
1622 * If size is less than required, the function will return
1623 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1624 * size.
1625 * If sort is true, the returned table will be sorted by interface index.
1627 DWORD WINAPI GetIfTable( MIB_IFTABLE *table, ULONG *size, BOOL sort )
1629 DWORD i, count, needed, err;
1630 NET_LUID *keys;
1631 struct nsi_ndis_ifinfo_rw *rw;
1632 struct nsi_ndis_ifinfo_dynamic *dyn;
1633 struct nsi_ndis_ifinfo_static *stat;
1635 if (!size) return ERROR_INVALID_PARAMETER;
1637 /* While this could be implemented on top of GetIfTable2(), it would require
1638 an additional copy of the data */
1639 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1640 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1641 (void **)&stat, sizeof(*stat), &count, 0 );
1642 if (err) return err;
1644 needed = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1646 if (!table || *size < needed)
1648 *size = needed;
1649 err = ERROR_INSUFFICIENT_BUFFER;
1650 goto err;
1653 table->dwNumEntries = count;
1654 for (i = 0; i < count; i++)
1656 MIB_IFROW *row = table->table + i;
1658 if_row_fill( row, rw + i, dyn + i, stat + i );
1661 if (sort) qsort( table->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1663 err:
1664 NsiFreeTable( keys, rw, dyn, stat );
1665 return err;
1668 /******************************************************************
1669 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1671 * Get table of local interfaces.
1672 * Like GetIfTable(), but allocate the returned table from heap.
1674 * PARAMS
1675 * table [Out] pointer into which the MIB_IFTABLE is
1676 * allocated and returned.
1677 * sort [In] whether to sort the table
1678 * heap [In] heap from which the table is allocated
1679 * flags [In] flags to HeapAlloc
1681 * RETURNS
1682 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1683 * GetIfTable() returns otherwise.
1685 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1687 DWORD i, count, size, err;
1688 NET_LUID *keys;
1689 struct nsi_ndis_ifinfo_rw *rw;
1690 struct nsi_ndis_ifinfo_dynamic *dyn;
1691 struct nsi_ndis_ifinfo_static *stat;
1693 if (!table) return ERROR_INVALID_PARAMETER;
1695 /* While this could be implemented on top of GetIfTable(), it would require
1696 an additional call to retrieve the size */
1697 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1698 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1699 (void **)&stat, sizeof(*stat), &count, 0 );
1700 if (err) return err;
1702 size = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1703 *table = HeapAlloc( heap, flags, size );
1704 if (!*table)
1706 err = ERROR_NOT_ENOUGH_MEMORY;
1707 goto err;
1710 (*table)->dwNumEntries = count;
1711 for (i = 0; i < count; i++)
1713 MIB_IFROW *row = (*table)->table + i;
1715 if_row_fill( row, rw + i, dyn + i, stat + i );
1717 if (sort) qsort( (*table)->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1719 err:
1720 NsiFreeTable( keys, rw, dyn, stat );
1721 return err;
1724 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1725 struct nsi_ndis_ifinfo_static *stat )
1727 row->InterfaceIndex = stat->if_index;
1728 row->InterfaceGuid = stat->if_guid;
1729 if_counted_string_copy( row->Alias, ARRAY_SIZE(row->Alias), &rw->alias );
1730 if_counted_string_copy( row->Description, ARRAY_SIZE(row->Description), &stat->descr );
1731 row->PhysicalAddressLength = rw->phys_addr.Length;
1732 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress)) row->PhysicalAddressLength = 0;
1733 memcpy( row->PhysicalAddress, rw->phys_addr.Address, row->PhysicalAddressLength );
1734 memcpy( row->PermanentPhysicalAddress, stat->perm_phys_addr.Address, row->PhysicalAddressLength );
1735 row->Mtu = dyn->mtu;
1736 row->Type = stat->type;
1737 row->TunnelType = TUNNEL_TYPE_NONE; /* fixme */
1738 row->MediaType = stat->media_type;
1739 row->PhysicalMediumType = stat->phys_medium_type;
1740 row->AccessType = stat->access_type;
1741 row->DirectionType = NET_IF_DIRECTION_SENDRECEIVE; /* fixme */
1742 row->InterfaceAndOperStatusFlags.HardwareInterface = stat->flags.hw;
1743 row->InterfaceAndOperStatusFlags.FilterInterface = stat->flags.filter;
1744 row->InterfaceAndOperStatusFlags.ConnectorPresent = !!stat->conn_present;
1745 row->InterfaceAndOperStatusFlags.NotAuthenticated = 0; /* fixme */
1746 row->InterfaceAndOperStatusFlags.NotMediaConnected = dyn->flags.not_media_conn;
1747 row->InterfaceAndOperStatusFlags.Paused = 0; /* fixme */
1748 row->InterfaceAndOperStatusFlags.LowPower = 0; /* fixme */
1749 row->InterfaceAndOperStatusFlags.EndPointInterface = 0; /* fixme */
1750 row->OperStatus = dyn->oper_status;
1751 row->AdminStatus = rw->admin_status;
1752 row->MediaConnectState = dyn->media_conn_state;
1753 row->NetworkGuid = rw->network_guid;
1754 row->ConnectionType = stat->conn_type;
1755 row->TransmitLinkSpeed = dyn->xmit_speed;
1756 row->ReceiveLinkSpeed = dyn->rcv_speed;
1757 row->InOctets = dyn->in_octets;
1758 row->InUcastPkts = dyn->in_ucast_pkts;
1759 row->InNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1760 row->InDiscards = dyn->in_discards;
1761 row->InErrors = dyn->in_errors;
1762 row->InUnknownProtos = 0; /* fixme */
1763 row->InUcastOctets = dyn->in_ucast_octs;
1764 row->InMulticastOctets = dyn->in_mcast_octs;
1765 row->InBroadcastOctets = dyn->in_bcast_octs;
1766 row->OutOctets = dyn->out_octets;
1767 row->OutUcastPkts = dyn->out_ucast_pkts;
1768 row->OutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1769 row->OutDiscards = dyn->out_discards;
1770 row->OutErrors = dyn->out_errors;
1771 row->OutUcastOctets = dyn->out_ucast_octs;
1772 row->OutMulticastOctets = dyn->out_mcast_octs;
1773 row->OutBroadcastOctets = dyn->out_bcast_octs;
1774 row->OutQLen = 0; /* fixme */
1777 /******************************************************************
1778 * GetIfEntry2Ex (IPHLPAPI.@)
1780 DWORD WINAPI GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_ROW2 *row )
1782 DWORD err;
1783 struct nsi_ndis_ifinfo_rw rw;
1784 struct nsi_ndis_ifinfo_dynamic dyn;
1785 struct nsi_ndis_ifinfo_static stat;
1787 TRACE( "(%d, %p)\n", level, row );
1789 if (level != MibIfTableNormal) FIXME( "level %u not fully supported\n", level );
1790 if (!row) return ERROR_INVALID_PARAMETER;
1792 if (!row->InterfaceLuid.Value)
1794 if (!row->InterfaceIndex) return ERROR_INVALID_PARAMETER;
1795 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
1796 if (err) return err;
1799 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1800 &row->InterfaceLuid, sizeof(row->InterfaceLuid),
1801 &rw, sizeof(rw), &dyn, sizeof(dyn), &stat, sizeof(stat) );
1802 if (!err) if_row2_fill( row, &rw, &dyn, &stat );
1803 return err;
1806 /******************************************************************
1807 * GetIfEntry2 (IPHLPAPI.@)
1809 DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row )
1811 return GetIfEntry2Ex( MibIfTableNormal, row );
1814 /******************************************************************
1815 * GetIfTable2Ex (IPHLPAPI.@)
1817 DWORD WINAPI GetIfTable2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_TABLE2 **table )
1819 DWORD i, count, size, err;
1820 NET_LUID *keys;
1821 struct nsi_ndis_ifinfo_rw *rw;
1822 struct nsi_ndis_ifinfo_dynamic *dyn;
1823 struct nsi_ndis_ifinfo_static *stat;
1825 TRACE( "level %u, table %p\n", level, table );
1827 if (!table || level > MibIfTableNormalWithoutStatistics)
1828 return ERROR_INVALID_PARAMETER;
1830 if (level != MibIfTableNormal)
1831 FIXME("level %u not fully supported\n", level);
1833 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1834 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1835 (void **)&stat, sizeof(*stat), &count, 0 );
1836 if (err) return err;
1838 size = FIELD_OFFSET( MIB_IF_TABLE2, Table[count] );
1840 if (!(*table = heap_alloc_zero( size )))
1842 err = ERROR_OUTOFMEMORY;
1843 goto err;
1846 (*table)->NumEntries = count;
1847 for (i = 0; i < count; i++)
1849 MIB_IF_ROW2 *row = (*table)->Table + i;
1851 row->InterfaceLuid.Value = keys[i].Value;
1852 if_row2_fill( row, rw + i, dyn + i, stat + i );
1854 err:
1855 NsiFreeTable( keys, rw, dyn, stat );
1856 return err;
1859 /******************************************************************
1860 * GetIfTable2 (IPHLPAPI.@)
1862 DWORD WINAPI GetIfTable2( MIB_IF_TABLE2 **table )
1864 TRACE( "table %p\n", table );
1865 return GetIfTable2Ex( MibIfTableNormal, table );
1868 /******************************************************************
1869 * GetInterfaceInfo (IPHLPAPI.@)
1871 * Get a list of network interface adapters.
1873 * PARAMS
1874 * pIfTable [Out] buffer for interface adapters
1875 * dwOutBufLen [Out] if buffer is too small, returns required size
1877 * RETURNS
1878 * Success: NO_ERROR
1879 * Failure: error code from winerror.h
1881 * BUGS
1882 * MSDN states this should return non-loopback interfaces only.
1884 DWORD WINAPI GetInterfaceInfo( IP_INTERFACE_INFO *table, ULONG *size )
1886 NET_LUID *keys;
1887 struct nsi_ndis_ifinfo_static *stat;
1888 DWORD err, count, num = 0, needed, i;
1890 TRACE( "table %p, size %p\n", table, size );
1891 if (!size) return ERROR_INVALID_PARAMETER;
1893 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1894 (void **)&keys, sizeof(*keys), NULL, 0, NULL, 0,
1895 (void **)&stat, sizeof(*stat), &count, 0 );
1896 if (err) return err;
1898 for (i = 0; i < count; i++)
1900 if (stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1901 num++;
1904 needed = FIELD_OFFSET(IP_INTERFACE_INFO, Adapter[num]);
1905 if (!table || *size < needed)
1907 *size = needed;
1908 err = ERROR_INSUFFICIENT_BUFFER;
1909 goto done;
1912 table->NumAdapters = num;
1913 for (i = 0, num = 0; i < count; i++)
1915 IP_ADAPTER_INDEX_MAP *row;
1917 if (stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1918 row = table->Adapter + num++;
1919 row->Index = stat[i].if_index;
1920 wcscpy( row->Name, device_tcpip );
1921 ConvertGuidToStringW( &stat[i].if_guid, row->Name + wcslen( device_tcpip ), CHARS_IN_GUID );
1923 done:
1924 NsiFreeTable( keys, NULL, NULL, stat );
1925 return err;
1928 static int ipaddrrow_cmp( const void *a, const void *b )
1930 const MIB_IPADDRROW *rowA = a, *rowB = b;
1931 return DWORD_cmp(RtlUlongByteSwap( rowA->dwAddr ), RtlUlongByteSwap( rowB->dwAddr ));
1934 /******************************************************************
1935 * GetIpAddrTable (IPHLPAPI.@)
1937 * Get interface-to-IP address mapping table.
1939 * PARAMS
1940 * table [Out] buffer for mapping table
1941 * size [In/Out] length of output buffer
1942 * sort [In] whether to sort the table
1944 * RETURNS
1945 * Success: NO_ERROR
1946 * Failure: error code from winerror.h
1949 DWORD WINAPI GetIpAddrTable( MIB_IPADDRTABLE *table, ULONG *size, BOOL sort )
1951 DWORD err, count, needed, i, loopback, row_num = 0;
1952 struct nsi_ipv4_unicast_key *keys;
1953 struct nsi_ip_unicast_rw *rw;
1955 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
1956 if (!size) return ERROR_INVALID_PARAMETER;
1958 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&keys, sizeof(*keys),
1959 (void **)&rw, sizeof(*rw), NULL, 0, NULL, 0, &count, 0 );
1960 if (err) return err;
1962 needed = FIELD_OFFSET( MIB_IPADDRTABLE, table[count] );
1964 if (!table || *size < needed)
1966 *size = needed;
1967 err = ERROR_INSUFFICIENT_BUFFER;
1968 goto err;
1971 table->dwNumEntries = count;
1973 for (loopback = 0; loopback < 2; loopback++) /* Move the loopback addresses to the end */
1975 for (i = 0; i < count; i++)
1977 MIB_IPADDRROW *row = table->table + row_num;
1979 if (!!loopback != (keys[i].luid.Info.IfType == MIB_IF_TYPE_LOOPBACK)) continue;
1981 row->dwAddr = keys[i].addr.s_addr;
1982 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
1983 ConvertLengthToIpv4Mask( rw[i].on_link_prefix, &row->dwMask );
1984 row->dwBCastAddr = 1;
1985 row->dwReasmSize = 0xffff;
1986 row->unused1 = 0;
1987 row->wType = MIB_IPADDR_PRIMARY;
1988 row_num++;
1992 if (sort) qsort( table->table, count, sizeof(MIB_IPADDRROW), ipaddrrow_cmp );
1993 err:
1994 NsiFreeTable( keys, rw, NULL, NULL );
1996 return err;
2000 /******************************************************************
2001 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2003 * Get interface-to-IP address mapping table.
2004 * Like GetIpAddrTable(), but allocate the returned table from heap.
2006 * PARAMS
2007 * table [Out] pointer into which the MIB_IPADDRTABLE is
2008 * allocated and returned.
2009 * sort [In] whether to sort the table
2010 * heap [In] heap from which the table is allocated
2011 * flags [In] flags to HeapAlloc
2014 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2016 DWORD err, size = FIELD_OFFSET(MIB_IPADDRTABLE, table[2]), attempt;
2018 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2020 for (attempt = 0; attempt < 5; attempt++)
2022 *table = HeapAlloc( heap, flags, size );
2023 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2025 err = GetIpAddrTable( *table, &size, sort );
2026 if (!err) break;
2027 HeapFree( heap, flags, *table );
2028 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2031 return err;
2034 static int ipforward_row_cmp( const void *a, const void *b )
2036 const MIB_IPFORWARDROW *rowA = a, *rowB = b;
2037 return DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardDest ), RtlUlongByteSwap( rowB->dwForwardDest )) ||
2038 DWORD_cmp(rowA->dwForwardProto, rowB->dwForwardProto) ||
2039 DWORD_cmp(rowA->dwForwardPolicy, rowB->dwForwardPolicy) ||
2040 DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardNextHop ), RtlUlongByteSwap( rowB->dwForwardNextHop ));
2043 /******************************************************************
2044 * GetIpForwardTable (IPHLPAPI.@)
2046 * Get the route table.
2048 * PARAMS
2049 * table [Out] buffer for route table
2050 * size [In/Out] length of output buffer
2051 * sort [In] whether to sort the table
2053 * RETURNS
2054 * Success: NO_ERROR
2055 * Failure: error code from winerror.h
2057 DWORD WINAPI GetIpForwardTable( MIB_IPFORWARDTABLE *table, ULONG *size, BOOL sort )
2059 DWORD err, count, uni_count, needed, i, addr;
2060 struct nsi_ipv4_forward_key *keys;
2061 struct nsi_ip_forward_rw *rw;
2062 struct nsi_ipv4_forward_dynamic *dyn;
2063 struct nsi_ip_forward_static *stat;
2064 struct nsi_ipv4_unicast_key *uni_keys = NULL;
2066 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2067 if (!size) return ERROR_INVALID_PARAMETER;
2069 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, (void **)&keys, sizeof(*keys),
2070 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2071 (void **)&stat, sizeof(*stat), &count, 0 );
2072 if (err) return err;
2074 needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
2076 if (!table || *size < needed)
2078 *size = needed;
2079 err = ERROR_INSUFFICIENT_BUFFER;
2080 goto err;
2083 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
2084 NULL, 0, NULL, 0, NULL, 0, &uni_count, 0 );
2085 if (err) goto err;
2087 table->dwNumEntries = count;
2088 for (i = 0; i < count; i++)
2090 MIB_IPFORWARDROW *row = table->table + i;
2092 row->dwForwardDest = keys[i].prefix.s_addr;
2093 ConvertLengthToIpv4Mask( keys[i].prefix_len, &row->dwForwardMask );
2094 row->dwForwardPolicy = 0;
2095 row->dwForwardNextHop = keys[i].next_hop.s_addr;
2096 row->dwForwardType = row->dwForwardNextHop ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
2097 if (!row->dwForwardNextHop) /* find the interface's addr */
2099 for (addr = 0; addr < uni_count; addr++)
2101 if (uni_keys[addr].luid.Value == keys[i].luid.Value)
2103 row->dwForwardNextHop = uni_keys[addr].addr.s_addr;
2104 break;
2108 row->dwForwardIfIndex = stat[i].if_index;
2109 row->dwForwardProto = rw[i].protocol;
2110 row->dwForwardAge = dyn[i].age;
2111 row->dwForwardNextHopAS = 0;
2112 row->dwForwardMetric1 = rw[i].metric; /* FIXME: add interface metric */
2113 row->dwForwardMetric2 = 0;
2114 row->dwForwardMetric3 = 0;
2115 row->dwForwardMetric4 = 0;
2116 row->dwForwardMetric5 = 0;
2119 if (sort) qsort( table->table, count, sizeof(MIB_IPFORWARDROW), ipforward_row_cmp );
2120 err:
2121 NsiFreeTable( uni_keys, NULL, NULL, NULL );
2122 NsiFreeTable( keys, rw, dyn, stat );
2124 return err;
2127 /******************************************************************
2128 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2130 * Get the route table.
2131 * Like GetIpForwardTable(), but allocate the returned table from heap.
2133 * PARAMS
2134 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2135 * allocated and returned.
2136 * sort [In] whether to sort the table
2137 * heap [In] heap from which the table is allocated
2138 * flags [In] flags to HeapAlloc
2140 * RETURNS
2141 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2142 * on failure, NO_ERROR on success.
2144 DWORD WINAPI AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2146 DWORD err, size = FIELD_OFFSET(MIB_IPFORWARDTABLE, table[2]), attempt;
2148 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2150 for (attempt = 0; attempt < 5; attempt++)
2152 *table = HeapAlloc( heap, flags, size );
2153 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2155 err = GetIpForwardTable( *table, &size, sort );
2156 if (!err) break;
2157 HeapFree( heap, flags, *table );
2158 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2161 return err;
2164 static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
2165 void *dyn, struct nsi_ip_forward_static *stat )
2167 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key;
2168 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key;
2169 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn;
2170 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn;
2172 if (fam == AF_INET)
2174 row->InterfaceLuid = key4->luid;
2175 row->DestinationPrefix.Prefix.Ipv4.sin_family = fam;
2176 row->DestinationPrefix.Prefix.Ipv4.sin_port = 0;
2177 row->DestinationPrefix.Prefix.Ipv4.sin_addr = key4->prefix;
2178 memset( &row->DestinationPrefix.Prefix.Ipv4.sin_zero, 0, sizeof(row->DestinationPrefix.Prefix.Ipv4.sin_zero) );
2179 row->DestinationPrefix.PrefixLength = key4->prefix_len;
2180 row->NextHop.Ipv4.sin_family = fam;
2181 row->NextHop.Ipv4.sin_port = 0;
2182 row->NextHop.Ipv4.sin_addr = key4->next_hop;
2183 memset( &row->NextHop.Ipv4.sin_zero, 0, sizeof(row->NextHop.Ipv4.sin_zero) );
2185 row->Age = dyn4->age;
2187 else
2189 row->InterfaceLuid = key6->luid;
2191 row->DestinationPrefix.Prefix.Ipv6.sin6_family = fam;
2192 row->DestinationPrefix.Prefix.Ipv6.sin6_port = 0;
2193 row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo = 0;
2194 row->DestinationPrefix.Prefix.Ipv6.sin6_addr = key6->prefix;
2195 row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id = 0;
2196 row->DestinationPrefix.PrefixLength = key6->prefix_len;
2197 row->NextHop.Ipv6.sin6_family = fam;
2198 row->NextHop.Ipv6.sin6_port = 0;
2199 row->NextHop.Ipv6.sin6_flowinfo = 0;
2200 row->NextHop.Ipv6.sin6_addr = key6->next_hop;
2201 row->NextHop.Ipv6.sin6_scope_id = 0;
2203 row->Age = dyn6->age;
2206 row->InterfaceIndex = stat->if_index;
2208 row->SitePrefixLength = rw->site_prefix_len;
2209 row->ValidLifetime = rw->valid_lifetime;
2210 row->PreferredLifetime = rw->preferred_lifetime;
2211 row->Metric = rw->metric;
2212 row->Protocol = rw->protocol;
2213 row->Loopback = rw->loopback;
2214 row->AutoconfigureAddress = rw->autoconf;
2215 row->Publish = rw->publish;
2216 row->Immortal = rw->immortal;
2218 row->Origin = stat->origin;
2221 /******************************************************************
2222 * GetIpForwardTable2 (IPHLPAPI.@)
2224 DWORD WINAPI GetIpForwardTable2( ADDRESS_FAMILY family, MIB_IPFORWARD_TABLE2 **table )
2226 void *key[2] = { NULL, NULL };
2227 struct nsi_ip_forward_rw *rw[2] = { NULL, NULL };
2228 void *dyn[2] = { NULL, NULL };
2229 struct nsi_ip_forward_static *stat[2] = { NULL, NULL };
2230 static const USHORT fam[2] = { AF_INET, AF_INET6 };
2231 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ipv6_forward_key) };
2232 static const DWORD dyn_size[2] = { sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ipv6_forward_dynamic) };
2233 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2235 TRACE( "%u, %p\n", family, table );
2237 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
2238 return ERROR_INVALID_PARAMETER;
2240 for (i = 0; i < 2; i++)
2242 if (family != AF_UNSPEC && family != fam[i]) continue;
2244 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_FORWARD_TABLE, key + i, key_size[i],
2245 (void **)rw + i, sizeof(**rw), dyn + i, dyn_size[i],
2246 (void **)stat + i, sizeof(**stat), count + i, 0 );
2247 if (err) count[i] = 0;
2250 size = FIELD_OFFSET(MIB_IPFORWARD_TABLE2, Table[ count[0] + count[1] ]);
2251 *table = heap_alloc( size );
2252 if (!*table)
2254 err = ERROR_NOT_ENOUGH_MEMORY;
2255 goto err;
2258 (*table)->NumEntries = count[0] + count[1];
2259 for (i = 0; i < count[0]; i++)
2261 MIB_IPFORWARD_ROW2 *row = (*table)->Table + i;
2262 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key[0];
2263 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn[0];
2265 forward_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn4 + i, stat[0] + i );
2268 for (i = 0; i < count[1]; i++)
2270 MIB_IPFORWARD_ROW2 *row = (*table)->Table + count[0] + i;
2271 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key[1];
2272 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn[1];
2274 forward_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn6 + i, stat[1] + i );
2277 err:
2278 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
2279 return err;
2282 static int ipnetrow_cmp( const void *a, const void *b )
2284 const MIB_IPNETROW *rowA = a, *rowB = b;
2286 if (rowA->dwIndex != rowB->dwIndex) return DWORD_cmp( rowA->dwIndex, rowB->dwIndex );
2288 return DWORD_cmp(RtlUlongByteSwap( rowA->dwAddr ), RtlUlongByteSwap( rowB->dwAddr ));
2291 /******************************************************************
2292 * GetIpNetTable (IPHLPAPI.@)
2294 * Get the IP-to-physical address mapping table.
2296 * PARAMS
2297 * table [Out] buffer for mapping table
2298 * size [In/Out] length of output buffer
2299 * sort [In] whether to sort the table
2301 * RETURNS
2302 * Success: NO_ERROR
2303 * Failure: error code from winerror.h
2306 DWORD WINAPI GetIpNetTable( MIB_IPNETTABLE *table, ULONG *size, BOOL sort )
2308 DWORD err, count, needed, i;
2309 struct nsi_ipv4_neighbour_key *keys;
2310 struct nsi_ip_neighbour_rw *rw;
2311 struct nsi_ip_neighbour_dynamic *dyn;
2313 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2315 if (!size) return ERROR_INVALID_PARAMETER;
2317 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_NEIGHBOUR_TABLE, (void **)&keys, sizeof(*keys),
2318 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2319 NULL, 0, &count, 0 );
2320 if (err) return err;
2322 needed = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
2324 if (!table || *size < needed)
2326 *size = needed;
2327 err = ERROR_INSUFFICIENT_BUFFER;
2328 goto err;
2331 table->dwNumEntries = count;
2333 if (!count)
2335 err = ERROR_NO_DATA;
2336 goto err;
2339 for (i = 0; i < count; i++)
2341 MIB_IPNETROW *row = table->table + i;
2343 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
2344 row->dwPhysAddrLen = dyn[i].phys_addr_len;
2345 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
2346 memcpy( row->bPhysAddr, rw[i].phys_addr, row->dwPhysAddrLen );
2347 memset( row->bPhysAddr + row->dwPhysAddrLen, 0,
2348 sizeof(row->bPhysAddr) - row->dwPhysAddrLen );
2349 row->dwAddr = keys[i].addr.s_addr;
2351 switch (dyn[i].state)
2353 case NlnsUnreachable:
2354 case NlnsIncomplete:
2355 row->Type = MIB_IPNET_TYPE_INVALID;
2356 break;
2357 case NlnsProbe:
2358 case NlnsDelay:
2359 case NlnsStale:
2360 case NlnsReachable:
2361 row->Type = MIB_IPNET_TYPE_DYNAMIC;
2362 break;
2363 case NlnsPermanent:
2364 row->Type = MIB_IPNET_TYPE_STATIC;
2365 break;
2366 default:
2367 row->Type = MIB_IPNET_TYPE_OTHER;
2371 if (sort) qsort( table->table, table->dwNumEntries, sizeof(*table->table), ipnetrow_cmp );
2373 err:
2374 NsiFreeTable( keys, rw, dyn, NULL );
2375 return err;
2378 /******************************************************************
2379 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2381 DWORD WINAPI AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2383 DWORD err, size = FIELD_OFFSET(MIB_IPNETTABLE, table[2]), attempt;
2385 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2387 for (attempt = 0; attempt < 5; attempt++)
2389 *table = HeapAlloc( heap, flags, size );
2390 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2392 err = GetIpNetTable( *table, &size, sort );
2393 if (!err) break;
2394 HeapFree( heap, flags, *table );
2395 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2398 return err;
2401 static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw,
2402 struct nsi_ip_neighbour_dynamic *dyn )
2404 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key;
2405 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key;
2407 if (fam == AF_INET)
2409 row->Address.Ipv4.sin_family = fam;
2410 row->Address.Ipv4.sin_port = 0;
2411 row->Address.Ipv4.sin_addr = key4->addr;
2412 memset( &row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
2413 row->InterfaceLuid = key4->luid;
2415 else
2417 row->Address.Ipv6.sin6_family = fam;
2418 row->Address.Ipv6.sin6_port = 0;
2419 row->Address.Ipv6.sin6_flowinfo = 0;
2420 row->Address.Ipv6.sin6_addr = key6->addr;
2421 row->Address.Ipv6.sin6_scope_id = 0;
2422 row->InterfaceLuid = key6->luid;
2425 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
2427 row->PhysicalAddressLength = dyn->phys_addr_len;
2428 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress))
2429 row->PhysicalAddressLength = 0;
2430 memcpy( row->PhysicalAddress, rw->phys_addr, row->PhysicalAddressLength );
2431 memset( row->PhysicalAddress + row->PhysicalAddressLength, 0,
2432 sizeof(row->PhysicalAddress) - row->PhysicalAddressLength );
2433 row->State = dyn->state;
2434 row->Flags = 0;
2435 row->IsRouter = dyn->flags.is_router;
2436 row->IsUnreachable = dyn->flags.is_unreachable;
2437 row->ReachabilityTime.LastReachable = dyn->time;
2440 /******************************************************************
2441 * GetIpNetTable2 (IPHLPAPI.@)
2443 DWORD WINAPI GetIpNetTable2( ADDRESS_FAMILY family, MIB_IPNET_TABLE2 **table )
2445 void *key[2] = { NULL, NULL };
2446 struct nsi_ip_neighbour_rw *rw[2] = { NULL, NULL };
2447 struct nsi_ip_neighbour_dynamic *dyn[2] = { NULL, NULL };
2448 static const USHORT fam[2] = { AF_INET, AF_INET6 };
2449 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ipv6_neighbour_key) };
2450 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2452 TRACE( "%u, %p\n", family, table );
2454 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
2455 return ERROR_INVALID_PARAMETER;
2457 for (i = 0; i < 2; i++)
2459 if (family != AF_UNSPEC && family != fam[i]) continue;
2461 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_NEIGHBOUR_TABLE, key + i, key_size[i],
2462 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
2463 NULL, 0, count + i, 0 );
2464 if (err) count[i] = 0;
2467 size = FIELD_OFFSET(MIB_IPNET_TABLE2, Table[ count[0] + count[1] ]);
2468 *table = heap_alloc( size );
2469 if (!*table)
2471 err = ERROR_NOT_ENOUGH_MEMORY;
2472 goto err;
2475 (*table)->NumEntries = count[0] + count[1];
2476 for (i = 0; i < count[0]; i++)
2478 MIB_IPNET_ROW2 *row = (*table)->Table + i;
2479 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key[0];
2481 ipnet_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn[0] + i );
2484 for (i = 0; i < count[1]; i++)
2486 MIB_IPNET_ROW2 *row = (*table)->Table + count[0] + i;
2487 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key[1];
2489 ipnet_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn[1] + i );
2492 err:
2493 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], NULL );
2494 return err;
2497 /******************************************************************
2498 * GetIpStatistics (IPHLPAPI.@)
2500 * Get the IP statistics for the local computer.
2502 * PARAMS
2503 * stats [Out] buffer for IP statistics
2505 * RETURNS
2506 * Success: NO_ERROR
2507 * Failure: error code from winerror.h
2509 DWORD WINAPI GetIpStatistics( MIB_IPSTATS *stats )
2511 return GetIpStatisticsEx( stats, AF_INET );
2514 /******************************************************************
2515 * GetIpStatisticsEx (IPHLPAPI.@)
2517 * Get the IPv4 and IPv6 statistics for the local computer.
2519 * PARAMS
2520 * stats [Out] buffer for IP statistics
2521 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2523 * RETURNS
2524 * Success: NO_ERROR
2525 * Failure: error code from winerror.h
2527 DWORD WINAPI GetIpStatisticsEx( MIB_IPSTATS *stats, DWORD family )
2529 struct nsi_ip_ipstats_dynamic dyn;
2530 struct nsi_ip_ipstats_static stat;
2531 struct nsi_ip_cmpt_rw cmpt_rw;
2532 struct nsi_ip_cmpt_dynamic cmpt_dyn;
2533 const NPI_MODULEID *mod;
2534 DWORD err, cmpt = 1;
2536 TRACE( "%p %ld\n", stats, family );
2538 if (!stats) return ERROR_INVALID_PARAMETER;
2539 mod = ip_module_id( family );
2540 if (!mod) return ERROR_INVALID_PARAMETER;
2542 memset( stats, 0, sizeof(*stats) );
2544 err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0,
2545 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2546 if (err) return err;
2548 err = NsiGetAllParameters( 1, mod, NSI_IP_COMPARTMENT_TABLE, &cmpt, sizeof(cmpt), &cmpt_rw, sizeof(cmpt_rw),
2549 &cmpt_dyn, sizeof(cmpt_dyn), NULL, 0 );
2550 if (err) return err;
2552 stats->Forwarding = cmpt_rw.not_forwarding + 1;
2553 stats->dwDefaultTTL = cmpt_rw.default_ttl;
2554 stats->dwInReceives = dyn.in_recv;
2555 stats->dwInHdrErrors = dyn.in_hdr_errs;
2556 stats->dwInAddrErrors = dyn.in_addr_errs;
2557 stats->dwForwDatagrams = dyn.fwd_dgrams;
2558 stats->dwInUnknownProtos = dyn.in_unk_protos;
2559 stats->dwInDiscards = dyn.in_discards;
2560 stats->dwInDelivers = dyn.in_delivers;
2561 stats->dwOutRequests = dyn.out_reqs;
2562 stats->dwRoutingDiscards = dyn.routing_discards;
2563 stats->dwOutDiscards = dyn.out_discards;
2564 stats->dwOutNoRoutes = dyn.out_no_routes;
2565 stats->dwReasmTimeout = stat.reasm_timeout;
2566 stats->dwReasmReqds = dyn.reasm_reqds;
2567 stats->dwReasmOks = dyn.reasm_oks;
2568 stats->dwReasmFails = dyn.reasm_fails;
2569 stats->dwFragOks = dyn.frag_oks;
2570 stats->dwFragFails = dyn.frag_fails;
2571 stats->dwFragCreates = dyn.frag_creates;
2572 stats->dwNumIf = cmpt_dyn.num_ifs;
2573 stats->dwNumAddr = cmpt_dyn.num_addrs;
2574 stats->dwNumRoutes = cmpt_dyn.num_routes;
2576 return err;
2579 /* Gets the DNS server list into the list beginning at list. Assumes that
2580 * a single server address may be placed at list if *len is at least
2581 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2582 * and assumes that all remaining DNS servers are contiguously located
2583 * beginning at second. On input, *len is assumed to be the total number
2584 * of bytes available for all DNS servers, and is ignored if list is NULL.
2585 * On return, *len is set to the total number of bytes required for all DNS
2586 * servers.
2587 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2588 * ERROR_SUCCESS otherwise.
2590 static DWORD get_dns_server_list( const NET_LUID *luid, IP_ADDR_STRING *list, IP_ADDR_STRING *second, DWORD *len )
2592 char buf[FIELD_OFFSET(IP4_ARRAY, AddrArray[3])];
2593 IP4_ARRAY *servers = (IP4_ARRAY *)buf;
2594 DWORD needed, num, err, i, array_len = sizeof(buf);
2595 IP_ADDR_STRING *ptr;
2597 if (luid && luid->Info.IfType == MIB_IF_TYPE_LOOPBACK) return ERROR_NO_DATA;
2599 for (;;)
2601 err = DnsQueryConfig( DnsConfigDnsServerList, 0, NULL, NULL, servers, &array_len );
2602 if (err != ERROR_SUCCESS && err != ERROR_MORE_DATA) goto err;
2603 num = (array_len - FIELD_OFFSET(IP4_ARRAY, AddrArray[0])) / sizeof(IP4_ADDRESS);
2604 needed = num * sizeof(IP_ADDR_STRING);
2605 if (!list || *len < needed)
2607 *len = needed;
2608 err = ERROR_BUFFER_OVERFLOW;
2609 goto err;
2611 if (!err) break;
2613 if ((char *)servers != buf) heap_free( servers );
2614 servers = heap_alloc( array_len );
2615 if (!servers)
2617 err = ERROR_NOT_ENOUGH_MEMORY;
2618 goto err;
2622 *len = needed;
2624 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next)
2626 RtlIpv4AddressToStringA( (IN_ADDR *)&servers->AddrArray[i], ptr->IpAddress.String );
2627 if (i == num - 1) ptr->Next = NULL;
2628 else if (i == 0) ptr->Next = second;
2629 else ptr->Next = ptr + 1;
2632 err:
2633 if ((char *)servers != buf) heap_free( servers );
2634 return err;
2637 /******************************************************************
2638 * GetNetworkParams (IPHLPAPI.@)
2640 * Get the network parameters for the local computer.
2642 * PARAMS
2643 * info [Out] buffer for network parameters
2644 * size [In/Out] length of output buffer
2646 * RETURNS
2647 * Success: NO_ERROR
2648 * Failure: error code from winerror.h
2650 * NOTES
2651 * If size is less than required, the function will return
2652 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2653 * size.
2655 DWORD WINAPI GetNetworkParams( FIXED_INFO *info, ULONG *size )
2657 DWORD needed = sizeof(*info), dns_size, err;
2658 MIB_IPSTATS ip_stats;
2659 HKEY key;
2661 TRACE( "info %p, size %p\n", info, size );
2662 if (!size) return ERROR_INVALID_PARAMETER;
2664 if (get_dns_server_list( NULL, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2665 needed += dns_size - sizeof(IP_ADDR_STRING);
2666 if (!info || *size < needed)
2668 *size = needed;
2669 return ERROR_BUFFER_OVERFLOW;
2672 *size = needed;
2673 memset( info, 0, needed );
2674 needed = sizeof(info->HostName);
2675 GetComputerNameExA( ComputerNameDnsHostname, info->HostName, &needed );
2676 needed = sizeof(info->DomainName);
2677 GetComputerNameExA( ComputerNameDnsDomain, info->DomainName, &needed );
2678 get_dns_server_list( NULL, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2679 info->CurrentDnsServer = &info->DnsServerList;
2680 info->NodeType = HYBRID_NODETYPE;
2681 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2682 0, KEY_READ, &key );
2683 if (err)
2684 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2685 0, KEY_READ, &key );
2686 if (!err)
2688 needed = sizeof(info->ScopeId);
2689 RegQueryValueExA( key, "ScopeID", NULL, NULL, (BYTE *)info->ScopeId, &needed );
2690 RegCloseKey( key );
2693 if (!GetIpStatistics( &ip_stats ))
2694 info->EnableRouting = (ip_stats.Forwarding == MIB_IP_FORWARDING);
2696 return ERROR_SUCCESS;
2700 /******************************************************************
2701 * GetNumberOfInterfaces (IPHLPAPI.@)
2703 * Get the number of interfaces.
2705 * PARAMS
2706 * pdwNumIf [Out] number of interfaces
2708 * RETURNS
2709 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2711 DWORD WINAPI GetNumberOfInterfaces( DWORD *count )
2713 DWORD err, num;
2715 TRACE( "count %p\n", count );
2716 if (!count) return ERROR_INVALID_PARAMETER;
2718 err = NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0,
2719 NULL, 0, NULL, 0, NULL, 0, &num );
2720 *count = err ? 0 : num;
2721 return err;
2724 /******************************************************************
2725 * GetPerAdapterInfo (IPHLPAPI.@)
2727 * Get information about an adapter corresponding to an interface.
2729 * PARAMS
2730 * IfIndex [In] interface info
2731 * pPerAdapterInfo [Out] buffer for per adapter info
2732 * pOutBufLen [In/Out] length of output buffer
2734 * RETURNS
2735 * Success: NO_ERROR
2736 * Failure: error code from winerror.h
2738 DWORD WINAPI GetPerAdapterInfo( ULONG index, IP_PER_ADAPTER_INFO *info, ULONG *size )
2740 DWORD needed = sizeof(*info), dns_size;
2741 NET_LUID luid;
2743 TRACE( "(index %ld, info %p, size %p)\n", index, info, size );
2745 if (!size) return ERROR_INVALID_PARAMETER;
2746 if (ConvertInterfaceIndexToLuid( index, &luid )) return ERROR_NO_DATA;
2748 if (get_dns_server_list( &luid, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2749 needed += dns_size - sizeof(IP_ADDR_STRING);
2751 if (!info || *size < needed)
2753 *size = needed;
2754 return ERROR_BUFFER_OVERFLOW;
2757 memset( info, 0, needed );
2758 get_dns_server_list( &luid, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2759 info->CurrentDnsServer = &info->DnsServerList;
2761 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2762 return ERROR_SUCCESS;
2766 /******************************************************************
2767 * GetRTTAndHopCount (IPHLPAPI.@)
2769 * Get round-trip time (RTT) and hop count.
2771 * PARAMS
2773 * DestIpAddress [In] destination address to get the info for
2774 * HopCount [Out] retrieved hop count
2775 * MaxHops [In] maximum hops to search for the destination
2776 * RTT [Out] RTT in milliseconds
2778 * RETURNS
2779 * Success: TRUE
2780 * Failure: FALSE
2782 * FIXME
2783 * Stub, returns FALSE.
2785 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2787 FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
2788 DestIpAddress, HopCount, MaxHops, RTT);
2789 return FALSE;
2792 /******************************************************************
2793 * GetTcpStatistics (IPHLPAPI.@)
2795 * Get the TCP statistics for the local computer.
2797 * PARAMS
2798 * stats [Out] buffer for TCP statistics
2800 * RETURNS
2801 * Success: NO_ERROR
2802 * Failure: error code from winerror.h
2804 DWORD WINAPI GetTcpStatistics( MIB_TCPSTATS *stats )
2806 return GetTcpStatisticsEx( stats, AF_INET );
2809 /******************************************************************
2810 * GetTcpStatisticsEx (IPHLPAPI.@)
2812 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2814 * PARAMS
2815 * stats [Out] buffer for TCP statistics
2816 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2818 * RETURNS
2819 * Success: NO_ERROR
2820 * Failure: error code from winerror.h
2822 DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
2824 struct nsi_tcp_stats_dynamic dyn;
2825 struct nsi_tcp_stats_static stat;
2826 USHORT key = (USHORT)family;
2827 DWORD err;
2829 if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
2830 memset( stats, 0, sizeof(*stats) );
2832 err = NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
2833 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2834 if (err) return err;
2836 stats->RtoAlgorithm = stat.rto_algo;
2837 stats->dwRtoMin = stat.rto_min;
2838 stats->dwRtoMax = stat.rto_max;
2839 stats->dwMaxConn = stat.max_conns;
2840 stats->dwActiveOpens = dyn.active_opens;
2841 stats->dwPassiveOpens = dyn.passive_opens;
2842 stats->dwAttemptFails = dyn.attempt_fails;
2843 stats->dwEstabResets = dyn.est_rsts;
2844 stats->dwCurrEstab = dyn.cur_est;
2845 stats->dwInSegs = (DWORD)dyn.in_segs;
2846 stats->dwOutSegs = (DWORD)dyn.out_segs;
2847 stats->dwRetransSegs = dyn.retrans_segs;
2848 stats->dwInErrs = dyn.in_errs;
2849 stats->dwOutRsts = dyn.out_rsts;
2850 stats->dwNumConns = dyn.num_conns;
2852 return err;
2855 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2857 static DWORD tcp_table_id( ULONG table_class )
2859 switch (table_class)
2861 case TCP_TABLE_BASIC_LISTENER:
2862 case TCP_TABLE_OWNER_PID_LISTENER:
2863 case TCP_TABLE_OWNER_MODULE_LISTENER:
2864 return NSI_TCP_LISTEN_TABLE;
2866 case TCP_TABLE_BASIC_CONNECTIONS:
2867 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2868 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2869 return NSI_TCP_ESTAB_TABLE;
2871 case TCP_TABLE_BASIC_ALL:
2872 case TCP_TABLE_OWNER_PID_ALL:
2873 case TCP_TABLE_OWNER_MODULE_ALL:
2874 case TCP_TABLE2:
2875 return NSI_TCP_ALL_TABLE;
2877 default:
2878 ERR( "unhandled class %lu\n", table_class );
2879 return ~0u;
2883 static DWORD tcp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
2885 switch (table_class)
2887 case TCP_TABLE_BASIC_LISTENER:
2888 case TCP_TABLE_BASIC_CONNECTIONS:
2889 case TCP_TABLE_BASIC_ALL:
2890 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW) : sizeof(MIB_TCP6ROW);
2891 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE, table[row_count]) :
2892 FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
2894 case TCP_TABLE_OWNER_PID_LISTENER:
2895 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2896 case TCP_TABLE_OWNER_PID_ALL:
2897 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW_OWNER_PID) : sizeof(MIB_TCP6ROW_OWNER_PID);
2898 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]) :
2899 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
2901 case TCP_TABLE_OWNER_MODULE_LISTENER:
2902 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2903 case TCP_TABLE_OWNER_MODULE_ALL:
2904 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW_OWNER_MODULE) : sizeof(MIB_TCP6ROW_OWNER_MODULE);
2905 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]) :
2906 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
2908 case TCP_TABLE2:
2909 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW2) : sizeof(MIB_TCP6ROW2);
2910 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE2, table[row_count]) :
2911 FIELD_OFFSET(MIB_TCP6TABLE2, table[row_count]);
2913 default:
2914 ERR( "unhandled class %lu\n", table_class );
2915 return 0;
2919 static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
2920 struct nsi_tcp_conn_key *key, struct nsi_tcp_conn_dynamic *dyn,
2921 struct nsi_tcp_conn_static *stat )
2923 if (family == AF_INET)
2925 switch (table_class)
2927 case TCP_TABLE_BASIC_LISTENER:
2928 case TCP_TABLE_BASIC_CONNECTIONS:
2929 case TCP_TABLE_BASIC_ALL:
2931 MIB_TCPROW *row = ((MIB_TCPTABLE *)table)->table + num;
2932 row->dwState = dyn->state;
2933 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2934 row->dwLocalPort = key->local.Ipv4.sin_port;
2935 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2936 row->dwRemotePort = key->remote.Ipv4.sin_port;
2937 return;
2939 case TCP_TABLE_OWNER_PID_LISTENER:
2940 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2941 case TCP_TABLE_OWNER_PID_ALL:
2943 MIB_TCPROW_OWNER_PID *row = ((MIB_TCPTABLE_OWNER_PID *)table)->table + num;
2944 row->dwState = dyn->state;
2945 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2946 row->dwLocalPort = key->local.Ipv4.sin_port;
2947 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2948 row->dwRemotePort = key->remote.Ipv4.sin_port;
2949 row->dwOwningPid = stat->pid;
2950 return;
2952 case TCP_TABLE_OWNER_MODULE_LISTENER:
2953 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2954 case TCP_TABLE_OWNER_MODULE_ALL:
2956 MIB_TCPROW_OWNER_MODULE *row = ((MIB_TCPTABLE_OWNER_MODULE *)table)->table + num;
2957 row->dwState = dyn->state;
2958 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2959 row->dwLocalPort = key->local.Ipv4.sin_port;
2960 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2961 row->dwRemotePort = key->remote.Ipv4.sin_port;
2962 row->dwOwningPid = stat->pid;
2963 row->liCreateTimestamp.QuadPart = stat->create_time;
2964 row->OwningModuleInfo[0] = stat->mod_info;
2965 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
2966 return;
2968 case TCP_TABLE2:
2970 MIB_TCPROW2 *row = ((MIB_TCPTABLE2 *)table)->table + num;
2971 row->dwState = dyn->state;
2972 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2973 row->dwLocalPort = key->local.Ipv4.sin_port;
2974 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2975 row->dwRemotePort = key->remote.Ipv4.sin_port;
2976 row->dwOwningPid = stat->pid;
2977 row->dwOffloadState = 0; /* FIXME */
2978 return;
2980 default:
2981 ERR( "Unknown class %ld\n", table_class );
2982 return;
2985 else
2987 switch (table_class)
2989 case TCP_TABLE_BASIC_LISTENER:
2990 case TCP_TABLE_BASIC_CONNECTIONS:
2991 case TCP_TABLE_BASIC_ALL:
2993 MIB_TCP6ROW *row = ((MIB_TCP6TABLE *)table)->table + num;
2994 row->State = dyn->state;
2995 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
2996 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
2997 row->dwLocalPort = key->local.Ipv6.sin6_port;
2998 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
2999 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3000 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3001 return;
3003 case TCP_TABLE_OWNER_PID_LISTENER:
3004 case TCP_TABLE_OWNER_PID_CONNECTIONS:
3005 case TCP_TABLE_OWNER_PID_ALL:
3007 MIB_TCP6ROW_OWNER_PID *row = ((MIB_TCP6TABLE_OWNER_PID *)table)->table + num;
3008 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3009 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3010 row->dwLocalPort = key->local.Ipv6.sin6_port;
3011 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3012 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3013 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3014 row->dwState = dyn->state;
3015 row->dwOwningPid = stat->pid;
3016 return;
3018 case TCP_TABLE_OWNER_MODULE_LISTENER:
3019 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
3020 case TCP_TABLE_OWNER_MODULE_ALL:
3022 MIB_TCP6ROW_OWNER_MODULE *row = ((MIB_TCP6TABLE_OWNER_MODULE *)table)->table + num;
3023 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3024 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3025 row->dwLocalPort = key->local.Ipv6.sin6_port;
3026 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3027 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3028 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3029 row->dwState = dyn->state;
3030 row->dwOwningPid = stat->pid;
3031 row->liCreateTimestamp.QuadPart = stat->create_time;
3032 row->OwningModuleInfo[0] = stat->mod_info;
3033 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3034 return;
3036 case TCP_TABLE2:
3038 MIB_TCP6ROW2 *row = ((MIB_TCP6TABLE2 *)table)->table + num;
3039 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
3040 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3041 row->dwLocalPort = key->local.Ipv6.sin6_port;
3042 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
3043 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3044 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3045 row->State = dyn->state;
3046 row->dwOwningPid = stat->pid;
3047 row->dwOffloadState = 0; /* FIXME */
3048 return;
3050 default:
3051 ERR( "Unknown class %ld\n", table_class );
3052 return;
3055 ERR( "Unknown family %ld\n", family );
3058 static int tcp_row_cmp( const void *a, const void *b )
3060 const MIB_TCPROW *rowA = a, *rowB = b;
3061 int ret;
3063 if ((ret = DWORD_cmp(RtlUshortByteSwap( rowA->dwLocalAddr ), RtlUshortByteSwap( rowB->dwLocalAddr ))) != 0) return ret;
3064 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3065 if ((ret = DWORD_cmp(RtlUshortByteSwap( rowA->dwRemoteAddr ), RtlUshortByteSwap( rowB->dwRemoteAddr ))) != 0) return ret;
3066 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3069 static int tcp6_row_basic_cmp( const void *a, const void *b )
3071 const MIB_TCP6ROW *rowA = a;
3072 const MIB_TCP6ROW *rowB = b;
3073 int ret;
3075 if ((ret = memcmp( &rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr) )) != 0) return ret;
3076 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3077 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3078 if ((ret = memcmp( &rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr) )) != 0) return ret;
3079 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3080 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3083 static int tcp6_row_owner_cmp( const void *a, const void *b )
3085 const MIB_TCP6ROW_OWNER_PID *rowA = a;
3086 const MIB_TCP6ROW_OWNER_PID *rowB = b;
3087 int ret;
3089 if ((ret = memcmp( &rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr) )) != 0) return ret;
3090 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3091 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3092 if ((ret = memcmp( &rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr) )) != 0) return ret;
3093 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3094 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3097 static BOOL tcp_table_needs_pids( ULONG table_class )
3099 switch (table_class)
3101 case TCP_TABLE_BASIC_LISTENER:
3102 case TCP_TABLE_BASIC_CONNECTIONS:
3103 case TCP_TABLE_BASIC_ALL:
3104 return FALSE;
3107 return TRUE;
3110 /*************************************************************************************
3111 * get_extended_tcp_table
3113 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3114 * corresponding to GetTcp(6)Table2()
3116 static DWORD get_extended_tcp_table( void *table, DWORD *size, BOOL sort, ULONG family, ULONG table_class )
3118 DWORD err, count, needed, i, num = 0, row_size = 0;
3119 struct nsi_tcp_conn_key *key;
3120 struct nsi_tcp_conn_dynamic *dyn;
3121 struct nsi_tcp_conn_static *stat = NULL;
3123 if (!size) return ERROR_INVALID_PARAMETER;
3125 if (tcp_table_needs_pids( table_class ))
3126 err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
3127 NULL, 0, (void **)&dyn, sizeof(*dyn),
3128 (void **)&stat, sizeof(*stat), &count, 0 );
3129 else /* Don't retrieve the static data if not required as this is expensive to compute */
3130 err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
3131 NULL, 0, (void **)&dyn, sizeof(*dyn),
3132 NULL, 0, &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 == 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 %lu, class %u, reserved %lu\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, 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, 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, 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, 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%08lx\n", table, sort, heap, flags );
3268 if (!table) return ERROR_INVALID_PARAMETER;
3270 return allocate_tcp_table( (void **)table, sort, heap, flags, 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%08lx, family %lu\n", table, sort, heap, flags, family );
3280 if (!table || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3281 if (family == AF_INET6) return ERROR_NOT_SUPPORTED;
3283 return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
3286 /******************************************************************
3287 * GetUdpStatistics (IPHLPAPI.@)
3289 * Get the UDP statistics for the local computer.
3291 * PARAMS
3292 * stats [Out] buffer for UDP statistics
3294 DWORD WINAPI GetUdpStatistics( MIB_UDPSTATS *stats )
3296 return GetUdpStatisticsEx( stats, AF_INET );
3299 /******************************************************************
3300 * GetUdpStatisticsEx (IPHLPAPI.@)
3302 * Get the IPv4 and IPv6 UDP statistics for the local computer.
3304 * PARAMS
3305 * stats [Out] buffer for UDP statistics
3306 * family [In] specifies whether IPv4 or IPv6 statistics are returned
3308 * RETURNS
3309 * Success: NO_ERROR
3310 * Failure: error code from winerror.h
3312 DWORD WINAPI GetUdpStatisticsEx( MIB_UDPSTATS *stats, DWORD family )
3314 struct nsi_udp_stats_dynamic dyn;
3315 USHORT key = (USHORT)family;
3316 DWORD err;
3318 if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3319 memset( stats, 0, sizeof(*stats) );
3321 err = NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_STATS_TABLE, &key, sizeof(key), NULL, 0,
3322 &dyn, sizeof(dyn), NULL, 0 );
3323 if (err) return err;
3325 stats->dwInDatagrams = dyn.in_dgrams;
3326 stats->dwNoPorts = dyn.no_ports;
3327 stats->dwInErrors = dyn.in_errs;
3328 stats->dwOutDatagrams = dyn.out_dgrams;
3329 stats->dwNumAddrs = dyn.num_addrs;
3330 return err;
3333 /******************************************************************
3334 * GetUdpTable (IPHLPAPI.@)
3336 * Get a table of active UDP connections.
3338 * PARAMS
3339 * table [Out] buffer for UDP connections table
3340 * size [In/Out] length of output buffer
3341 * sort [In] whether to order the table
3344 DWORD WINAPI GetUdpTable( MIB_UDPTABLE *table, DWORD *size, BOOL sort )
3346 return GetExtendedUdpTable( table, size, sort, AF_INET, UDP_TABLE_BASIC, 0 );
3349 /******************************************************************
3350 * GetUdp6Table (IPHLPAPI.@)
3352 DWORD WINAPI GetUdp6Table( MIB_UDP6TABLE *table, DWORD *size, BOOL sort )
3354 return GetExtendedUdpTable( table, size, sort, AF_INET6, UDP_TABLE_BASIC, 0 );
3357 static DWORD udp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
3359 switch (table_class)
3361 case UDP_TABLE_BASIC:
3362 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW) : sizeof(MIB_UDP6ROW);
3363 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE, table[row_count]) :
3364 FIELD_OFFSET(MIB_UDP6TABLE, table[row_count]);
3366 case UDP_TABLE_OWNER_PID:
3367 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW_OWNER_PID) : sizeof(MIB_UDP6ROW_OWNER_PID);
3368 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]) :
3369 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID, table[row_count]);
3371 case UDP_TABLE_OWNER_MODULE:
3372 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW_OWNER_MODULE) : sizeof(MIB_UDP6ROW_OWNER_MODULE);
3373 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]) :
3374 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE, table[row_count]);
3376 default:
3377 ERR( "unhandled class %lu\n", table_class );
3378 return 0;
3382 static void udp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
3383 struct nsi_udp_endpoint_key *key,
3384 struct nsi_udp_endpoint_static *stat )
3386 if (family == AF_INET)
3388 switch (table_class)
3390 case UDP_TABLE_BASIC:
3392 MIB_UDPROW *row = ((MIB_UDPTABLE *)table)->table + num;
3393 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3394 row->dwLocalPort = key->local.Ipv4.sin_port;
3395 return;
3397 case UDP_TABLE_OWNER_PID:
3399 MIB_UDPROW_OWNER_PID *row = ((MIB_UDPTABLE_OWNER_PID *)table)->table + num;
3400 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3401 row->dwLocalPort = key->local.Ipv4.sin_port;
3402 row->dwOwningPid = stat->pid;
3403 return;
3405 case UDP_TABLE_OWNER_MODULE:
3407 MIB_UDPROW_OWNER_MODULE *row = ((MIB_UDPTABLE_OWNER_MODULE *)table)->table + num;
3408 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3409 row->dwLocalPort = key->local.Ipv4.sin_port;
3410 row->dwOwningPid = stat->pid;
3411 row->liCreateTimestamp.QuadPart = stat->create_time;
3412 row->dwFlags = stat->flags;
3413 row->OwningModuleInfo[0] = stat->mod_info;
3414 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3415 return;
3417 default:
3418 ERR( "Unknown class %ld\n", table_class );
3419 return;
3422 else
3424 switch (table_class)
3426 case UDP_TABLE_BASIC:
3428 MIB_UDP6ROW *row = ((MIB_UDP6TABLE *)table)->table + num;
3429 memcpy( &row->dwLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->dwLocalAddr) );
3430 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3431 row->dwLocalPort = key->local.Ipv6.sin6_port;
3432 return;
3434 case UDP_TABLE_OWNER_PID:
3436 MIB_UDP6ROW_OWNER_PID *row = ((MIB_UDP6TABLE_OWNER_PID *)table)->table + num;
3437 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3438 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3439 row->dwLocalPort = key->local.Ipv6.sin6_port;
3440 row->dwOwningPid = stat->pid;
3441 return;
3443 case UDP_TABLE_OWNER_MODULE:
3445 MIB_UDP6ROW_OWNER_MODULE *row = ((MIB_UDP6TABLE_OWNER_MODULE *)table)->table + num;
3446 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3447 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3448 row->dwLocalPort = key->local.Ipv6.sin6_port;
3449 row->dwOwningPid = stat->pid;
3450 row->liCreateTimestamp.QuadPart = stat->create_time;
3451 row->dwFlags = stat->flags;
3452 row->OwningModuleInfo[0] = stat->mod_info;
3453 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3454 return;
3456 default:
3457 ERR( "Unknown class %ld\n", table_class );
3458 return;
3461 ERR( "Unknown family %ld\n", family );
3462 return;
3465 static int udp_row_cmp( const void *a, const void *b )
3467 const MIB_UDPROW *rowA = a, *rowB = b;
3469 return DWORD_cmp(RtlUlongByteSwap( rowA->dwLocalAddr), RtlUlongByteSwap( rowB->dwLocalAddr )) ||
3470 RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort );
3473 static int udp6_row_cmp( const void *a, const void *b )
3475 const MIB_UDP6ROW *rowA = a;
3476 const MIB_UDP6ROW *rowB = b;
3477 int ret;
3479 if ((ret = memcmp( &rowA->dwLocalAddr, &rowB->dwLocalAddr, sizeof(rowA->dwLocalAddr) )) != 0) return ret;
3480 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3481 return RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort );
3484 /******************************************************************
3485 * GetExtendedUdpTable (IPHLPAPI.@)
3487 DWORD WINAPI GetExtendedUdpTable( void *table, DWORD *size, BOOL sort, ULONG family,
3488 UDP_TABLE_CLASS table_class, ULONG reserved )
3490 DWORD err, count, needed, i, num = 0, row_size = 0;
3491 struct nsi_udp_endpoint_key *key;
3492 struct nsi_udp_endpoint_static *stat;
3494 TRACE( "table %p, size %p, sort %d, family %lu, table_class %u, reserved %lu\n",
3495 table, size, sort, family, table_class, reserved );
3497 if (!size || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3499 err = NsiAllocateAndGetTable( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_ENDPOINT_TABLE, (void **)&key, sizeof(*key),
3500 NULL, 0, NULL, 0, (void **)&stat, sizeof(*stat), &count, 0 );
3501 if (err) return err;
3503 for (i = 0; i < count; i++)
3504 if (key[i].local.si_family == family)
3505 num++;
3507 needed = udp_table_size( family, table_class, num, &row_size );
3508 if (!table || *size < needed)
3510 *size = needed;
3511 err = ERROR_INSUFFICIENT_BUFFER;
3513 else
3515 *size = needed;
3516 *(DWORD *)table = num;
3517 num = 0;
3518 for (i = 0; i < count; i++)
3520 if (key[i].local.si_family != family) continue;
3521 udp_row_fill( table, num++, family, table_class, key + i, stat + i );
3525 if (!err && sort)
3527 int (*fn)(const void *, const void *);
3528 DWORD offset = udp_table_size( family, table_class, 0, &row_size );
3530 if (family == AF_INET) fn = udp_row_cmp;
3531 else fn = udp6_row_cmp;
3533 qsort( (BYTE *)table + offset, num, row_size, fn );
3536 NsiFreeTable( key, NULL, NULL, stat );
3537 return err;
3540 DWORD WINAPI AllocateAndGetUdpTableFromStack( MIB_UDPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
3542 DWORD err, size = 0x100, attempt;
3544 TRACE("table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
3546 if (!table) return ERROR_INVALID_PARAMETER;
3548 for (attempt = 0; attempt < 5; attempt++)
3550 *table = HeapAlloc( heap, flags, size );
3551 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
3552 err = GetExtendedUdpTable( *table, &size, sort, AF_INET, UDP_TABLE_BASIC, 0 );
3553 if (!err) break;
3554 HeapFree( heap, flags, *table );
3555 *table = NULL;
3556 if (err != ERROR_INSUFFICIENT_BUFFER) break;
3558 return err;
3561 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW *row, USHORT fam, void *key, struct nsi_ip_unicast_rw *rw,
3562 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
3564 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key;
3565 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key;
3567 if (fam == AF_INET)
3569 row->Address.Ipv4.sin_family = fam;
3570 row->Address.Ipv4.sin_port = 0;
3571 row->Address.Ipv4.sin_addr = key4->addr;
3572 memset( row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
3573 row->InterfaceLuid.Value = key4->luid.Value;
3575 else
3577 row->Address.Ipv6.sin6_family = fam;
3578 row->Address.Ipv6.sin6_port = 0;
3579 row->Address.Ipv6.sin6_flowinfo = 0;
3580 row->Address.Ipv6.sin6_addr = key6->addr;
3581 row->Address.Ipv6.sin6_scope_id = dyn->scope_id;
3582 row->InterfaceLuid.Value = key6->luid.Value;
3585 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
3586 row->PrefixOrigin = rw->prefix_origin;
3587 row->SuffixOrigin = rw->suffix_origin;
3588 row->ValidLifetime = rw->valid_lifetime;
3589 row->PreferredLifetime = rw->preferred_lifetime;
3590 row->OnLinkPrefixLength = rw->on_link_prefix;
3591 row->SkipAsSource = 0;
3592 row->DadState = dyn->dad_state;
3593 row->ScopeId.Value = dyn->scope_id;
3594 row->CreationTimeStamp.QuadPart = stat->creation_time;
3597 DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW *row)
3599 struct nsi_ipv4_unicast_key key4;
3600 struct nsi_ipv6_unicast_key key6;
3601 struct nsi_ip_unicast_rw rw;
3602 struct nsi_ip_unicast_dynamic dyn;
3603 struct nsi_ip_unicast_static stat;
3604 const NPI_MODULEID *mod;
3605 DWORD err, key_size;
3606 void *key;
3608 TRACE( "%p\n", row );
3610 if (!row) return ERROR_INVALID_PARAMETER;
3611 mod = ip_module_id( row->Address.si_family );
3612 if (!mod) return ERROR_INVALID_PARAMETER;
3614 if (!row->InterfaceLuid.Value)
3616 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
3617 if (err) return err;
3620 if (row->Address.si_family == AF_INET)
3622 key4.luid = row->InterfaceLuid;
3623 key4.addr = row->Address.Ipv4.sin_addr;
3624 key4.pad = 0;
3625 key = &key4;
3626 key_size = sizeof(key4);
3628 else if (row->Address.si_family == AF_INET6)
3630 key6.luid = row->InterfaceLuid;
3631 key6.addr = row->Address.Ipv6.sin6_addr;
3632 key = &key6;
3633 key_size = sizeof(key6);
3635 else return ERROR_INVALID_PARAMETER;
3637 err = NsiGetAllParameters( 1, mod, NSI_IP_UNICAST_TABLE, key, key_size, &rw, sizeof(rw),
3638 &dyn, sizeof(dyn), &stat, sizeof(stat) );
3639 if (!err) unicast_row_fill( row, row->Address.si_family, key, &rw, &dyn, &stat );
3640 return err;
3643 DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY family, MIB_UNICASTIPADDRESS_TABLE **table)
3645 void *key[2] = { NULL, NULL };
3646 struct nsi_ip_unicast_rw *rw[2] = { NULL, NULL };
3647 struct nsi_ip_unicast_dynamic *dyn[2] = { NULL, NULL };
3648 struct nsi_ip_unicast_static *stat[2] = { NULL, NULL };
3649 static const USHORT fam[2] = { AF_INET, AF_INET6 };
3650 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ipv6_unicast_key) };
3651 DWORD err, i, size, count[2] = { 0, 0 };
3653 TRACE( "%u, %p\n", family, table );
3655 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
3656 return ERROR_INVALID_PARAMETER;
3658 for (i = 0; i < 2; i++)
3660 if (family != AF_UNSPEC && family != fam[i]) continue;
3662 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_UNICAST_TABLE, key + i, key_size[i],
3663 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
3664 (void **)stat + i, sizeof(**stat), count + i, 0 );
3665 if (err) goto err;
3668 size = FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE, Table[ count[0] + count[1] ]);
3669 *table = heap_alloc( size );
3670 if (!*table)
3672 err = ERROR_NOT_ENOUGH_MEMORY;
3673 goto err;
3676 (*table)->NumEntries = count[0] + count[1];
3677 for (i = 0; i < count[0]; i++)
3679 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + i;
3680 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key[0];
3682 unicast_row_fill( row, fam[0], (void *)(key4 + i), rw[0] + i, dyn[0] + i, stat[0] + i );
3685 for (i = 0; i < count[1]; i++)
3687 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + count[0] + i;
3688 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key[1];
3690 unicast_row_fill( row, fam[1], (void *)(key6 + i), rw[1] + i, dyn[1] + i, stat[1] + i );
3693 err:
3694 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
3695 return err;
3698 /******************************************************************
3699 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3701 * This is a Win98-only function to get information on "unidirectional"
3702 * adapters. Since this is pretty nonsensical in other contexts, it
3703 * never returns anything.
3705 * PARAMS
3706 * pIPIfInfo [Out] buffer for adapter infos
3707 * dwOutBufLen [Out] length of the output buffer
3709 * RETURNS
3710 * Success: NO_ERROR
3711 * Failure: error code from winerror.h
3713 * FIXME
3714 * Stub, returns ERROR_NOT_SUPPORTED.
3716 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
3718 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
3719 /* a unidirectional adapter?? not bloody likely! */
3720 return ERROR_NOT_SUPPORTED;
3724 /******************************************************************
3725 * IpReleaseAddress (IPHLPAPI.@)
3727 * Release an IP obtained through DHCP,
3729 * PARAMS
3730 * AdapterInfo [In] adapter to release IP address
3732 * RETURNS
3733 * Success: NO_ERROR
3734 * Failure: error code from winerror.h
3736 * NOTES
3737 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3738 * this function does nothing.
3740 * FIXME
3741 * Stub, returns ERROR_NOT_SUPPORTED.
3743 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3745 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3746 return ERROR_NOT_SUPPORTED;
3750 /******************************************************************
3751 * IpRenewAddress (IPHLPAPI.@)
3753 * Renew an IP obtained through DHCP.
3755 * PARAMS
3756 * AdapterInfo [In] adapter to renew IP address
3758 * RETURNS
3759 * Success: NO_ERROR
3760 * Failure: error code from winerror.h
3762 * NOTES
3763 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3764 * this function does nothing.
3766 * FIXME
3767 * Stub, returns ERROR_NOT_SUPPORTED.
3769 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3771 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3772 return ERROR_NOT_SUPPORTED;
3776 /******************************************************************
3777 * NotifyAddrChange (IPHLPAPI.@)
3779 * Notify caller whenever the ip-interface map is changed.
3781 * PARAMS
3782 * Handle [Out] handle usable in asynchronous notification
3783 * overlapped [In] overlapped structure that notifies the caller
3785 * RETURNS
3786 * Success: NO_ERROR
3787 * Failure: error code from winerror.h
3789 * FIXME
3790 * Stub, returns ERROR_NOT_SUPPORTED.
3792 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3794 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3795 if (Handle) *Handle = INVALID_HANDLE_VALUE;
3796 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
3797 return ERROR_IO_PENDING;
3801 /******************************************************************
3802 * NotifyIpInterfaceChange (IPHLPAPI.@)
3804 DWORD WINAPI NotifyIpInterfaceChange(ADDRESS_FAMILY family, PIPINTERFACE_CHANGE_CALLBACK callback,
3805 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3807 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3808 family, callback, context, init_notify, handle);
3809 if (handle) *handle = NULL;
3810 return NO_ERROR;
3813 /******************************************************************
3814 * NotifyRouteChange2 (IPHLPAPI.@)
3816 DWORD WINAPI NotifyRouteChange2(ADDRESS_FAMILY family, PIPFORWARD_CHANGE_CALLBACK callback, VOID* context,
3817 BOOLEAN init_notify, HANDLE* handle)
3819 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3820 family, callback, context, init_notify, handle);
3821 if (handle) *handle = NULL;
3822 return NO_ERROR;
3826 /******************************************************************
3827 * NotifyRouteChange (IPHLPAPI.@)
3829 * Notify caller whenever the ip routing table is changed.
3831 * PARAMS
3832 * Handle [Out] handle usable in asynchronous notification
3833 * overlapped [In] overlapped structure that notifies the caller
3835 * RETURNS
3836 * Success: NO_ERROR
3837 * Failure: error code from winerror.h
3839 * FIXME
3840 * Stub, returns ERROR_NOT_SUPPORTED.
3842 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3844 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3845 return ERROR_NOT_SUPPORTED;
3849 /******************************************************************
3850 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3852 DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback,
3853 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3855 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3856 family, callback, context, init_notify, handle);
3857 if (handle) *handle = NULL;
3859 if (init_notify)
3860 callback(context, NULL, MibInitialNotification);
3862 return NO_ERROR;
3865 /******************************************************************
3866 * SendARP (IPHLPAPI.@)
3868 * Send an ARP request.
3870 * PARAMS
3871 * DestIP [In] attempt to obtain this IP
3872 * SrcIP [In] optional sender IP address
3873 * pMacAddr [Out] buffer for the mac address
3874 * PhyAddrLen [In/Out] length of the output buffer
3876 * RETURNS
3877 * Success: NO_ERROR
3878 * Failure: error code from winerror.h
3880 * FIXME
3881 * Stub, returns ERROR_NOT_SUPPORTED.
3883 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
3885 FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
3886 DestIP, SrcIP, pMacAddr, PhyAddrLen);
3887 return ERROR_NOT_SUPPORTED;
3891 /******************************************************************
3892 * SetIfEntry (IPHLPAPI.@)
3894 * Set the administrative status of an interface.
3896 * PARAMS
3897 * pIfRow [In] dwAdminStatus member specifies the new status.
3899 * RETURNS
3900 * Success: NO_ERROR
3901 * Failure: error code from winerror.h
3903 * FIXME
3904 * Stub, returns ERROR_NOT_SUPPORTED.
3906 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
3908 FIXME("(pIfRow %p): stub\n", pIfRow);
3909 /* this is supposed to set an interface administratively up or down.
3910 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3911 this sort of down is indistinguishable from other sorts of down (e.g. no
3912 link). */
3913 return ERROR_NOT_SUPPORTED;
3917 /******************************************************************
3918 * SetIpForwardEntry (IPHLPAPI.@)
3920 * Modify an existing route.
3922 * PARAMS
3923 * pRoute [In] route with the new information
3925 * RETURNS
3926 * Success: NO_ERROR
3927 * Failure: error code from winerror.h
3929 * FIXME
3930 * Stub, returns NO_ERROR.
3932 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
3934 FIXME("(pRoute %p): stub\n", pRoute);
3935 /* this is to add a route entry, how's it distinguishable from
3936 CreateIpForwardEntry?
3937 could use SIOCADDRT, not sure I want to */
3938 return 0;
3942 /******************************************************************
3943 * SetIpNetEntry (IPHLPAPI.@)
3945 * Modify an existing ARP entry.
3947 * PARAMS
3948 * pArpEntry [In] ARP entry with the new information
3950 * RETURNS
3951 * Success: NO_ERROR
3952 * Failure: error code from winerror.h
3954 * FIXME
3955 * Stub, returns NO_ERROR.
3957 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3959 FIXME("(pArpEntry %p): stub\n", pArpEntry);
3960 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3961 return 0;
3965 /******************************************************************
3966 * SetIpStatistics (IPHLPAPI.@)
3968 * Toggle IP forwarding and det the default TTL value.
3970 * PARAMS
3971 * pIpStats [In] IP statistics with the new information
3973 * RETURNS
3974 * Success: NO_ERROR
3975 * Failure: error code from winerror.h
3977 * FIXME
3978 * Stub, returns NO_ERROR.
3980 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3982 FIXME("(pIpStats %p): stub\n", pIpStats);
3983 return 0;
3987 /******************************************************************
3988 * SetIpTTL (IPHLPAPI.@)
3990 * Set the default TTL value.
3992 * PARAMS
3993 * nTTL [In] new TTL value
3995 * RETURNS
3996 * Success: NO_ERROR
3997 * Failure: error code from winerror.h
3999 * FIXME
4000 * Stub, returns NO_ERROR.
4002 DWORD WINAPI SetIpTTL(UINT nTTL)
4004 FIXME("(nTTL %d): stub\n", nTTL);
4005 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
4006 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
4007 return 0;
4011 /******************************************************************
4012 * SetTcpEntry (IPHLPAPI.@)
4014 * Set the state of a TCP connection.
4016 * PARAMS
4017 * pTcpRow [In] specifies connection with new state
4019 * RETURNS
4020 * Success: NO_ERROR
4021 * Failure: error code from winerror.h
4023 * FIXME
4024 * Stub, returns NO_ERROR.
4026 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
4028 FIXME("(pTcpRow %p): stub\n", pTcpRow);
4029 return 0;
4032 /******************************************************************
4033 * SetPerTcpConnectionEStats (IPHLPAPI.@)
4035 DWORD WINAPI SetPerTcpConnectionEStats(PMIB_TCPROW row, TCP_ESTATS_TYPE state, PBYTE rw,
4036 ULONG version, ULONG size, ULONG offset)
4038 FIXME("(row %p, state %d, rw %p, version %lu, size %lu, offset %lu): stub\n",
4039 row, state, rw, version, size, offset);
4040 return ERROR_NOT_SUPPORTED;
4044 /******************************************************************
4045 * UnenableRouter (IPHLPAPI.@)
4047 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
4048 * if it reaches zero.
4050 * PARAMS
4051 * pOverlapped [In/Out] should be the same as in EnableRouter()
4052 * lpdwEnableCount [Out] optional, receives reference count
4054 * RETURNS
4055 * Success: NO_ERROR
4056 * Failure: error code from winerror.h
4058 * FIXME
4059 * Stub, returns ERROR_NOT_SUPPORTED.
4061 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
4063 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
4064 lpdwEnableCount);
4065 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
4066 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
4068 return ERROR_NOT_SUPPORTED;
4071 /******************************************************************
4072 * PfCreateInterface (IPHLPAPI.@)
4074 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
4075 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
4077 FIXME("(%ld %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
4078 return ERROR_CALL_NOT_IMPLEMENTED;
4081 /******************************************************************
4082 * PfUnBindInterface (IPHLPAPI.@)
4084 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
4086 FIXME("(%p) stub\n", interface);
4087 return ERROR_CALL_NOT_IMPLEMENTED;
4090 /******************************************************************
4091 * PfDeleteInterface(IPHLPAPI.@)
4093 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
4095 FIXME("(%p) stub\n", interface);
4096 return ERROR_CALL_NOT_IMPLEMENTED;
4099 /******************************************************************
4100 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
4102 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
4104 FIXME("(%p %d %p) stub\n", interface, type, ip);
4105 return ERROR_CALL_NOT_IMPLEMENTED;
4108 /******************************************************************
4109 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
4111 DWORD WINAPI ConvertInterfaceAliasToLuid( const WCHAR *alias, NET_LUID *luid )
4113 struct nsi_ndis_ifinfo_rw *data;
4114 DWORD err, count, i, len;
4115 NET_LUID *keys;
4117 TRACE( "(%s %p)\n", debugstr_w(alias), luid );
4119 if (!alias || !*alias || !luid) return ERROR_INVALID_PARAMETER;
4120 luid->Value = 0;
4121 len = wcslen( alias );
4123 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
4124 (void **)&data, sizeof(*data), NULL, 0, NULL, 0, &count, 0 );
4125 if (err) return err;
4127 err = ERROR_INVALID_PARAMETER;
4128 for (i = 0; i < count; i++)
4130 if (data[i].alias.Length == len * 2 && !memcmp( data[i].alias.String, alias, len * 2 ))
4132 luid->Value = keys[i].Value;
4133 err = ERROR_SUCCESS;
4134 break;
4137 NsiFreeTable( keys, data, NULL, NULL );
4138 return err;
4141 /******************************************************************
4142 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
4144 DWORD WINAPI ConvertInterfaceGuidToLuid(const GUID *guid, NET_LUID *luid)
4146 struct nsi_ndis_ifinfo_static *data;
4147 DWORD err, count, i;
4148 NET_LUID *keys;
4150 TRACE( "(%s %p)\n", debugstr_guid(guid), luid );
4152 if (!guid || !luid) return ERROR_INVALID_PARAMETER;
4153 luid->Value = 0;
4155 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
4156 NULL, 0, NULL, 0, (void **)&data, sizeof(*data), &count, 0 );
4157 if (err) return err;
4159 err = ERROR_INVALID_PARAMETER;
4160 for (i = 0; i < count; i++)
4162 if (IsEqualGUID( &data[i].if_guid, guid ))
4164 luid->Value = keys[i].Value;
4165 err = ERROR_SUCCESS;
4166 break;
4169 NsiFreeTable( keys, NULL, NULL, data );
4170 return err;
4173 /******************************************************************
4174 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
4176 DWORD WINAPI ConvertInterfaceIndexToLuid(NET_IFINDEX index, NET_LUID *luid)
4178 DWORD err;
4180 TRACE( "(%lu %p)\n", index, luid );
4182 if (!luid) return ERROR_INVALID_PARAMETER;
4184 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &index, sizeof(index),
4185 NSI_PARAM_TYPE_STATIC, luid, sizeof(*luid), 0 );
4186 if (err) luid->Value = 0;
4187 return err;
4190 /******************************************************************
4191 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4193 DWORD WINAPI ConvertInterfaceLuidToAlias( const NET_LUID *luid, WCHAR *alias, SIZE_T len )
4195 DWORD err;
4196 IF_COUNTED_STRING name;
4198 TRACE( "(%p %p %Iu)\n", luid, alias, len );
4200 if (!luid || !alias) return ERROR_INVALID_PARAMETER;
4202 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4203 NSI_PARAM_TYPE_RW, &name, sizeof(name),
4204 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw, alias) );
4205 if (err) return err;
4207 if (len <= name.Length / sizeof(WCHAR)) return ERROR_NOT_ENOUGH_MEMORY;
4208 memcpy( alias, name.String, name.Length );
4209 alias[name.Length / sizeof(WCHAR)] = '\0';
4211 return err;
4214 /******************************************************************
4215 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4217 DWORD WINAPI ConvertInterfaceLuidToGuid(const NET_LUID *luid, GUID *guid)
4219 DWORD err;
4221 TRACE( "(%p %p)\n", luid, guid );
4223 if (!luid || !guid) return ERROR_INVALID_PARAMETER;
4225 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4226 NSI_PARAM_TYPE_STATIC, guid, sizeof(*guid),
4227 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_guid) );
4228 if (err) memset( guid, 0, sizeof(*guid) );
4229 return err;
4232 /******************************************************************
4233 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4235 DWORD WINAPI ConvertInterfaceLuidToIndex(const NET_LUID *luid, NET_IFINDEX *index)
4237 DWORD err;
4239 TRACE( "(%p %p)\n", luid, index );
4241 if (!luid || !index) return ERROR_INVALID_PARAMETER;
4243 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4244 NSI_PARAM_TYPE_STATIC, index, sizeof(*index),
4245 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index) );
4246 if (err) *index = 0;
4247 return err;
4250 /******************************************************************
4251 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4253 DWORD WINAPI ConvertInterfaceLuidToNameA(const NET_LUID *luid, char *name, SIZE_T len)
4255 DWORD err;
4256 WCHAR nameW[IF_MAX_STRING_SIZE + 1];
4258 TRACE( "(%p %p %Iu)\n", luid, name, len );
4260 if (!luid) return ERROR_INVALID_PARAMETER;
4261 if (!name || !len) return ERROR_NOT_ENOUGH_MEMORY;
4263 err = ConvertInterfaceLuidToNameW( luid, nameW, ARRAY_SIZE(nameW) );
4264 if (err) return err;
4266 if (!WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, len, NULL, NULL ))
4267 err = GetLastError();
4268 return err;
4271 struct name_prefix
4273 const WCHAR *prefix;
4274 DWORD type;
4276 static const struct name_prefix name_prefixes[] =
4278 { L"other", IF_TYPE_OTHER },
4279 { L"ethernet", IF_TYPE_ETHERNET_CSMACD },
4280 { L"tokenring", IF_TYPE_ISO88025_TOKENRING },
4281 { L"ppp", IF_TYPE_PPP },
4282 { L"loopback", IF_TYPE_SOFTWARE_LOOPBACK },
4283 { L"atm", IF_TYPE_ATM },
4284 { L"wireless", IF_TYPE_IEEE80211 },
4285 { L"tunnel", IF_TYPE_TUNNEL },
4286 { L"ieee1394", IF_TYPE_IEEE1394 }
4289 /******************************************************************
4290 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4292 DWORD WINAPI ConvertInterfaceLuidToNameW(const NET_LUID *luid, WCHAR *name, SIZE_T len)
4294 DWORD i, needed;
4295 const WCHAR *prefix = NULL;
4296 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4298 TRACE( "(%p %p %Iu)\n", luid, name, len );
4300 if (!luid || !name) return ERROR_INVALID_PARAMETER;
4302 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4304 if (luid->Info.IfType == name_prefixes[i].type)
4306 prefix = name_prefixes[i].prefix;
4307 break;
4311 if (prefix) needed = swprintf( buf, len, L"%s_%d", prefix, luid->Info.NetLuidIndex );
4312 else needed = swprintf( buf, len, L"iftype%d_%d", luid->Info.IfType, luid->Info.NetLuidIndex );
4314 if (needed >= len) return ERROR_NOT_ENOUGH_MEMORY;
4315 memcpy( name, buf, (needed + 1) * sizeof(WCHAR) );
4316 return ERROR_SUCCESS;
4319 /******************************************************************
4320 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4322 DWORD WINAPI ConvertInterfaceNameToLuidA(const char *name, NET_LUID *luid)
4324 WCHAR nameW[IF_MAX_STRING_SIZE];
4326 TRACE( "(%s %p)\n", debugstr_a(name), luid );
4328 if (!name) return ERROR_INVALID_NAME;
4329 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW) ))
4330 return GetLastError();
4332 return ConvertInterfaceNameToLuidW( nameW, luid );
4335 /******************************************************************
4336 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4338 DWORD WINAPI ConvertInterfaceNameToLuidW(const WCHAR *name, NET_LUID *luid)
4340 const WCHAR *sep;
4341 DWORD type = ~0u, i;
4342 int iftype_len = wcslen( L"iftype" );
4343 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4345 TRACE( "(%s %p)\n", debugstr_w(name), luid );
4347 if (!luid) return ERROR_INVALID_PARAMETER;
4348 memset( luid, 0, sizeof(*luid) );
4350 if (!name || !(sep = wcschr( name, '_' )) || sep >= name + ARRAY_SIZE(buf)) return ERROR_INVALID_NAME;
4351 memcpy( buf, name, (sep - name) * sizeof(WCHAR) );
4352 buf[sep - name] = '\0';
4354 if (sep - name > iftype_len && !memcmp( buf, L"iftype", iftype_len * sizeof(WCHAR) ))
4356 type = wcstol( buf + iftype_len, NULL, 10 );
4358 else
4360 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4362 if (!wcscmp( buf, name_prefixes[i].prefix ))
4364 type = name_prefixes[i].type;
4365 break;
4369 if (type == ~0u) return ERROR_INVALID_NAME;
4371 luid->Info.NetLuidIndex = wcstol( sep + 1, NULL, 10 );
4372 luid->Info.IfType = type;
4373 return ERROR_SUCCESS;
4376 /******************************************************************
4377 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4379 DWORD WINAPI ConvertLengthToIpv4Mask(ULONG mask_len, ULONG *mask)
4381 if (mask_len > 32)
4383 *mask = INADDR_NONE;
4384 return ERROR_INVALID_PARAMETER;
4387 if (mask_len == 0)
4388 *mask = 0;
4389 else
4390 *mask = htonl(~0u << (32 - mask_len));
4392 return NO_ERROR;
4395 /******************************************************************
4396 * if_nametoindex (IPHLPAPI.@)
4398 IF_INDEX WINAPI IPHLP_if_nametoindex(const char *name)
4400 IF_INDEX index;
4401 NET_LUID luid;
4402 DWORD err;
4404 TRACE( "(%s)\n", name );
4406 err = ConvertInterfaceNameToLuidA( name, &luid );
4407 if (err) return 0;
4409 err = ConvertInterfaceLuidToIndex( &luid, &index );
4410 if (err) index = 0;
4411 return index;
4414 /******************************************************************
4415 * if_indextoname (IPHLPAPI.@)
4417 char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
4419 NET_LUID luid;
4420 DWORD err;
4422 TRACE( "(%lu, %p)\n", index, name );
4424 err = ConvertInterfaceIndexToLuid( index, &luid );
4425 if (err) return NULL;
4427 err = ConvertInterfaceLuidToNameA( &luid, name, IF_MAX_STRING_SIZE );
4428 if (err) return NULL;
4429 return name;
4432 /******************************************************************
4433 * GetIpInterfaceTable (IPHLPAPI.@)
4435 DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table)
4437 FIXME("(%u %p): stub\n", family, table);
4438 return ERROR_NOT_SUPPORTED;
4441 /******************************************************************
4442 * GetBestRoute2 (IPHLPAPI.@)
4444 DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
4445 const SOCKADDR_INET *source, const SOCKADDR_INET *destination,
4446 ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
4447 SOCKADDR_INET *bestaddress)
4449 static int once;
4451 if (!once++)
4452 FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid, index, source,
4453 destination, options, bestroute, bestaddress);
4455 if (!destination || !bestroute || !bestaddress)
4456 return ERROR_INVALID_PARAMETER;
4458 return ERROR_NOT_SUPPORTED;
4461 /******************************************************************
4462 * ParseNetworkString (IPHLPAPI.@)
4464 DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
4465 NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len)
4467 IN_ADDR temp_addr4;
4468 IN6_ADDR temp_addr6;
4469 ULONG temp_scope;
4470 USHORT temp_port = 0;
4471 NTSTATUS status;
4473 TRACE("(%s, %ld, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len);
4475 if (!str)
4476 return ERROR_INVALID_PARAMETER;
4478 if (type & NET_STRING_IPV4_ADDRESS)
4480 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4481 if (SUCCEEDED(status) && !temp_port)
4483 if (info)
4485 info->Format = NET_ADDRESS_IPV4;
4486 info->Ipv4Address.sin_addr = temp_addr4;
4487 info->Ipv4Address.sin_port = 0;
4489 if (port) *port = 0;
4490 if (prefix_len) *prefix_len = 255;
4491 return ERROR_SUCCESS;
4494 if (type & NET_STRING_IPV4_SERVICE)
4496 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4497 if (SUCCEEDED(status) && temp_port)
4499 if (info)
4501 info->Format = NET_ADDRESS_IPV4;
4502 info->Ipv4Address.sin_addr = temp_addr4;
4503 info->Ipv4Address.sin_port = temp_port;
4505 if (port) *port = ntohs(temp_port);
4506 if (prefix_len) *prefix_len = 255;
4507 return ERROR_SUCCESS;
4510 if (type & NET_STRING_IPV6_ADDRESS)
4512 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4513 if (SUCCEEDED(status) && !temp_port)
4515 if (info)
4517 info->Format = NET_ADDRESS_IPV6;
4518 info->Ipv6Address.sin6_addr = temp_addr6;
4519 info->Ipv6Address.sin6_scope_id = temp_scope;
4520 info->Ipv6Address.sin6_port = 0;
4522 if (port) *port = 0;
4523 if (prefix_len) *prefix_len = 255;
4524 return ERROR_SUCCESS;
4527 if (type & NET_STRING_IPV6_SERVICE)
4529 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4530 if (SUCCEEDED(status) && temp_port)
4532 if (info)
4534 info->Format = NET_ADDRESS_IPV6;
4535 info->Ipv6Address.sin6_addr = temp_addr6;
4536 info->Ipv6Address.sin6_scope_id = temp_scope;
4537 info->Ipv6Address.sin6_port = temp_port;
4539 if (port) *port = ntohs(temp_port);
4540 if (prefix_len) *prefix_len = 255;
4541 return ERROR_SUCCESS;
4545 if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED;
4547 if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_ADDRESS|NET_STRING_IPV6_SERVICE))
4549 FIXME("Unimplemented type 0x%lx\n", type);
4550 return ERROR_NOT_SUPPORTED;
4553 return ERROR_INVALID_PARAMETER;
4556 struct icmp_handle_data
4558 HANDLE nsi_device;
4561 /***********************************************************************
4562 * IcmpCloseHandle (IPHLPAPI.@)
4564 BOOL WINAPI IcmpCloseHandle( HANDLE handle )
4566 struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
4568 CloseHandle( data->nsi_device );
4569 heap_free( data );
4570 return TRUE;
4573 /***********************************************************************
4574 * IcmpCreateFile (IPHLPAPI.@)
4576 HANDLE WINAPI IcmpCreateFile( void )
4578 struct icmp_handle_data *data = heap_alloc( sizeof(*data) );
4580 if (!data)
4582 SetLastError( IP_NO_RESOURCES );
4583 return INVALID_HANDLE_VALUE;
4586 data->nsi_device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
4587 FILE_FLAG_OVERLAPPED, NULL );
4588 if (data->nsi_device == INVALID_HANDLE_VALUE)
4590 heap_free( data );
4591 return INVALID_HANDLE_VALUE;
4594 return (HANDLE)data;
4597 /******************************************************************
4598 * IcmpParseReplies (IPHLPAPI.@)
4600 DWORD WINAPI IcmpParseReplies( void *reply, DWORD reply_size )
4602 ICMP_ECHO_REPLY *icmp_reply = reply;
4603 DWORD num_pkts = icmp_reply->Reserved;
4605 icmp_reply->Reserved = 0;
4606 if (!num_pkts) SetLastError( icmp_reply->Status );
4607 return num_pkts;
4610 /***********************************************************************
4611 * IcmpSendEcho (IPHLPAPI.@)
4613 DWORD WINAPI IcmpSendEcho( HANDLE handle, IPAddr dst, void *request, WORD request_size,
4614 IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size,
4615 DWORD timeout )
4617 return IcmpSendEcho2Ex( handle, NULL, NULL, NULL, INADDR_ANY, dst, request, request_size,
4618 opts, reply, reply_size, timeout );
4621 /***********************************************************************
4622 * IcmpSendEcho2 (IPHLPAPI.@)
4624 DWORD WINAPI IcmpSendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4625 IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
4626 void *reply, DWORD reply_size, DWORD timeout )
4628 return IcmpSendEcho2Ex( handle, event, apc_routine, apc_ctxt, INADDR_ANY, dst, request, request_size,
4629 opts, reply, reply_size, timeout );
4632 struct icmp_apc_ctxt
4634 void *apc_ctxt;
4635 PIO_APC_ROUTINE apc_routine;
4636 IO_STATUS_BLOCK iosb;
4639 void WINAPI icmp_apc_routine( void *context, IO_STATUS_BLOCK *iosb, ULONG reserved )
4641 struct icmp_apc_ctxt *ctxt = context;
4643 ctxt->apc_routine( ctxt->apc_ctxt, iosb, reserved );
4644 heap_free( ctxt );
4647 /***********************************************************************
4648 * IcmpSendEcho2Ex (IPHLPAPI.@)
4650 DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4651 IPAddr src, IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
4652 void *reply, DWORD reply_size, DWORD timeout )
4654 struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
4655 struct icmp_apc_ctxt *ctxt = heap_alloc( sizeof(*ctxt) );
4656 IO_STATUS_BLOCK *iosb = &ctxt->iosb;
4657 DWORD opt_size, in_size, ret = 0;
4658 struct nsiproxy_icmp_echo *in;
4659 HANDLE request_event;
4660 NTSTATUS status;
4662 if (handle == INVALID_HANDLE_VALUE || !reply)
4664 heap_free( ctxt );
4665 SetLastError( ERROR_INVALID_PARAMETER );
4666 return 0;
4669 ctxt->apc_routine = apc_routine;
4670 ctxt->apc_ctxt = apc_ctxt;
4672 opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0;
4673 in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]);
4674 in = heap_alloc_zero( in_size );
4676 if (!in)
4678 heap_free( ctxt );
4679 SetLastError( IP_NO_RESOURCES );
4680 return 0;
4683 in->user_reply_ptr = (ULONG_PTR)reply;
4684 in->bits = sizeof(void*) * 8;
4685 in->src.Ipv4.sin_family = AF_INET;
4686 in->src.Ipv4.sin_addr.s_addr = src;
4687 in->dst.Ipv4.sin_family = AF_INET;
4688 in->dst.Ipv4.sin_addr.s_addr = dst;
4689 if (opts)
4691 in->ttl = opts->Ttl;
4692 in->tos = opts->Tos;
4693 in->flags = opts->Flags;
4694 memcpy( in->data, opts->OptionsData, opts->OptionsSize );
4695 in->opt_size = opts->OptionsSize;
4697 in->req_size = request_size;
4698 in->timeout = timeout;
4699 memcpy( in->data + opt_size, request, request_size );
4701 request_event = event ? event : (apc_routine ? NULL : CreateEventW( NULL, 0, 0, NULL ));
4703 status = NtDeviceIoControlFile( data->nsi_device, request_event, apc_routine ? icmp_apc_routine : NULL,
4704 apc_routine ? ctxt : apc_ctxt, iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO,
4705 in, in_size, reply, reply_size );
4707 if (status == STATUS_PENDING)
4709 if (!event && !apc_routine && !WaitForSingleObject( request_event, INFINITE ))
4710 status = iosb->Status;
4713 if (!status)
4714 ret = IcmpParseReplies( reply, reply_size );
4716 if (!event && request_event) CloseHandle( request_event );
4717 if (!apc_routine || status != STATUS_PENDING) heap_free( ctxt );
4718 heap_free( in );
4720 if (status) SetLastError( RtlNtStatusToDosError( status ) );
4721 return ret;
4724 /***********************************************************************
4725 * Icmp6CreateFile (IPHLPAPI.@)
4727 HANDLE WINAPI Icmp6CreateFile( void )
4729 FIXME( "stub\n" );
4730 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4731 return INVALID_HANDLE_VALUE;
4734 /***********************************************************************
4735 * Icmp6SendEcho2 (IPHLPAPI.@)
4737 DWORD WINAPI Icmp6SendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4738 struct sockaddr_in6 *src, struct sockaddr_in6 *dst, void *request, WORD request_size,
4739 IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size, DWORD timeout )
4741 FIXME( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld): stub\n", handle, event,
4742 apc_routine, apc_ctxt, src, dst, request, request_size, opts, reply, reply_size, timeout );
4743 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4744 return 0;