winecoreaudio: Remove GetAudioSessionWrapper.
[wine.git] / dlls / iphlpapi / iphlpapi_main.c
blobf8ecb89c328597ed7b254bac507f941484100744
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 "ip2string.h"
36 #include "netiodef.h"
37 #include "icmpapi.h"
39 #include "wine/nsi.h"
40 #include "wine/debug.h"
41 #include "wine/heap.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
45 #define CHARS_IN_GUID 39
47 static const WCHAR *device_tcpip = L"\\DEVICE\\TCPIP_";
49 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags );
51 static const NPI_MODULEID *ip_module_id( USHORT family )
53 if (family == AF_INET) return &NPI_MS_IPV4_MODULEID;
54 if (family == AF_INET6) return &NPI_MS_IPV6_MODULEID;
55 return NULL;
58 DWORD WINAPI ConvertGuidToStringA( const GUID *guid, char *str, DWORD len )
60 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
61 sprintf( str, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
62 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
63 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
64 return ERROR_SUCCESS;
67 DWORD WINAPI ConvertGuidToStringW( const GUID *guid, WCHAR *str, DWORD len )
69 if (len < CHARS_IN_GUID) return ERROR_INSUFFICIENT_BUFFER;
70 swprintf( str, len, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
71 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
72 guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
73 return ERROR_SUCCESS;
76 DWORD WINAPI ConvertStringToGuidW( const WCHAR *str, GUID *guid )
78 UNICODE_STRING ustr;
80 RtlInitUnicodeString( &ustr, str );
81 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr, guid ) );
84 static void if_counted_string_copy( WCHAR *dst, unsigned int len, IF_COUNTED_STRING *src )
86 unsigned int copy = src->Length;
88 if (copy >= len * sizeof(WCHAR)) copy = 0;
89 memcpy( dst, src->String, copy );
90 memset( (char *)dst + copy, 0, len * sizeof(WCHAR) - copy );
93 /******************************************************************
94 * AddIPAddress (IPHLPAPI.@)
96 * Add an IP address to an adapter.
98 * PARAMS
99 * Address [In] IP address to add to the adapter
100 * IpMask [In] subnet mask for the IP address
101 * IfIndex [In] adapter index to add the address
102 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
103 * NTEInstance [Out] NTE instance for the IP address
105 * RETURNS
106 * Success: NO_ERROR
107 * Failure: error code from winerror.h
109 * FIXME
110 * Stub. Currently returns ERROR_NOT_SUPPORTED.
112 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
114 FIXME(":stub\n");
115 return ERROR_NOT_SUPPORTED;
118 /******************************************************************
119 * CancelIPChangeNotify (IPHLPAPI.@)
121 * Cancel a previous notification created by NotifyAddrChange or
122 * NotifyRouteChange.
124 * PARAMS
125 * overlapped [In] overlapped structure that notifies the caller
127 * RETURNS
128 * Success: TRUE
129 * Failure: FALSE
131 * FIXME
132 * Stub, returns FALSE.
134 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
136 FIXME("(overlapped %p): stub\n", overlapped);
137 return FALSE;
141 /******************************************************************
142 * CancelMibChangeNotify2 (IPHLPAPI.@)
144 DWORD WINAPI CancelMibChangeNotify2(HANDLE handle)
146 FIXME("(handle %p): stub\n", handle);
147 return NO_ERROR;
151 /******************************************************************
152 * CreateIpForwardEntry (IPHLPAPI.@)
154 * Create a route in the local computer's IP table.
156 * PARAMS
157 * pRoute [In] new route information
159 * RETURNS
160 * Success: NO_ERROR
161 * Failure: error code from winerror.h
163 * FIXME
164 * Stub, always returns NO_ERROR.
166 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
168 FIXME("(pRoute %p): stub\n", pRoute);
169 /* could use SIOCADDRT, not sure I want to */
170 return 0;
174 /******************************************************************
175 * CreateIpNetEntry (IPHLPAPI.@)
177 * Create entry in the ARP table.
179 * PARAMS
180 * pArpEntry [In] new ARP entry
182 * RETURNS
183 * Success: NO_ERROR
184 * Failure: error code from winerror.h
186 * FIXME
187 * Stub, always returns NO_ERROR.
189 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
191 FIXME("(pArpEntry %p)\n", pArpEntry);
192 /* could use SIOCSARP on systems that support it, not sure I want to */
193 return 0;
197 /******************************************************************
198 * CreateProxyArpEntry (IPHLPAPI.@)
200 * Create a Proxy ARP (PARP) entry for an IP address.
202 * PARAMS
203 * dwAddress [In] IP address for which this computer acts as a proxy.
204 * dwMask [In] subnet mask for dwAddress
205 * dwIfIndex [In] interface index
207 * RETURNS
208 * Success: NO_ERROR
209 * Failure: error code from winerror.h
211 * FIXME
212 * Stub, returns ERROR_NOT_SUPPORTED.
214 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
216 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
217 dwAddress, dwMask, dwIfIndex);
218 return ERROR_NOT_SUPPORTED;
221 static char *debugstr_ipv6(const struct sockaddr_in6 *sin, char *buf)
223 const IN6_ADDR *addr = &sin->sin6_addr;
224 char *p = buf;
225 int i;
226 BOOL in_zero = FALSE;
228 for (i = 0; i < 7; i++)
230 if (!addr->u.Word[i])
232 if (i == 0)
233 *p++ = ':';
234 if (!in_zero)
236 *p++ = ':';
237 in_zero = TRUE;
240 else
242 p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
243 in_zero = FALSE;
246 sprintf(p, "%x", ntohs(addr->u.Word[7]));
247 return buf;
250 static BOOL map_address_6to4( const SOCKADDR_IN6 *addr6, SOCKADDR_IN *addr4 )
252 ULONG i;
254 if (addr6->sin6_family != AF_INET6) return FALSE;
256 for (i = 0; i < 5; i++)
257 if (addr6->sin6_addr.u.Word[i]) return FALSE;
259 if (addr6->sin6_addr.u.Word[5] != 0xffff) return FALSE;
261 addr4->sin_family = AF_INET;
262 addr4->sin_port = addr6->sin6_port;
263 addr4->sin_addr.S_un.S_addr = addr6->sin6_addr.u.Word[6] << 16 | addr6->sin6_addr.u.Word[7];
264 memset( &addr4->sin_zero, 0, sizeof(addr4->sin_zero) );
266 return TRUE;
269 static BOOL find_src_address( MIB_IPADDRTABLE *table, const SOCKADDR_IN *dst, SOCKADDR_IN6 *src )
271 MIB_IPFORWARDROW row;
272 DWORD i, j;
274 if (GetBestRoute( dst->sin_addr.S_un.S_addr, 0, &row )) return FALSE;
276 for (i = 0; i < table->dwNumEntries; i++)
278 /* take the first address */
279 if (table->table[i].dwIndex == row.dwForwardIfIndex)
281 src->sin6_family = AF_INET6;
282 src->sin6_port = 0;
283 src->sin6_flowinfo = 0;
284 for (j = 0; j < 5; j++) src->sin6_addr.u.Word[j] = 0;
285 src->sin6_addr.u.Word[5] = 0xffff;
286 src->sin6_addr.u.Word[6] = table->table[i].dwAddr & 0xffff;
287 src->sin6_addr.u.Word[7] = table->table[i].dwAddr >> 16;
288 return TRUE;
292 return FALSE;
295 /******************************************************************
296 * CreateSortedAddressPairs (IPHLPAPI.@)
298 DWORD WINAPI CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list, DWORD src_count,
299 const PSOCKADDR_IN6 dst_list, DWORD dst_count,
300 DWORD options, PSOCKADDR_IN6_PAIR *pair_list,
301 DWORD *pair_count )
303 DWORD i, size, ret;
304 SOCKADDR_IN6_PAIR *pairs;
305 SOCKADDR_IN6 *ptr;
306 SOCKADDR_IN addr4;
307 MIB_IPADDRTABLE *table;
309 FIXME( "(src_list %p src_count %lu dst_list %p dst_count %lu options %lx pair_list %p pair_count %p): stub\n",
310 src_list, src_count, dst_list, dst_count, options, pair_list, pair_count );
312 if (src_list || src_count || !dst_list || !pair_list || !pair_count || dst_count > 500)
313 return ERROR_INVALID_PARAMETER;
315 for (i = 0; i < dst_count; i++)
317 if (!map_address_6to4( &dst_list[i], &addr4 ))
319 FIXME("only mapped IPv4 addresses are supported\n");
320 return ERROR_NOT_SUPPORTED;
324 size = dst_count * sizeof(*pairs);
325 size += dst_count * sizeof(SOCKADDR_IN6) * 2; /* source address + destination address */
326 if (!(pairs = HeapAlloc( GetProcessHeap(), 0, size ))) return ERROR_NOT_ENOUGH_MEMORY;
327 ptr = (SOCKADDR_IN6 *)&pairs[dst_count];
329 if ((ret = AllocateAndGetIpAddrTableFromStack( &table, FALSE, GetProcessHeap(), 0 )))
331 HeapFree( GetProcessHeap(), 0, pairs );
332 return ret;
335 for (i = 0; i < dst_count; i++)
337 pairs[i].SourceAddress = ptr++;
338 if (!map_address_6to4( &dst_list[i], &addr4 ) ||
339 !find_src_address( table, &addr4, pairs[i].SourceAddress ))
341 char buf[46];
342 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list[i], buf) );
343 memset( pairs[i].SourceAddress, 0, sizeof(*pairs[i].SourceAddress) );
344 pairs[i].SourceAddress->sin6_family = AF_INET6;
347 pairs[i].DestinationAddress = ptr++;
348 memcpy( pairs[i].DestinationAddress, &dst_list[i], sizeof(*pairs[i].DestinationAddress) );
350 *pair_list = pairs;
351 *pair_count = dst_count;
353 HeapFree( GetProcessHeap(), 0, table );
354 return NO_ERROR;
358 /******************************************************************
359 * DeleteIPAddress (IPHLPAPI.@)
361 * Delete an IP address added with AddIPAddress().
363 * PARAMS
364 * NTEContext [In] NTE context from AddIPAddress();
366 * RETURNS
367 * Success: NO_ERROR
368 * Failure: error code from winerror.h
370 * FIXME
371 * Stub, returns ERROR_NOT_SUPPORTED.
373 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
375 FIXME("(NTEContext %ld): stub\n", NTEContext);
376 return ERROR_NOT_SUPPORTED;
380 /******************************************************************
381 * DeleteIpForwardEntry (IPHLPAPI.@)
383 * Delete a route.
385 * PARAMS
386 * pRoute [In] route to delete
388 * RETURNS
389 * Success: NO_ERROR
390 * Failure: error code from winerror.h
392 * FIXME
393 * Stub, returns NO_ERROR.
395 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
397 FIXME("(pRoute %p): stub\n", pRoute);
398 /* could use SIOCDELRT, not sure I want to */
399 return 0;
403 /******************************************************************
404 * DeleteIpNetEntry (IPHLPAPI.@)
406 * Delete an ARP entry.
408 * PARAMS
409 * pArpEntry [In] ARP entry to delete
411 * RETURNS
412 * Success: NO_ERROR
413 * Failure: error code from winerror.h
415 * FIXME
416 * Stub, returns NO_ERROR.
418 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
420 FIXME("(pArpEntry %p): stub\n", pArpEntry);
421 /* could use SIOCDARP on systems that support it, not sure I want to */
422 return 0;
426 /******************************************************************
427 * DeleteProxyArpEntry (IPHLPAPI.@)
429 * Delete a Proxy ARP entry.
431 * PARAMS
432 * dwAddress [In] IP address for which this computer acts as a proxy.
433 * dwMask [In] subnet mask for dwAddress
434 * dwIfIndex [In] interface index
436 * RETURNS
437 * Success: NO_ERROR
438 * Failure: error code from winerror.h
440 * FIXME
441 * Stub, returns ERROR_NOT_SUPPORTED.
443 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
445 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
446 dwAddress, dwMask, dwIfIndex);
447 return ERROR_NOT_SUPPORTED;
451 /******************************************************************
452 * EnableRouter (IPHLPAPI.@)
454 * Turn on ip forwarding.
456 * PARAMS
457 * pHandle [In/Out]
458 * pOverlapped [In/Out] hEvent member should contain a valid handle.
460 * RETURNS
461 * Success: ERROR_IO_PENDING
462 * Failure: error code from winerror.h
464 * FIXME
465 * Stub, returns ERROR_NOT_SUPPORTED.
467 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
469 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
470 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
471 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
473 return ERROR_NOT_SUPPORTED;
477 /******************************************************************
478 * FlushIpNetTable (IPHLPAPI.@)
480 * Delete all ARP entries of an interface
482 * PARAMS
483 * dwIfIndex [In] interface index
485 * RETURNS
486 * Success: NO_ERROR
487 * Failure: error code from winerror.h
489 * FIXME
490 * Stub, returns ERROR_NOT_SUPPORTED.
492 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
494 FIXME("(dwIfIndex 0x%08lx): stub\n", dwIfIndex);
495 /* this flushes the arp cache of the given index */
496 return ERROR_NOT_SUPPORTED;
499 /******************************************************************
500 * FreeMibTable (IPHLPAPI.@)
502 * Free buffer allocated by network functions
504 * PARAMS
505 * ptr [In] pointer to the buffer to free
508 void WINAPI FreeMibTable( void *ptr )
510 TRACE( "(%p)\n", ptr );
511 heap_free( ptr );
514 /******************************************************************
515 * GetAdapterIndex (IPHLPAPI.@)
517 * Get interface index from its name.
519 * PARAMS
520 * adapter_name [In] unicode string with the adapter name
521 * index [Out] returns found interface index
523 DWORD WINAPI GetAdapterIndex( WCHAR *adapter_name, ULONG *index )
525 NET_LUID luid;
526 GUID guid;
527 DWORD err;
529 TRACE( "name %s, index %p\n", debugstr_w( adapter_name ), index );
531 if (wcslen( adapter_name ) < wcslen( device_tcpip )) return ERROR_INVALID_PARAMETER;
532 err = ConvertStringToGuidW( adapter_name + wcslen( device_tcpip ), &guid );
533 if (err) return err;
534 err = ConvertInterfaceGuidToLuid( &guid, &luid );
535 if (err) return err;
536 return ConvertInterfaceLuidToIndex( &luid, index );
539 static DWORD get_wins_servers( SOCKADDR_INET **servers )
541 HKEY key;
542 char buf[4 * 4];
543 DWORD size, i, count = 0;
544 static const char *values[] = { "WinsServer", "BackupWinsServer" };
545 IN_ADDR addrs[ARRAY_SIZE(values)];
547 *servers = NULL;
548 /* @@ Wine registry key: HKCU\Software\Wine\Network */
549 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Network", &key )) return 0;
551 for (i = 0; i < ARRAY_SIZE(values); i++)
553 size = sizeof(buf);
554 if (!RegQueryValueExA( key, values[i], NULL, NULL, (LPBYTE)buf, &size ))
555 if (!RtlIpv4StringToAddressA( buf, TRUE, NULL, addrs + count ) &&
556 addrs[count].s_addr != INADDR_NONE && addrs[count].s_addr != INADDR_ANY)
557 count++;
559 RegCloseKey( key );
561 if (count)
563 *servers = heap_alloc_zero( count * sizeof(**servers) );
564 if (!*servers) return 0;
565 for (i = 0; i < count; i++)
567 (*servers)[i].Ipv4.sin_family = AF_INET;
568 (*servers)[i].Ipv4.sin_addr = addrs[i];
571 return count;
574 static void ip_addr_string_init( IP_ADDR_STRING *s, const IN_ADDR *addr, const IN_ADDR *mask, DWORD ctxt )
576 s->Next = NULL;
578 if (addr) RtlIpv4AddressToStringA( addr, s->IpAddress.String );
579 else s->IpAddress.String[0] = '\0';
580 if (mask) RtlIpv4AddressToStringA( mask, s->IpMask.String );
581 else s->IpMask.String[0] = '\0';
582 s->Context = ctxt;
585 /******************************************************************
586 * GetAdaptersInfo (IPHLPAPI.@)
588 * Get information about adapters.
590 * PARAMS
591 * info [Out] buffer for adapter infos
592 * size [In] length of output buffer
594 DWORD WINAPI GetAdaptersInfo( IP_ADAPTER_INFO *info, ULONG *size )
596 DWORD err, if_count, if_num = 0, uni_count, fwd_count, needed, wins_server_count;
597 DWORD len, i, uni, fwd;
598 NET_LUID *if_keys = NULL;
599 struct nsi_ndis_ifinfo_rw *if_rw = NULL;
600 struct nsi_ndis_ifinfo_static *if_stat = NULL;
601 struct nsi_ipv4_unicast_key *uni_keys = NULL;
602 struct nsi_ip_unicast_rw *uni_rw = NULL;
603 struct nsi_ipv4_forward_key *fwd_keys = NULL;
604 SOCKADDR_INET *wins_servers = NULL;
605 IP_ADDR_STRING *extra_ip_addrs, *cursor;
606 IN_ADDR gw, mask;
608 TRACE( "info %p, size %p\n", info, size );
609 if (!size) return ERROR_INVALID_PARAMETER;
611 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
612 (void **)&if_keys, sizeof(*if_keys), (void **)&if_rw, sizeof(*if_rw),
613 NULL, 0, (void **)&if_stat, sizeof(*if_stat), &if_count, 0 );
615 if (err) return err;
616 for (i = 0; i < if_count; i++)
618 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
619 if_num++;
622 if (!if_num)
624 err = ERROR_NO_DATA;
625 goto err;
628 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE,
629 (void **)&uni_keys, sizeof(*uni_keys), (void **)&uni_rw, sizeof(*uni_rw),
630 NULL, 0, NULL, 0, &uni_count, 0 );
631 if (err) goto err;
633 /* Slightly overestimate the needed size by assuming that all
634 unicast addresses require a separate IP_ADDR_STRING. */
636 needed = if_num * sizeof(*info) + uni_count * sizeof(IP_ADDR_STRING);
637 if (!info || *size < needed)
639 *size = needed;
640 err = ERROR_BUFFER_OVERFLOW;
641 goto err;
644 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE,
645 (void **)&fwd_keys, sizeof(*fwd_keys), NULL, 0,
646 NULL, 0, NULL, 0, &fwd_count, 0 );
647 if (err) goto err;
649 wins_server_count = get_wins_servers( &wins_servers );
651 extra_ip_addrs = (IP_ADDR_STRING *)(info + if_num);
652 for (i = 0; i < if_count; i++)
654 if (if_stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
656 info->Next = info + 1;
657 info->ComboIndex = 0;
658 ConvertGuidToStringA( &if_stat[i].if_guid, info->AdapterName, sizeof(info->AdapterName) );
659 len = WideCharToMultiByte( CP_ACP, 0, if_stat[i].descr.String, if_stat[i].descr.Length / sizeof(WCHAR),
660 info->Description, sizeof(info->Description) - 1, NULL, NULL );
661 info->Description[len] = '\0';
662 info->AddressLength = if_rw[i].phys_addr.Length;
663 if (info->AddressLength > sizeof(info->Address)) info->AddressLength = 0;
664 memcpy( info->Address, if_rw[i].phys_addr.Address, info->AddressLength );
665 memset( info->Address + info->AddressLength, 0, sizeof(info->Address) - info->AddressLength );
666 info->Index = if_stat[i].if_index;
667 info->Type = if_stat[i].type;
668 info->DhcpEnabled = TRUE; /* FIXME */
669 info->CurrentIpAddress = NULL;
671 cursor = NULL;
672 for (uni = 0; uni < uni_count; uni++)
674 if (uni_keys[uni].luid.Value != if_keys[i].Value) continue;
675 if (!cursor) cursor = &info->IpAddressList;
676 else
678 cursor->Next = extra_ip_addrs++;
679 cursor = cursor->Next;
681 ConvertLengthToIpv4Mask( uni_rw[uni].on_link_prefix, &mask.s_addr );
682 ip_addr_string_init( cursor, &uni_keys[uni].addr, &mask, 0 );
684 if (!cursor)
686 mask.s_addr = INADDR_ANY;
687 ip_addr_string_init( &info->IpAddressList, &mask, &mask, 0 );
690 gw.s_addr = INADDR_ANY;
691 mask.s_addr = INADDR_NONE;
692 for (fwd = 0; fwd < fwd_count; fwd++)
693 { /* find the first router on this interface */
694 if (fwd_keys[fwd].luid.Value == if_keys[i].Value &&
695 fwd_keys[fwd].next_hop.s_addr != INADDR_ANY &&
696 !fwd_keys[fwd].prefix_len)
698 gw = fwd_keys[fwd].next_hop;
699 break;
702 ip_addr_string_init( &info->GatewayList, &gw, &mask, 0 );
704 ip_addr_string_init( &info->DhcpServer, NULL, NULL, 0 );
706 info->HaveWins = !!wins_server_count;
707 ip_addr_string_init( &info->PrimaryWinsServer, NULL, NULL, 0 );
708 ip_addr_string_init( &info->SecondaryWinsServer, NULL, NULL, 0 );
709 if (info->HaveWins)
711 mask.s_addr = INADDR_NONE;
712 ip_addr_string_init( &info->PrimaryWinsServer, &wins_servers[0].Ipv4.sin_addr, &mask, 0 );
713 if (wins_server_count > 1)
714 ip_addr_string_init( &info->SecondaryWinsServer, &wins_servers[1].Ipv4.sin_addr, &mask, 0 );
717 info->LeaseObtained = 0;
718 info->LeaseExpires = 0;
720 info++;
722 info[-1].Next = NULL;
724 err:
725 heap_free( wins_servers );
726 NsiFreeTable( fwd_keys, NULL, NULL, NULL );
727 NsiFreeTable( uni_keys, uni_rw, NULL, NULL );
728 NsiFreeTable( if_keys, if_rw, NULL, if_stat );
729 return err;
732 static void address_entry_free( void *ptr, ULONG offset, void *ctxt )
734 heap_free( ptr );
737 static void address_entry_size( void *ptr, ULONG offset, void *ctxt )
739 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
740 ULONG *total = (ULONG *)ctxt, align = sizeof(ULONGLONG) - 1;
742 *total = (*total + src_addr->Length + src_addr->Address.iSockaddrLength + align) & ~align;
745 struct address_entry_copy_params
747 IP_ADAPTER_ADDRESSES *src, *dst;
748 char *ptr;
749 void *next;
750 ULONG cur_offset;
753 static void address_entry_copy( void *ptr, ULONG offset, void *ctxt )
755 struct address_entry_copy_params *params = ctxt;
756 IP_ADAPTER_DNS_SERVER_ADDRESS *src_addr = ptr; /* all list types are super-sets of this type */
757 IP_ADAPTER_DNS_SERVER_ADDRESS *dst_addr = (IP_ADAPTER_DNS_SERVER_ADDRESS *)params->ptr;
758 ULONG align = sizeof(ULONGLONG) - 1;
760 memcpy( dst_addr, src_addr, src_addr->Length );
761 params->ptr += src_addr->Length;
762 dst_addr->Address.lpSockaddr = (SOCKADDR *)params->ptr;
763 memcpy( dst_addr->Address.lpSockaddr, src_addr->Address.lpSockaddr, src_addr->Address.iSockaddrLength );
764 params->ptr += (src_addr->Address.iSockaddrLength + align) & ~align;
766 if (params->cur_offset != offset) /* new list */
768 params->next = (BYTE *)params->dst + offset;
769 params->cur_offset = offset;
771 *(IP_ADAPTER_DNS_SERVER_ADDRESS **)params->next = dst_addr;
772 params->next = &dst_addr->Next;
775 static void address_lists_iterate( IP_ADAPTER_ADDRESSES *aa, void (*fn)(void *entry, ULONG offset, void *ctxt), void *ctxt )
777 IP_ADAPTER_UNICAST_ADDRESS *uni;
778 IP_ADAPTER_DNS_SERVER_ADDRESS *dns;
779 IP_ADAPTER_GATEWAY_ADDRESS *gw;
780 IP_ADAPTER_PREFIX *prefix;
781 void *next;
783 for (uni = aa->FirstUnicastAddress; uni; uni = next)
785 next = uni->Next;
786 fn( uni, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstUnicastAddress ), ctxt );
789 for (dns = aa->FirstDnsServerAddress; dns; dns = next)
791 next = dns->Next;
792 fn( dns, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstDnsServerAddress ), ctxt );
795 for (gw = aa->FirstGatewayAddress; gw; gw = next)
797 next = gw->Next;
798 fn( gw, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstGatewayAddress ), ctxt );
801 for (prefix = aa->FirstPrefix; prefix; prefix = next)
803 next = prefix->Next;
804 fn( prefix, FIELD_OFFSET( IP_ADAPTER_ADDRESSES, FirstPrefix ), ctxt );
808 static void adapters_addresses_free( IP_ADAPTER_ADDRESSES *info )
810 IP_ADAPTER_ADDRESSES *aa;
812 for (aa = info; aa; aa = aa->Next)
814 address_lists_iterate( aa, address_entry_free, NULL );
816 heap_free( aa->DnsSuffix );
818 heap_free( info );
821 static ULONG adapters_addresses_size( IP_ADAPTER_ADDRESSES *info )
823 IP_ADAPTER_ADDRESSES *aa;
824 ULONG size = 0, align = sizeof(ULONGLONG) - 1;
826 for (aa = info; aa; aa = aa->Next)
828 size += sizeof(*aa) + ((strlen( aa->AdapterName ) + 1 + 1) & ~1);
829 size += (wcslen( aa->Description ) + 1 + wcslen( aa->DnsSuffix ) + 1) * sizeof(WCHAR);
830 if (aa->FriendlyName) size += (wcslen( aa->FriendlyName ) + 1) * sizeof(WCHAR);
831 size = (size + align) & ~align;
832 address_lists_iterate( aa, address_entry_size, &size );
834 return size;
837 static void adapters_addresses_copy( IP_ADAPTER_ADDRESSES *dst, IP_ADAPTER_ADDRESSES *src )
839 char *ptr;
840 DWORD len;
841 UINT_PTR align = sizeof(ULONGLONG) - 1;
842 struct address_entry_copy_params params;
844 while (src)
846 ptr = (char *)(dst + 1);
847 *dst = *src;
848 dst->AdapterName = ptr;
849 len = strlen( src->AdapterName ) + 1;
850 memcpy( dst->AdapterName, src->AdapterName, len );
851 ptr += (len + 1) & ~1;
852 dst->Description = (WCHAR *)ptr;
853 len = (wcslen( src->Description ) + 1) * sizeof(WCHAR);
854 memcpy( dst->Description, src->Description, len );
855 ptr += len;
856 dst->DnsSuffix = (WCHAR *)ptr;
857 len = (wcslen( src->DnsSuffix ) + 1) * sizeof(WCHAR);
858 memcpy( dst->DnsSuffix, src->DnsSuffix, len );
859 ptr += len;
860 if (src->FriendlyName)
862 dst->FriendlyName = (WCHAR *)ptr;
863 len = (wcslen( src->FriendlyName ) + 1) * sizeof(WCHAR);
864 memcpy( dst->FriendlyName, src->FriendlyName, len );
865 ptr += len;
867 ptr = (char *)(((UINT_PTR)ptr + align) & ~align);
869 params.src = src;
870 params.dst = dst;
871 params.ptr = ptr;
872 params.next = NULL;
873 params.cur_offset = ~0u;
874 address_lists_iterate( src, address_entry_copy, &params );
875 ptr = params.ptr;
877 if (src->Next)
879 dst->Next = (IP_ADAPTER_ADDRESSES *)ptr;
880 dst = dst->Next;
882 src = src->Next;
886 static BOOL sockaddr_is_loopback( SOCKADDR *sock )
888 if (sock->sa_family == AF_INET)
890 SOCKADDR_IN *sin = (SOCKADDR_IN *)sock;
891 return (sin->sin_addr.s_addr & 0xff) == 127;
893 else if (sock->sa_family == AF_INET6)
895 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
896 return IN6_IS_ADDR_LOOPBACK( &sin6->sin6_addr );
898 return FALSE;
901 static BOOL sockaddr_is_linklocal( SOCKADDR *sock )
903 if (sock->sa_family == AF_INET6)
905 SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)sock;
906 return IN6_IS_ADDR_LINKLOCAL( &sin6->sin6_addr );
908 return FALSE;
911 static BOOL unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS *uni )
913 return !sockaddr_is_loopback( uni->Address.lpSockaddr ) &&
914 !sockaddr_is_linklocal( uni->Address.lpSockaddr );
917 static DWORD unicast_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
919 struct nsi_ipv4_unicast_key *key4;
920 struct nsi_ipv6_unicast_key *key6;
921 struct nsi_ip_unicast_rw *rw;
922 struct nsi_ip_unicast_dynamic *dyn;
923 struct nsi_ip_unicast_static *stat;
924 IP_ADAPTER_UNICAST_ADDRESS *addr, **next;
925 DWORD err, count, i, key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
926 DWORD sockaddr_size = (family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
927 NET_LUID *luid;
928 void *key;
930 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_UNICAST_TABLE, &key, key_size,
931 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
932 (void **)&stat, sizeof(*stat), &count, 0 );
933 if (err) return err;
936 while (aa)
938 for (next = &aa->FirstUnicastAddress; *next; next = &(*next)->Next)
941 for (i = 0; i < count; i++)
943 key4 = (struct nsi_ipv4_unicast_key *)key + i;
944 key6 = (struct nsi_ipv6_unicast_key *)key + i;
945 luid = (family == AF_INET) ? &key4->luid : &key6->luid;
946 if (luid->Value != aa->Luid.Value) continue;
947 addr = heap_alloc_zero( sizeof(*addr) + sockaddr_size );
948 if (!addr)
950 err = ERROR_NOT_ENOUGH_MEMORY;
951 goto err;
953 addr->Length = sizeof(*addr);
954 addr->Address.lpSockaddr = (SOCKADDR *)(addr + 1);
955 addr->Address.iSockaddrLength = sockaddr_size;
956 addr->Address.lpSockaddr->sa_family = family;
957 if (family == AF_INET)
959 SOCKADDR_IN *in = (SOCKADDR_IN *)addr->Address.lpSockaddr;
960 in->sin_addr = key4->addr;
961 aa->Ipv4Enabled = TRUE;
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;
968 aa->Ipv6Enabled = TRUE;
970 addr->PrefixOrigin = rw[i].prefix_origin;
971 addr->SuffixOrigin = rw[i].suffix_origin;
972 addr->DadState = dyn[i].dad_state;
973 addr->ValidLifetime = rw[i].valid_lifetime;
974 addr->PreferredLifetime = rw[i].preferred_lifetime;
975 addr->LeaseLifetime = rw[i].valid_lifetime; /* FIXME */
976 addr->OnLinkPrefixLength = rw[i].on_link_prefix;
977 if (unicast_is_dns_eligible( addr )) addr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE;
979 *next = addr;
980 next = &addr->Next;
982 aa = aa->Next;
985 err:
986 NsiFreeTable( key, rw, dyn, stat );
987 return err;
990 static DWORD gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
992 struct nsi_ipv4_forward_key *key4;
993 struct nsi_ipv6_forward_key *key6;
994 IP_ADAPTER_GATEWAY_ADDRESS *gw, **gw_next;
995 IP_ADAPTER_PREFIX *prefix, **prefix_next;
996 DWORD err, count, i, prefix_len, key_size = (family == AF_INET) ? sizeof(*key4) : sizeof(*key6);
997 DWORD sockaddr_size = (family == AF_INET) ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
998 SOCKADDR_INET sockaddr;
999 NET_LUID *luid;
1000 void *key;
1002 err = NsiAllocateAndGetTable( 1, ip_module_id( family ), NSI_IP_FORWARD_TABLE, &key, key_size,
1003 NULL, 0, NULL, 0, NULL, 0, &count, 0 );
1004 if (err) return err;
1006 while (aa)
1008 for (gw_next = &aa->FirstGatewayAddress; *gw_next; gw_next = &(*gw_next)->Next)
1010 for (prefix_next = &aa->FirstPrefix; *prefix_next; prefix_next = &(*prefix_next)->Next)
1013 for (i = 0; i < count; i++)
1015 key4 = (struct nsi_ipv4_forward_key *)key + i;
1016 key6 = (struct nsi_ipv6_forward_key *)key + i;
1017 luid = (family == AF_INET) ? &key4->luid : &key6->luid;
1018 if (luid->Value != aa->Luid.Value) continue;
1020 if (flags & GAA_FLAG_INCLUDE_GATEWAYS)
1022 memset( &sockaddr, 0, sizeof(sockaddr) );
1023 if (family == AF_INET)
1025 if (key4->next_hop.s_addr != 0)
1027 sockaddr.si_family = family;
1028 sockaddr.Ipv4.sin_addr = key4->next_hop;
1031 else
1033 static const IN6_ADDR zero;
1034 if (memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1036 sockaddr.si_family = family;
1037 sockaddr.Ipv6.sin6_addr = key6->next_hop;
1041 if (sockaddr.si_family)
1043 gw = heap_alloc_zero( sizeof(*gw) + sockaddr_size );
1044 if (!gw)
1046 err = ERROR_NOT_ENOUGH_MEMORY;
1047 goto err;
1049 gw->Length = sizeof(*gw);
1050 gw->Address.lpSockaddr = (SOCKADDR *)(gw + 1);
1051 gw->Address.iSockaddrLength = sockaddr_size;
1052 memcpy( gw->Address.lpSockaddr, &sockaddr, sockaddr_size );
1053 *gw_next = gw;
1054 gw_next = &gw->Next;
1058 if (flags & GAA_FLAG_INCLUDE_PREFIX)
1060 memset( &sockaddr, 0, sizeof(sockaddr) );
1061 prefix_len = 0;
1062 if (family == AF_INET)
1064 if (!key4->next_hop.s_addr)
1066 sockaddr.si_family = family;
1067 sockaddr.Ipv4.sin_addr = key4->prefix;
1068 prefix_len = key4->prefix_len;
1071 else
1073 static const IN6_ADDR zero;
1074 if (!memcmp( &key6->next_hop, &zero, sizeof(zero) ))
1076 sockaddr.si_family = family;
1077 sockaddr.Ipv6.sin6_addr = key6->prefix;
1078 prefix_len = key6->prefix_len;
1082 if (sockaddr.si_family)
1084 prefix = heap_alloc_zero( sizeof(*prefix) + sockaddr_size );
1085 if (!prefix)
1087 err = ERROR_NOT_ENOUGH_MEMORY;
1088 goto err;
1090 prefix->Length = sizeof(*prefix);
1091 prefix->Address.lpSockaddr = (SOCKADDR *)(prefix + 1);
1092 prefix->Address.iSockaddrLength = sockaddr_size;
1093 memcpy( prefix->Address.lpSockaddr, &sockaddr, sockaddr_size );
1094 prefix->PrefixLength = prefix_len;
1095 *prefix_next = prefix;
1096 prefix_next = &prefix->Next;
1100 aa = aa->Next;
1103 err:
1104 NsiFreeTable( key, NULL, NULL, NULL );
1105 return err;
1108 static DWORD call_families( DWORD (*fn)( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags ),
1109 IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1111 DWORD err;
1113 if (family != AF_INET)
1115 err = fn( aa, AF_INET6, flags );
1116 if (err) return err;
1119 if (family != AF_INET6)
1121 err = fn( aa, AF_INET, flags );
1122 if (err) return err;
1124 return err;
1127 static DWORD dns_servers_query_code( ULONG family )
1129 if (family == AF_INET) return DnsConfigDnsServersIpv4;
1130 if (family == AF_INET6) return DnsConfigDnsServersIpv6;
1131 return DnsConfigDnsServersUnspec;
1134 static DWORD dns_info_alloc( IP_ADAPTER_ADDRESSES *aa, ULONG family, ULONG flags )
1136 char buf[FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[3])];
1137 IP_ADAPTER_DNS_SERVER_ADDRESS *dns, **next;
1138 DWORD query = dns_servers_query_code( family );
1139 DWORD err, i, size, attempt, sockaddr_len;
1140 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
1141 DNS_ADDR_ARRAY *servers;
1142 WCHAR *search;
1144 while (aa)
1146 MultiByteToWideChar( CP_ACP, 0, aa->AdapterName, -1, name, ARRAY_SIZE(name) );
1147 if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1149 servers = (DNS_ADDR_ARRAY *)buf;
1150 for (attempt = 0; attempt < 5; attempt++)
1152 err = DnsQueryConfig( query, 0, name, NULL, servers, &size );
1153 if (err != ERROR_MORE_DATA) break;
1154 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1155 servers = heap_alloc( size );
1156 if (!servers)
1158 err = ERROR_NOT_ENOUGH_MEMORY;
1159 break;
1162 if (!err)
1164 next = &aa->FirstDnsServerAddress;
1165 for (i = 0; i < servers->AddrCount; i++)
1167 sockaddr_len = servers->AddrArray[i].Data.DnsAddrUserDword[0];
1168 if (sockaddr_len > sizeof(servers->AddrArray[i].MaxSa))
1169 sockaddr_len = sizeof(servers->AddrArray[i].MaxSa);
1170 dns = heap_alloc_zero( sizeof(*dns) + sockaddr_len );
1171 if (!dns)
1173 err = ERROR_NOT_ENOUGH_MEMORY;
1174 break;
1176 dns->Length = sizeof(*dns);
1177 dns->Address.lpSockaddr = (SOCKADDR *)(dns + 1);
1178 dns->Address.iSockaddrLength = sockaddr_len;
1179 memcpy( dns->Address.lpSockaddr, servers->AddrArray[i].MaxSa, sockaddr_len );
1180 *next = dns;
1181 next = &dns->Next;
1184 if (servers != (DNS_ADDR_ARRAY *)buf) heap_free( servers );
1185 if (err) return err;
1188 aa->DnsSuffix = heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH * sizeof(WCHAR) );
1189 if (!aa->DnsSuffix) return ERROR_NOT_ENOUGH_MEMORY;
1190 aa->DnsSuffix[0] = '\0';
1192 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, NULL, &size ) &&
1193 (search = heap_alloc( size )))
1195 if (!DnsQueryConfig( DnsConfigSearchList, 0, name, NULL, search, &size ) &&
1196 search[0] && wcslen( search ) < MAX_DNS_SUFFIX_STRING_LENGTH)
1198 wcscpy( aa->DnsSuffix, search );
1200 heap_free( search );
1203 aa = aa->Next;
1206 return ERROR_SUCCESS;
1209 static DWORD adapters_addresses_alloc( ULONG family, ULONG flags, IP_ADAPTER_ADDRESSES **info )
1211 IP_ADAPTER_ADDRESSES *aa;
1212 NET_LUID *luids;
1213 struct nsi_ndis_ifinfo_rw *rw;
1214 struct nsi_ndis_ifinfo_dynamic *dyn;
1215 struct nsi_ndis_ifinfo_static *stat;
1216 DWORD err, i, count, needed;
1217 GUID guid;
1218 char *str_ptr;
1220 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&luids, sizeof(*luids),
1221 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1222 (void **)&stat, sizeof(*stat), &count, 0 );
1223 if (err) return err;
1225 needed = count * (sizeof(*aa) + ((CHARS_IN_GUID + 1) & ~1) + sizeof(stat->descr.String));
1226 needed += count * sizeof(rw->alias.String); /* GAA_FLAG_SKIP_FRIENDLY_NAME is ignored */
1228 aa = heap_alloc_zero( needed );
1229 if (!aa)
1231 err = ERROR_NOT_ENOUGH_MEMORY;
1232 goto err;
1235 str_ptr = (char *)(aa + count);
1236 for (i = 0; i < count; i++)
1238 aa[i].Length = sizeof(*aa);
1239 aa[i].IfIndex = stat[i].if_index;
1240 if (i < count - 1) aa[i].Next = aa + i + 1;
1241 ConvertInterfaceLuidToGuid( luids + i, &guid );
1242 ConvertGuidToStringA( &guid, str_ptr, CHARS_IN_GUID );
1243 aa[i].AdapterName = str_ptr;
1244 str_ptr += (CHARS_IN_GUID + 1) & ~1;
1245 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(stat[i].descr.String), &stat[i].descr );
1246 aa[i].Description = (WCHAR *)str_ptr;
1247 str_ptr += sizeof(stat[i].descr.String);
1248 if_counted_string_copy( (WCHAR *)str_ptr, ARRAY_SIZE(rw[i].alias.String), &rw[i].alias );
1249 aa[i].FriendlyName = (WCHAR *)str_ptr;
1250 str_ptr += sizeof(rw[i].alias.String);
1251 aa[i].PhysicalAddressLength = rw[i].phys_addr.Length;
1252 if (aa[i].PhysicalAddressLength > sizeof(aa[i].PhysicalAddress)) aa[i].PhysicalAddressLength = 0;
1253 memcpy( aa[i].PhysicalAddress, rw[i].phys_addr.Address, aa[i].PhysicalAddressLength );
1254 aa[i].Mtu = dyn[i].mtu;
1255 aa[i].IfType = stat[i].type;
1256 aa[i].OperStatus = dyn[i].oper_status;
1257 aa[i].TransmitLinkSpeed = dyn[i].xmit_speed;
1258 aa[i].ReceiveLinkSpeed = dyn[i].rcv_speed;
1259 aa[i].Luid = luids[i];
1260 aa[i].NetworkGuid = rw[i].network_guid;
1261 aa[i].ConnectionType = stat[i].conn_type;
1264 if (!(flags & GAA_FLAG_SKIP_UNICAST))
1266 err = call_families( unicast_addresses_alloc, aa, family, flags );
1267 if (err) goto err;
1270 if (flags & (GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_PREFIX))
1272 err = call_families( gateway_and_prefix_addresses_alloc, aa, family, flags );
1273 if (err) goto err;
1276 err = dns_info_alloc( aa, family, flags );
1277 if (err) goto err;
1279 err:
1280 NsiFreeTable( luids, rw, dyn, stat );
1281 if (!err) *info = aa;
1282 else adapters_addresses_free( aa );
1283 return err;
1286 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses( ULONG family, ULONG flags, void *reserved,
1287 IP_ADAPTER_ADDRESSES *aa, ULONG *size )
1289 IP_ADAPTER_ADDRESSES *info;
1290 DWORD err, needed;
1292 TRACE( "(%ld, %08lx, %p, %p, %p)\n", family, flags, reserved, aa, size );
1294 if (!size) return ERROR_INVALID_PARAMETER;
1296 err = adapters_addresses_alloc( family, flags, &info );
1297 if (err) return err;
1299 needed = adapters_addresses_size( info );
1300 if (!aa || *size < needed)
1302 *size = needed;
1303 err = ERROR_BUFFER_OVERFLOW;
1305 else
1306 adapters_addresses_copy( aa, info );
1308 adapters_addresses_free( info );
1309 return err;
1312 /******************************************************************
1313 * GetBestInterface (IPHLPAPI.@)
1315 * Get the interface, with the best route for the given IP address.
1317 * PARAMS
1318 * dwDestAddr [In] IP address to search the interface for
1319 * pdwBestIfIndex [Out] found best interface
1321 * RETURNS
1322 * Success: NO_ERROR
1323 * Failure: error code from winerror.h
1325 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1327 struct sockaddr_in sa_in;
1328 memset(&sa_in, 0, sizeof(sa_in));
1329 sa_in.sin_family = AF_INET;
1330 sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1331 return GetBestInterfaceEx((struct sockaddr *)&sa_in, pdwBestIfIndex);
1334 /******************************************************************
1335 * GetBestInterfaceEx (IPHLPAPI.@)
1337 * Get the interface, with the best route for the given IP address.
1339 * PARAMS
1340 * dwDestAddr [In] IP address to search the interface for
1341 * pdwBestIfIndex [Out] found best interface
1343 * RETURNS
1344 * Success: NO_ERROR
1345 * Failure: error code from winerror.h
1347 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1349 DWORD ret;
1351 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1352 if (!pDestAddr || !pdwBestIfIndex)
1353 ret = ERROR_INVALID_PARAMETER;
1354 else {
1355 MIB_IPFORWARDROW ipRow;
1357 if (pDestAddr->sa_family == AF_INET) {
1358 ret = GetBestRoute(((struct sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1359 if (ret == ERROR_SUCCESS)
1360 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1361 } else {
1362 FIXME("address family %d not supported\n", pDestAddr->sa_family);
1363 ret = ERROR_NOT_SUPPORTED;
1366 TRACE("returning %ld\n", ret);
1367 return ret;
1371 /******************************************************************
1372 * GetBestRoute (IPHLPAPI.@)
1374 * Get the best route for the given IP address.
1376 * PARAMS
1377 * dwDestAddr [In] IP address to search the best route for
1378 * dwSourceAddr [In] optional source IP address
1379 * pBestRoute [Out] found best route
1381 * RETURNS
1382 * Success: NO_ERROR
1383 * Failure: error code from winerror.h
1385 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1387 PMIB_IPFORWARDTABLE table;
1388 DWORD ret;
1390 TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
1391 dwSourceAddr, pBestRoute);
1392 if (!pBestRoute)
1393 return ERROR_INVALID_PARAMETER;
1395 ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1396 if (!ret) {
1397 DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1399 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1400 if (table->table[ndx].ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1401 (dwDestAddr & table->table[ndx].dwForwardMask) ==
1402 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1403 DWORD numShifts, mask;
1405 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1406 mask && mask & 1; mask >>= 1, numShifts++)
1408 if (numShifts > matchedBits) {
1409 matchedBits = numShifts;
1410 matchedNdx = ndx;
1412 else if (!matchedBits) {
1413 matchedNdx = ndx;
1417 if (matchedNdx < table->dwNumEntries) {
1418 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1419 ret = ERROR_SUCCESS;
1421 else {
1422 /* No route matches, which can happen if there's no default route. */
1423 ret = ERROR_HOST_UNREACHABLE;
1425 HeapFree(GetProcessHeap(), 0, table);
1427 TRACE("returning %ld\n", ret);
1428 return ret;
1432 /******************************************************************
1433 * GetFriendlyIfIndex (IPHLPAPI.@)
1435 * Get a "friendly" version of IfIndex, which is one that doesn't
1436 * have the top byte set. Doesn't validate whether IfIndex is a valid
1437 * adapter index.
1439 * PARAMS
1440 * IfIndex [In] interface index to get the friendly one for
1442 * RETURNS
1443 * A friendly version of IfIndex.
1445 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1447 /* windows doesn't validate these, either, just makes sure the top byte is
1448 cleared. I assume my ifenum module never gives an index with the top
1449 byte set. */
1450 TRACE("returning %ld\n", IfIndex);
1451 return IfIndex;
1454 static void icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX *stats_ex, MIBICMPSTATS *stats )
1456 stats->dwMsgs = stats_ex->dwMsgs;
1457 stats->dwErrors = stats_ex->dwErrors;
1458 stats->dwDestUnreachs = stats_ex->rgdwTypeCount[ICMP4_DST_UNREACH];
1459 stats->dwTimeExcds = stats_ex->rgdwTypeCount[ICMP4_TIME_EXCEEDED];
1460 stats->dwParmProbs = stats_ex->rgdwTypeCount[ICMP4_PARAM_PROB];
1461 stats->dwSrcQuenchs = stats_ex->rgdwTypeCount[ICMP4_SOURCE_QUENCH];
1462 stats->dwRedirects = stats_ex->rgdwTypeCount[ICMP4_REDIRECT];
1463 stats->dwEchos = stats_ex->rgdwTypeCount[ICMP4_ECHO_REQUEST];
1464 stats->dwEchoReps = stats_ex->rgdwTypeCount[ICMP4_ECHO_REPLY];
1465 stats->dwTimestamps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST];
1466 stats->dwTimestampReps = stats_ex->rgdwTypeCount[ICMP4_TIMESTAMP_REPLY];
1467 stats->dwAddrMasks = stats_ex->rgdwTypeCount[ICMP4_MASK_REQUEST];
1468 stats->dwAddrMaskReps = stats_ex->rgdwTypeCount[ICMP4_MASK_REPLY];
1471 /******************************************************************
1472 * GetIcmpStatistics (IPHLPAPI.@)
1474 * Get the ICMP statistics for the local computer.
1476 * PARAMS
1477 * stats [Out] buffer for ICMP statistics
1479 * RETURNS
1480 * Success: NO_ERROR
1481 * Failure: error code from winerror.h
1483 DWORD WINAPI GetIcmpStatistics( MIB_ICMP *stats )
1485 MIB_ICMP_EX stats_ex;
1486 DWORD err = GetIcmpStatisticsEx( &stats_ex, AF_INET );
1488 if (err) return err;
1490 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpInStats, &stats->stats.icmpInStats );
1491 icmp_stats_ex_to_icmp_stats( &stats_ex.icmpOutStats, &stats->stats.icmpOutStats );
1492 return err;
1495 /******************************************************************
1496 * GetIcmpStatisticsEx (IPHLPAPI.@)
1498 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1500 * PARAMS
1501 * stats [Out] buffer for ICMP statistics
1502 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1504 * RETURNS
1505 * Success: NO_ERROR
1506 * Failure: error code from winerror.h
1508 DWORD WINAPI GetIcmpStatisticsEx( MIB_ICMP_EX *stats, DWORD family )
1510 const NPI_MODULEID *mod = ip_module_id( family );
1511 struct nsi_ip_icmpstats_dynamic dyn;
1512 DWORD err;
1514 if (!stats || !mod) return ERROR_INVALID_PARAMETER;
1515 memset( stats, 0, sizeof(*stats) );
1517 err = NsiGetAllParameters( 1, mod, NSI_IP_ICMPSTATS_TABLE, NULL, 0, NULL, 0,
1518 &dyn, sizeof(dyn), NULL, 0 );
1519 if (err) return err;
1521 stats->icmpInStats.dwMsgs = dyn.in_msgs;
1522 stats->icmpInStats.dwErrors = dyn.in_errors;
1523 memcpy( stats->icmpInStats.rgdwTypeCount, dyn.in_type_counts, sizeof( dyn.in_type_counts ) );
1524 stats->icmpOutStats.dwMsgs = dyn.out_msgs;
1525 stats->icmpOutStats.dwErrors = dyn.out_errors;
1526 memcpy( stats->icmpOutStats.rgdwTypeCount, dyn.out_type_counts, sizeof( dyn.out_type_counts ) );
1528 return ERROR_SUCCESS;
1531 static void if_row_fill( MIB_IFROW *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1532 struct nsi_ndis_ifinfo_static *stat )
1534 wcscpy( row->wszName, device_tcpip );
1535 ConvertGuidToStringW( &stat->if_guid, row->wszName + wcslen( device_tcpip ), CHARS_IN_GUID );
1536 row->dwIndex = stat->if_index;
1537 row->dwType = stat->type;
1538 row->dwMtu = dyn->mtu;
1539 row->dwSpeed = dyn->rcv_speed;
1540 row->dwPhysAddrLen = rw->phys_addr.Length;
1541 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
1542 memcpy( row->bPhysAddr, rw->phys_addr.Address, row->dwPhysAddrLen );
1543 row->dwAdminStatus = rw->admin_status;
1544 row->dwOperStatus = (dyn->oper_status == IfOperStatusUp) ? MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_NON_OPERATIONAL;
1545 row->dwLastChange = 0;
1546 row->dwInOctets = dyn->in_octets;
1547 row->dwInUcastPkts = dyn->in_ucast_pkts;
1548 row->dwInNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1549 row->dwInDiscards = dyn->in_discards;
1550 row->dwInErrors = dyn->in_errors;
1551 row->dwInUnknownProtos = 0;
1552 row->dwOutOctets = dyn->out_octets;
1553 row->dwOutUcastPkts = dyn->out_ucast_pkts;
1554 row->dwOutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1555 row->dwOutDiscards = dyn->out_discards;
1556 row->dwOutErrors = dyn->out_errors;
1557 row->dwOutQLen = 0;
1558 row->dwDescrLen = WideCharToMultiByte( CP_ACP, 0, stat->descr.String, stat->descr.Length / sizeof(WCHAR),
1559 (char *)row->bDescr, sizeof(row->bDescr) - 1, NULL, NULL );
1560 row->bDescr[row->dwDescrLen] = '\0';
1563 /******************************************************************
1564 * GetIfEntry (IPHLPAPI.@)
1566 * Get information about an interface.
1568 * PARAMS
1569 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1570 * Out: interface information
1572 * RETURNS
1573 * Success: NO_ERROR
1574 * Failure: error code from winerror.h
1576 DWORD WINAPI GetIfEntry( MIB_IFROW *row )
1578 struct nsi_ndis_ifinfo_rw rw;
1579 struct nsi_ndis_ifinfo_dynamic dyn;
1580 struct nsi_ndis_ifinfo_static stat;
1581 NET_LUID luid;
1582 DWORD err;
1584 TRACE( "row %p\n", row );
1585 if (!row) return ERROR_INVALID_PARAMETER;
1587 err = ConvertInterfaceIndexToLuid( row->dwIndex, &luid );
1588 if (err) return err;
1590 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1591 &luid, sizeof(luid), &rw, sizeof(rw),
1592 &dyn, sizeof(dyn), &stat, sizeof(stat) );
1593 if (!err) if_row_fill( row, &rw, &dyn, &stat );
1594 return err;
1597 static int DWORD_cmp( DWORD a, DWORD b )
1599 return a < b ? -1 : a > b ? 1 : 0; /* a subtraction would overflow */
1602 static int ifrow_cmp( const void *a, const void *b )
1604 const MIB_IFROW *rowA = a, *rowB = b;
1605 return DWORD_cmp(rowA->dwIndex, rowB->dwIndex);
1608 /******************************************************************
1609 * GetIfTable (IPHLPAPI.@)
1611 * Get a table of local interfaces.
1613 * PARAMS
1614 * table [Out] buffer for local interfaces table
1615 * size [In/Out] length of output buffer
1616 * sort [In] whether to sort the table
1618 * RETURNS
1619 * Success: NO_ERROR
1620 * Failure: error code from winerror.h
1622 * NOTES
1623 * If size is less than required, the function will return
1624 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1625 * size.
1626 * If sort is true, the returned table will be sorted by interface index.
1628 DWORD WINAPI GetIfTable( MIB_IFTABLE *table, ULONG *size, BOOL sort )
1630 DWORD i, count, needed, err;
1631 NET_LUID *keys;
1632 struct nsi_ndis_ifinfo_rw *rw;
1633 struct nsi_ndis_ifinfo_dynamic *dyn;
1634 struct nsi_ndis_ifinfo_static *stat;
1636 if (!size) return ERROR_INVALID_PARAMETER;
1638 /* While this could be implemented on top of GetIfTable2(), it would require
1639 an additional copy of the data */
1640 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1641 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1642 (void **)&stat, sizeof(*stat), &count, 0 );
1643 if (err) return err;
1645 needed = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1647 if (!table || *size < needed)
1649 *size = needed;
1650 err = ERROR_INSUFFICIENT_BUFFER;
1651 goto err;
1654 table->dwNumEntries = count;
1655 for (i = 0; i < count; i++)
1657 MIB_IFROW *row = table->table + i;
1659 if_row_fill( row, rw + i, dyn + i, stat + i );
1662 if (sort) qsort( table->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1664 err:
1665 NsiFreeTable( keys, rw, dyn, stat );
1666 return err;
1669 /******************************************************************
1670 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1672 * Get table of local interfaces.
1673 * Like GetIfTable(), but allocate the returned table from heap.
1675 * PARAMS
1676 * table [Out] pointer into which the MIB_IFTABLE is
1677 * allocated and returned.
1678 * sort [In] whether to sort the table
1679 * heap [In] heap from which the table is allocated
1680 * flags [In] flags to HeapAlloc
1682 * RETURNS
1683 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1684 * GetIfTable() returns otherwise.
1686 DWORD WINAPI AllocateAndGetIfTableFromStack( MIB_IFTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
1688 DWORD i, count, size, err;
1689 NET_LUID *keys;
1690 struct nsi_ndis_ifinfo_rw *rw;
1691 struct nsi_ndis_ifinfo_dynamic *dyn;
1692 struct nsi_ndis_ifinfo_static *stat;
1694 if (!table) return ERROR_INVALID_PARAMETER;
1696 /* While this could be implemented on top of GetIfTable(), it would require
1697 an additional call to retrieve the size */
1698 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1699 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1700 (void **)&stat, sizeof(*stat), &count, 0 );
1701 if (err) return err;
1703 size = FIELD_OFFSET( MIB_IFTABLE, table[count] );
1704 *table = HeapAlloc( heap, flags, size );
1705 if (!*table)
1707 err = ERROR_NOT_ENOUGH_MEMORY;
1708 goto err;
1711 (*table)->dwNumEntries = count;
1712 for (i = 0; i < count; i++)
1714 MIB_IFROW *row = (*table)->table + i;
1716 if_row_fill( row, rw + i, dyn + i, stat + i );
1718 if (sort) qsort( (*table)->table, count, sizeof(MIB_IFROW), ifrow_cmp );
1720 err:
1721 NsiFreeTable( keys, rw, dyn, stat );
1722 return err;
1725 static void if_row2_fill( MIB_IF_ROW2 *row, struct nsi_ndis_ifinfo_rw *rw, struct nsi_ndis_ifinfo_dynamic *dyn,
1726 struct nsi_ndis_ifinfo_static *stat )
1728 row->InterfaceIndex = stat->if_index;
1729 row->InterfaceGuid = stat->if_guid;
1730 if_counted_string_copy( row->Alias, ARRAY_SIZE(row->Alias), &rw->alias );
1731 if_counted_string_copy( row->Description, ARRAY_SIZE(row->Description), &stat->descr );
1732 row->PhysicalAddressLength = rw->phys_addr.Length;
1733 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress)) row->PhysicalAddressLength = 0;
1734 memcpy( row->PhysicalAddress, rw->phys_addr.Address, row->PhysicalAddressLength );
1735 memcpy( row->PermanentPhysicalAddress, stat->perm_phys_addr.Address, row->PhysicalAddressLength );
1736 row->Mtu = dyn->mtu;
1737 row->Type = stat->type;
1738 row->TunnelType = TUNNEL_TYPE_NONE; /* fixme */
1739 row->MediaType = stat->media_type;
1740 row->PhysicalMediumType = stat->phys_medium_type;
1741 row->AccessType = stat->access_type;
1742 row->DirectionType = NET_IF_DIRECTION_SENDRECEIVE; /* fixme */
1743 row->InterfaceAndOperStatusFlags.HardwareInterface = stat->flags.hw;
1744 row->InterfaceAndOperStatusFlags.FilterInterface = stat->flags.filter;
1745 row->InterfaceAndOperStatusFlags.ConnectorPresent = !!stat->conn_present;
1746 row->InterfaceAndOperStatusFlags.NotAuthenticated = 0; /* fixme */
1747 row->InterfaceAndOperStatusFlags.NotMediaConnected = dyn->flags.not_media_conn;
1748 row->InterfaceAndOperStatusFlags.Paused = 0; /* fixme */
1749 row->InterfaceAndOperStatusFlags.LowPower = 0; /* fixme */
1750 row->InterfaceAndOperStatusFlags.EndPointInterface = 0; /* fixme */
1751 row->OperStatus = dyn->oper_status;
1752 row->AdminStatus = rw->admin_status;
1753 row->MediaConnectState = dyn->media_conn_state;
1754 row->NetworkGuid = rw->network_guid;
1755 row->ConnectionType = stat->conn_type;
1756 row->TransmitLinkSpeed = dyn->xmit_speed;
1757 row->ReceiveLinkSpeed = dyn->rcv_speed;
1758 row->InOctets = dyn->in_octets;
1759 row->InUcastPkts = dyn->in_ucast_pkts;
1760 row->InNUcastPkts = dyn->in_bcast_pkts + dyn->in_mcast_pkts;
1761 row->InDiscards = dyn->in_discards;
1762 row->InErrors = dyn->in_errors;
1763 row->InUnknownProtos = 0; /* fixme */
1764 row->InUcastOctets = dyn->in_ucast_octs;
1765 row->InMulticastOctets = dyn->in_mcast_octs;
1766 row->InBroadcastOctets = dyn->in_bcast_octs;
1767 row->OutOctets = dyn->out_octets;
1768 row->OutUcastPkts = dyn->out_ucast_pkts;
1769 row->OutNUcastPkts = dyn->out_bcast_pkts + dyn->out_mcast_pkts;
1770 row->OutDiscards = dyn->out_discards;
1771 row->OutErrors = dyn->out_errors;
1772 row->OutUcastOctets = dyn->out_ucast_octs;
1773 row->OutMulticastOctets = dyn->out_mcast_octs;
1774 row->OutBroadcastOctets = dyn->out_bcast_octs;
1775 row->OutQLen = 0; /* fixme */
1778 /******************************************************************
1779 * GetIfEntry2Ex (IPHLPAPI.@)
1781 DWORD WINAPI GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_ROW2 *row )
1783 DWORD err;
1784 struct nsi_ndis_ifinfo_rw rw;
1785 struct nsi_ndis_ifinfo_dynamic dyn;
1786 struct nsi_ndis_ifinfo_static stat;
1788 TRACE( "(%d, %p)\n", level, row );
1790 if (level != MibIfTableNormal) FIXME( "level %u not fully supported\n", level );
1791 if (!row) return ERROR_INVALID_PARAMETER;
1793 if (!row->InterfaceLuid.Value)
1795 if (!row->InterfaceIndex) return ERROR_INVALID_PARAMETER;
1796 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
1797 if (err) return err;
1800 err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1801 &row->InterfaceLuid, sizeof(row->InterfaceLuid),
1802 &rw, sizeof(rw), &dyn, sizeof(dyn), &stat, sizeof(stat) );
1803 if (!err) if_row2_fill( row, &rw, &dyn, &stat );
1804 return err;
1807 /******************************************************************
1808 * GetIfEntry2 (IPHLPAPI.@)
1810 DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row )
1812 return GetIfEntry2Ex( MibIfTableNormal, row );
1815 /******************************************************************
1816 * GetIfTable2Ex (IPHLPAPI.@)
1818 DWORD WINAPI GetIfTable2Ex( MIB_IF_TABLE_LEVEL level, MIB_IF_TABLE2 **table )
1820 DWORD i, count, size, err;
1821 NET_LUID *keys;
1822 struct nsi_ndis_ifinfo_rw *rw;
1823 struct nsi_ndis_ifinfo_dynamic *dyn;
1824 struct nsi_ndis_ifinfo_static *stat;
1826 TRACE( "level %u, table %p\n", level, table );
1828 if (!table || level > MibIfTableNormalWithoutStatistics)
1829 return ERROR_INVALID_PARAMETER;
1831 if (level != MibIfTableNormal)
1832 FIXME("level %u not fully supported\n", level);
1834 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
1835 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
1836 (void **)&stat, sizeof(*stat), &count, 0 );
1837 if (err) return err;
1839 size = FIELD_OFFSET( MIB_IF_TABLE2, Table[count] );
1841 if (!(*table = heap_alloc_zero( size )))
1843 err = ERROR_OUTOFMEMORY;
1844 goto err;
1847 (*table)->NumEntries = count;
1848 for (i = 0; i < count; i++)
1850 MIB_IF_ROW2 *row = (*table)->Table + i;
1852 row->InterfaceLuid.Value = keys[i].Value;
1853 if_row2_fill( row, rw + i, dyn + i, stat + i );
1855 err:
1856 NsiFreeTable( keys, rw, dyn, stat );
1857 return err;
1860 /******************************************************************
1861 * GetIfTable2 (IPHLPAPI.@)
1863 DWORD WINAPI GetIfTable2( MIB_IF_TABLE2 **table )
1865 TRACE( "table %p\n", table );
1866 return GetIfTable2Ex( MibIfTableNormal, table );
1869 /******************************************************************
1870 * GetInterfaceInfo (IPHLPAPI.@)
1872 * Get a list of network interface adapters.
1874 * PARAMS
1875 * pIfTable [Out] buffer for interface adapters
1876 * dwOutBufLen [Out] if buffer is too small, returns required size
1878 * RETURNS
1879 * Success: NO_ERROR
1880 * Failure: error code from winerror.h
1882 * BUGS
1883 * MSDN states this should return non-loopback interfaces only.
1885 DWORD WINAPI GetInterfaceInfo( IP_INTERFACE_INFO *table, ULONG *size )
1887 NET_LUID *keys;
1888 struct nsi_ndis_ifinfo_static *stat;
1889 DWORD err, count, num = 0, needed, i;
1891 TRACE( "table %p, size %p\n", table, size );
1892 if (!size) return ERROR_INVALID_PARAMETER;
1894 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE,
1895 (void **)&keys, sizeof(*keys), NULL, 0, NULL, 0,
1896 (void **)&stat, sizeof(*stat), &count, 0 );
1897 if (err) return err;
1899 for (i = 0; i < count; i++)
1901 if (stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1902 num++;
1905 needed = FIELD_OFFSET(IP_INTERFACE_INFO, Adapter[num]);
1906 if (!table || *size < needed)
1908 *size = needed;
1909 err = ERROR_INSUFFICIENT_BUFFER;
1910 goto done;
1913 table->NumAdapters = num;
1914 for (i = 0, num = 0; i < count; i++)
1916 IP_ADAPTER_INDEX_MAP *row;
1918 if (stat[i].type == IF_TYPE_SOFTWARE_LOOPBACK) continue;
1919 row = table->Adapter + num++;
1920 row->Index = stat[i].if_index;
1921 wcscpy( row->Name, device_tcpip );
1922 ConvertGuidToStringW( &stat[i].if_guid, row->Name + wcslen( device_tcpip ), CHARS_IN_GUID );
1924 done:
1925 NsiFreeTable( keys, NULL, NULL, stat );
1926 return err;
1929 static int ipaddrrow_cmp( const void *a, const void *b )
1931 const MIB_IPADDRROW *rowA = a, *rowB = b;
1932 return DWORD_cmp(RtlUlongByteSwap( rowA->dwAddr ), RtlUlongByteSwap( rowB->dwAddr ));
1935 /******************************************************************
1936 * GetIpAddrTable (IPHLPAPI.@)
1938 * Get interface-to-IP address mapping table.
1940 * PARAMS
1941 * table [Out] buffer for mapping table
1942 * size [In/Out] length of output buffer
1943 * sort [In] whether to sort the table
1945 * RETURNS
1946 * Success: NO_ERROR
1947 * Failure: error code from winerror.h
1950 DWORD WINAPI GetIpAddrTable( MIB_IPADDRTABLE *table, ULONG *size, BOOL sort )
1952 DWORD err, count, needed, i, loopback, row_num = 0;
1953 struct nsi_ipv4_unicast_key *keys;
1954 struct nsi_ip_unicast_rw *rw;
1956 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
1957 if (!size) return ERROR_INVALID_PARAMETER;
1959 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&keys, sizeof(*keys),
1960 (void **)&rw, sizeof(*rw), NULL, 0, NULL, 0, &count, 0 );
1961 if (err) return err;
1963 needed = FIELD_OFFSET( MIB_IPADDRTABLE, table[count] );
1965 if (!table || *size < needed)
1967 *size = needed;
1968 err = ERROR_INSUFFICIENT_BUFFER;
1969 goto err;
1972 table->dwNumEntries = count;
1974 for (loopback = 0; loopback < 2; loopback++) /* Move the loopback addresses to the end */
1976 for (i = 0; i < count; i++)
1978 MIB_IPADDRROW *row = table->table + row_num;
1980 if (!!loopback != (keys[i].luid.Info.IfType == MIB_IF_TYPE_LOOPBACK)) continue;
1982 row->dwAddr = keys[i].addr.s_addr;
1983 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
1984 ConvertLengthToIpv4Mask( rw[i].on_link_prefix, &row->dwMask );
1985 row->dwBCastAddr = 1;
1986 row->dwReasmSize = 0xffff;
1987 row->unused1 = 0;
1988 row->wType = MIB_IPADDR_PRIMARY;
1989 row_num++;
1993 if (sort) qsort( table->table, count, sizeof(MIB_IPADDRROW), ipaddrrow_cmp );
1994 err:
1995 NsiFreeTable( keys, rw, NULL, NULL );
1997 return err;
2001 /******************************************************************
2002 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2004 * Get interface-to-IP address mapping table.
2005 * Like GetIpAddrTable(), but allocate the returned table from heap.
2007 * PARAMS
2008 * table [Out] pointer into which the MIB_IPADDRTABLE is
2009 * allocated and returned.
2010 * sort [In] whether to sort the table
2011 * heap [In] heap from which the table is allocated
2012 * flags [In] flags to HeapAlloc
2015 DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2017 DWORD err, size = FIELD_OFFSET(MIB_IPADDRTABLE, table[2]), attempt;
2019 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2021 for (attempt = 0; attempt < 5; attempt++)
2023 *table = HeapAlloc( heap, flags, size );
2024 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2026 err = GetIpAddrTable( *table, &size, sort );
2027 if (!err) break;
2028 HeapFree( heap, flags, *table );
2029 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2032 return err;
2035 static int ipforward_row_cmp( const void *a, const void *b )
2037 const MIB_IPFORWARDROW *rowA = a, *rowB = b;
2038 return DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardDest ), RtlUlongByteSwap( rowB->dwForwardDest )) ||
2039 DWORD_cmp(rowA->dwForwardProto, rowB->dwForwardProto) ||
2040 DWORD_cmp(rowA->dwForwardPolicy, rowB->dwForwardPolicy) ||
2041 DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardNextHop ), RtlUlongByteSwap( rowB->dwForwardNextHop ));
2044 /******************************************************************
2045 * GetIpForwardTable (IPHLPAPI.@)
2047 * Get the route table.
2049 * PARAMS
2050 * table [Out] buffer for route table
2051 * size [In/Out] length of output buffer
2052 * sort [In] whether to sort the table
2054 * RETURNS
2055 * Success: NO_ERROR
2056 * Failure: error code from winerror.h
2058 DWORD WINAPI GetIpForwardTable( MIB_IPFORWARDTABLE *table, ULONG *size, BOOL sort )
2060 DWORD err, count, uni_count, needed, i, addr;
2061 struct nsi_ipv4_forward_key *keys;
2062 struct nsi_ip_forward_rw *rw;
2063 struct nsi_ipv4_forward_dynamic *dyn;
2064 struct nsi_ip_forward_static *stat;
2065 struct nsi_ipv4_unicast_key *uni_keys = NULL;
2067 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2068 if (!size) return ERROR_INVALID_PARAMETER;
2070 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, (void **)&keys, sizeof(*keys),
2071 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2072 (void **)&stat, sizeof(*stat), &count, 0 );
2073 if (err) return err;
2075 needed = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
2077 if (!table || *size < needed)
2079 *size = needed;
2080 err = ERROR_INSUFFICIENT_BUFFER;
2081 goto err;
2084 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, (void **)&uni_keys, sizeof(*uni_keys),
2085 NULL, 0, NULL, 0, NULL, 0, &uni_count, 0 );
2086 if (err) goto err;
2088 table->dwNumEntries = count;
2089 for (i = 0; i < count; i++)
2091 MIB_IPFORWARDROW *row = table->table + i;
2093 row->dwForwardDest = keys[i].prefix.s_addr;
2094 ConvertLengthToIpv4Mask( keys[i].prefix_len, &row->dwForwardMask );
2095 row->dwForwardPolicy = 0;
2096 row->dwForwardNextHop = keys[i].next_hop.s_addr;
2097 row->dwForwardType = row->dwForwardNextHop ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
2098 if (!row->dwForwardNextHop) /* find the interface's addr */
2100 for (addr = 0; addr < uni_count; addr++)
2102 if (uni_keys[addr].luid.Value == keys[i].luid.Value)
2104 row->dwForwardNextHop = uni_keys[addr].addr.s_addr;
2105 break;
2109 row->dwForwardIfIndex = stat[i].if_index;
2110 row->dwForwardProto = rw[i].protocol;
2111 row->dwForwardAge = dyn[i].age;
2112 row->dwForwardNextHopAS = 0;
2113 row->dwForwardMetric1 = rw[i].metric; /* FIXME: add interface metric */
2114 row->dwForwardMetric2 = 0;
2115 row->dwForwardMetric3 = 0;
2116 row->dwForwardMetric4 = 0;
2117 row->dwForwardMetric5 = 0;
2120 if (sort) qsort( table->table, count, sizeof(MIB_IPFORWARDROW), ipforward_row_cmp );
2121 err:
2122 NsiFreeTable( uni_keys, NULL, NULL, NULL );
2123 NsiFreeTable( keys, rw, dyn, stat );
2125 return err;
2128 /******************************************************************
2129 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2131 * Get the route table.
2132 * Like GetIpForwardTable(), but allocate the returned table from heap.
2134 * PARAMS
2135 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2136 * allocated and returned.
2137 * sort [In] whether to sort the table
2138 * heap [In] heap from which the table is allocated
2139 * flags [In] flags to HeapAlloc
2141 * RETURNS
2142 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2143 * on failure, NO_ERROR on success.
2145 DWORD WINAPI AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2147 DWORD err, size = FIELD_OFFSET(MIB_IPFORWARDTABLE, table[2]), attempt;
2149 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2151 for (attempt = 0; attempt < 5; attempt++)
2153 *table = HeapAlloc( heap, flags, size );
2154 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2156 err = GetIpForwardTable( *table, &size, sort );
2157 if (!err) break;
2158 HeapFree( heap, flags, *table );
2159 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2162 return err;
2165 static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw,
2166 void *dyn, struct nsi_ip_forward_static *stat )
2168 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key;
2169 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key;
2170 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn;
2171 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn;
2173 if (fam == AF_INET)
2175 row->InterfaceLuid = key4->luid;
2176 row->DestinationPrefix.Prefix.Ipv4.sin_family = fam;
2177 row->DestinationPrefix.Prefix.Ipv4.sin_port = 0;
2178 row->DestinationPrefix.Prefix.Ipv4.sin_addr = key4->prefix;
2179 memset( &row->DestinationPrefix.Prefix.Ipv4.sin_zero, 0, sizeof(row->DestinationPrefix.Prefix.Ipv4.sin_zero) );
2180 row->DestinationPrefix.PrefixLength = key4->prefix_len;
2181 row->NextHop.Ipv4.sin_family = fam;
2182 row->NextHop.Ipv4.sin_port = 0;
2183 row->NextHop.Ipv4.sin_addr = key4->next_hop;
2184 memset( &row->NextHop.Ipv4.sin_zero, 0, sizeof(row->NextHop.Ipv4.sin_zero) );
2186 row->Age = dyn4->age;
2188 else
2190 row->InterfaceLuid = key6->luid;
2192 row->DestinationPrefix.Prefix.Ipv6.sin6_family = fam;
2193 row->DestinationPrefix.Prefix.Ipv6.sin6_port = 0;
2194 row->DestinationPrefix.Prefix.Ipv6.sin6_flowinfo = 0;
2195 row->DestinationPrefix.Prefix.Ipv6.sin6_addr = key6->prefix;
2196 row->DestinationPrefix.Prefix.Ipv6.sin6_scope_id = 0;
2197 row->DestinationPrefix.PrefixLength = key6->prefix_len;
2198 row->NextHop.Ipv6.sin6_family = fam;
2199 row->NextHop.Ipv6.sin6_port = 0;
2200 row->NextHop.Ipv6.sin6_flowinfo = 0;
2201 row->NextHop.Ipv6.sin6_addr = key6->next_hop;
2202 row->NextHop.Ipv6.sin6_scope_id = 0;
2204 row->Age = dyn6->age;
2207 row->InterfaceIndex = stat->if_index;
2209 row->SitePrefixLength = rw->site_prefix_len;
2210 row->ValidLifetime = rw->valid_lifetime;
2211 row->PreferredLifetime = rw->preferred_lifetime;
2212 row->Metric = rw->metric;
2213 row->Protocol = rw->protocol;
2214 row->Loopback = rw->loopback;
2215 row->AutoconfigureAddress = rw->autoconf;
2216 row->Publish = rw->publish;
2217 row->Immortal = rw->immortal;
2219 row->Origin = stat->origin;
2222 /******************************************************************
2223 * GetIpForwardTable2 (IPHLPAPI.@)
2225 DWORD WINAPI GetIpForwardTable2( ADDRESS_FAMILY family, MIB_IPFORWARD_TABLE2 **table )
2227 void *key[2] = { NULL, NULL };
2228 struct nsi_ip_forward_rw *rw[2] = { NULL, NULL };
2229 void *dyn[2] = { NULL, NULL };
2230 struct nsi_ip_forward_static *stat[2] = { NULL, NULL };
2231 static const USHORT fam[2] = { AF_INET, AF_INET6 };
2232 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ipv6_forward_key) };
2233 static const DWORD dyn_size[2] = { sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ipv6_forward_dynamic) };
2234 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2236 TRACE( "%u, %p\n", family, table );
2238 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
2239 return ERROR_INVALID_PARAMETER;
2241 for (i = 0; i < 2; i++)
2243 if (family != AF_UNSPEC && family != fam[i]) continue;
2245 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_FORWARD_TABLE, key + i, key_size[i],
2246 (void **)rw + i, sizeof(**rw), dyn + i, dyn_size[i],
2247 (void **)stat + i, sizeof(**stat), count + i, 0 );
2248 if (err) count[i] = 0;
2251 size = FIELD_OFFSET(MIB_IPFORWARD_TABLE2, Table[ count[0] + count[1] ]);
2252 *table = heap_alloc( size );
2253 if (!*table)
2255 err = ERROR_NOT_ENOUGH_MEMORY;
2256 goto err;
2259 (*table)->NumEntries = count[0] + count[1];
2260 for (i = 0; i < count[0]; i++)
2262 MIB_IPFORWARD_ROW2 *row = (*table)->Table + i;
2263 struct nsi_ipv4_forward_key *key4 = (struct nsi_ipv4_forward_key *)key[0];
2264 struct nsi_ipv4_forward_dynamic *dyn4 = (struct nsi_ipv4_forward_dynamic *)dyn[0];
2266 forward_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn4 + i, stat[0] + i );
2269 for (i = 0; i < count[1]; i++)
2271 MIB_IPFORWARD_ROW2 *row = (*table)->Table + count[0] + i;
2272 struct nsi_ipv6_forward_key *key6 = (struct nsi_ipv6_forward_key *)key[1];
2273 struct nsi_ipv6_forward_dynamic *dyn6 = (struct nsi_ipv6_forward_dynamic *)dyn[1];
2275 forward_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn6 + i, stat[1] + i );
2278 err:
2279 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
2280 return err;
2283 static int ipnetrow_cmp( const void *a, const void *b )
2285 const MIB_IPNETROW *rowA = a, *rowB = b;
2287 if (rowA->dwIndex != rowB->dwIndex) return DWORD_cmp( rowA->dwIndex, rowB->dwIndex );
2289 return DWORD_cmp(RtlUlongByteSwap( rowA->dwAddr ), RtlUlongByteSwap( rowB->dwAddr ));
2292 /******************************************************************
2293 * GetIpNetTable (IPHLPAPI.@)
2295 * Get the IP-to-physical address mapping table.
2297 * PARAMS
2298 * table [Out] buffer for mapping table
2299 * size [In/Out] length of output buffer
2300 * sort [In] whether to sort the table
2302 * RETURNS
2303 * Success: NO_ERROR
2304 * Failure: error code from winerror.h
2307 DWORD WINAPI GetIpNetTable( MIB_IPNETTABLE *table, ULONG *size, BOOL sort )
2309 DWORD err, count, needed, i;
2310 struct nsi_ipv4_neighbour_key *keys;
2311 struct nsi_ip_neighbour_rw *rw;
2312 struct nsi_ip_neighbour_dynamic *dyn;
2314 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
2316 if (!size) return ERROR_INVALID_PARAMETER;
2318 err = NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID, NSI_IP_NEIGHBOUR_TABLE, (void **)&keys, sizeof(*keys),
2319 (void **)&rw, sizeof(*rw), (void **)&dyn, sizeof(*dyn),
2320 NULL, 0, &count, 0 );
2321 if (err) return err;
2323 needed = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
2325 if (!table || *size < needed)
2327 *size = needed;
2328 err = ERROR_INSUFFICIENT_BUFFER;
2329 goto err;
2332 table->dwNumEntries = count;
2334 if (!count)
2336 err = ERROR_NO_DATA;
2337 goto err;
2340 for (i = 0; i < count; i++)
2342 MIB_IPNETROW *row = table->table + i;
2344 ConvertInterfaceLuidToIndex( &keys[i].luid, &row->dwIndex );
2345 row->dwPhysAddrLen = dyn[i].phys_addr_len;
2346 if (row->dwPhysAddrLen > sizeof(row->bPhysAddr)) row->dwPhysAddrLen = 0;
2347 memcpy( row->bPhysAddr, rw[i].phys_addr, row->dwPhysAddrLen );
2348 memset( row->bPhysAddr + row->dwPhysAddrLen, 0,
2349 sizeof(row->bPhysAddr) - row->dwPhysAddrLen );
2350 row->dwAddr = keys[i].addr.s_addr;
2352 switch (dyn[i].state)
2354 case NlnsUnreachable:
2355 case NlnsIncomplete:
2356 row->Type = MIB_IPNET_TYPE_INVALID;
2357 break;
2358 case NlnsProbe:
2359 case NlnsDelay:
2360 case NlnsStale:
2361 case NlnsReachable:
2362 row->Type = MIB_IPNET_TYPE_DYNAMIC;
2363 break;
2364 case NlnsPermanent:
2365 row->Type = MIB_IPNET_TYPE_STATIC;
2366 break;
2367 default:
2368 row->Type = MIB_IPNET_TYPE_OTHER;
2372 if (sort) qsort( table->table, table->dwNumEntries, sizeof(*table->table), ipnetrow_cmp );
2374 err:
2375 NsiFreeTable( keys, rw, dyn, NULL );
2376 return err;
2379 /******************************************************************
2380 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2382 DWORD WINAPI AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
2384 DWORD err, size = FIELD_OFFSET(MIB_IPNETTABLE, table[2]), attempt;
2386 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
2388 for (attempt = 0; attempt < 5; attempt++)
2390 *table = HeapAlloc( heap, flags, size );
2391 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
2393 err = GetIpNetTable( *table, &size, sort );
2394 if (!err) break;
2395 HeapFree( heap, flags, *table );
2396 if (err != ERROR_INSUFFICIENT_BUFFER) break;
2399 return err;
2402 static void ipnet_row2_fill( MIB_IPNET_ROW2 *row, USHORT fam, void *key, struct nsi_ip_neighbour_rw *rw,
2403 struct nsi_ip_neighbour_dynamic *dyn )
2405 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key;
2406 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key;
2408 if (fam == AF_INET)
2410 row->Address.Ipv4.sin_family = fam;
2411 row->Address.Ipv4.sin_port = 0;
2412 row->Address.Ipv4.sin_addr = key4->addr;
2413 memset( &row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
2414 row->InterfaceLuid = key4->luid;
2416 else
2418 row->Address.Ipv6.sin6_family = fam;
2419 row->Address.Ipv6.sin6_port = 0;
2420 row->Address.Ipv6.sin6_flowinfo = 0;
2421 row->Address.Ipv6.sin6_addr = key6->addr;
2422 row->Address.Ipv6.sin6_scope_id = 0;
2423 row->InterfaceLuid = key6->luid;
2426 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
2428 row->PhysicalAddressLength = dyn->phys_addr_len;
2429 if (row->PhysicalAddressLength > sizeof(row->PhysicalAddress))
2430 row->PhysicalAddressLength = 0;
2431 memcpy( row->PhysicalAddress, rw->phys_addr, row->PhysicalAddressLength );
2432 memset( row->PhysicalAddress + row->PhysicalAddressLength, 0,
2433 sizeof(row->PhysicalAddress) - row->PhysicalAddressLength );
2434 row->State = dyn->state;
2435 row->Flags = 0;
2436 row->IsRouter = dyn->flags.is_router;
2437 row->IsUnreachable = dyn->flags.is_unreachable;
2438 row->ReachabilityTime.LastReachable = dyn->time;
2441 /******************************************************************
2442 * GetIpNetTable2 (IPHLPAPI.@)
2444 DWORD WINAPI GetIpNetTable2( ADDRESS_FAMILY family, MIB_IPNET_TABLE2 **table )
2446 void *key[2] = { NULL, NULL };
2447 struct nsi_ip_neighbour_rw *rw[2] = { NULL, NULL };
2448 struct nsi_ip_neighbour_dynamic *dyn[2] = { NULL, NULL };
2449 static const USHORT fam[2] = { AF_INET, AF_INET6 };
2450 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ipv6_neighbour_key) };
2451 DWORD err = ERROR_SUCCESS, i, size, count[2] = { 0, 0 };
2453 TRACE( "%u, %p\n", family, table );
2455 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
2456 return ERROR_INVALID_PARAMETER;
2458 for (i = 0; i < 2; i++)
2460 if (family != AF_UNSPEC && family != fam[i]) continue;
2462 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_NEIGHBOUR_TABLE, key + i, key_size[i],
2463 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
2464 NULL, 0, count + i, 0 );
2465 if (err) count[i] = 0;
2468 size = FIELD_OFFSET(MIB_IPNET_TABLE2, Table[ count[0] + count[1] ]);
2469 *table = heap_alloc( size );
2470 if (!*table)
2472 err = ERROR_NOT_ENOUGH_MEMORY;
2473 goto err;
2476 (*table)->NumEntries = count[0] + count[1];
2477 for (i = 0; i < count[0]; i++)
2479 MIB_IPNET_ROW2 *row = (*table)->Table + i;
2480 struct nsi_ipv4_neighbour_key *key4 = (struct nsi_ipv4_neighbour_key *)key[0];
2482 ipnet_row2_fill( row, fam[0], key4 + i, rw[0] + i, dyn[0] + i );
2485 for (i = 0; i < count[1]; i++)
2487 MIB_IPNET_ROW2 *row = (*table)->Table + count[0] + i;
2488 struct nsi_ipv6_neighbour_key *key6 = (struct nsi_ipv6_neighbour_key *)key[1];
2490 ipnet_row2_fill( row, fam[1], key6 + i, rw[1] + i, dyn[1] + i );
2493 err:
2494 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], NULL );
2495 return err;
2498 /******************************************************************
2499 * GetIpStatistics (IPHLPAPI.@)
2501 * Get the IP statistics for the local computer.
2503 * PARAMS
2504 * stats [Out] buffer for IP statistics
2506 * RETURNS
2507 * Success: NO_ERROR
2508 * Failure: error code from winerror.h
2510 DWORD WINAPI GetIpStatistics( MIB_IPSTATS *stats )
2512 return GetIpStatisticsEx( stats, AF_INET );
2515 /******************************************************************
2516 * GetIpStatisticsEx (IPHLPAPI.@)
2518 * Get the IPv4 and IPv6 statistics for the local computer.
2520 * PARAMS
2521 * stats [Out] buffer for IP statistics
2522 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2524 * RETURNS
2525 * Success: NO_ERROR
2526 * Failure: error code from winerror.h
2528 DWORD WINAPI GetIpStatisticsEx( MIB_IPSTATS *stats, DWORD family )
2530 struct nsi_ip_ipstats_dynamic dyn;
2531 struct nsi_ip_ipstats_static stat;
2532 struct nsi_ip_cmpt_rw cmpt_rw;
2533 struct nsi_ip_cmpt_dynamic cmpt_dyn;
2534 const NPI_MODULEID *mod;
2535 DWORD err, cmpt = 1;
2537 TRACE( "%p %ld\n", stats, family );
2539 if (!stats) return ERROR_INVALID_PARAMETER;
2540 mod = ip_module_id( family );
2541 if (!mod) return ERROR_INVALID_PARAMETER;
2543 memset( stats, 0, sizeof(*stats) );
2545 err = NsiGetAllParameters( 1, mod, NSI_IP_IPSTATS_TABLE, NULL, 0, NULL, 0,
2546 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2547 if (err) return err;
2549 err = NsiGetAllParameters( 1, mod, NSI_IP_COMPARTMENT_TABLE, &cmpt, sizeof(cmpt), &cmpt_rw, sizeof(cmpt_rw),
2550 &cmpt_dyn, sizeof(cmpt_dyn), NULL, 0 );
2551 if (err) return err;
2553 stats->Forwarding = cmpt_rw.not_forwarding + 1;
2554 stats->dwDefaultTTL = cmpt_rw.default_ttl;
2555 stats->dwInReceives = dyn.in_recv;
2556 stats->dwInHdrErrors = dyn.in_hdr_errs;
2557 stats->dwInAddrErrors = dyn.in_addr_errs;
2558 stats->dwForwDatagrams = dyn.fwd_dgrams;
2559 stats->dwInUnknownProtos = dyn.in_unk_protos;
2560 stats->dwInDiscards = dyn.in_discards;
2561 stats->dwInDelivers = dyn.in_delivers;
2562 stats->dwOutRequests = dyn.out_reqs;
2563 stats->dwRoutingDiscards = dyn.routing_discards;
2564 stats->dwOutDiscards = dyn.out_discards;
2565 stats->dwOutNoRoutes = dyn.out_no_routes;
2566 stats->dwReasmTimeout = stat.reasm_timeout;
2567 stats->dwReasmReqds = dyn.reasm_reqds;
2568 stats->dwReasmOks = dyn.reasm_oks;
2569 stats->dwReasmFails = dyn.reasm_fails;
2570 stats->dwFragOks = dyn.frag_oks;
2571 stats->dwFragFails = dyn.frag_fails;
2572 stats->dwFragCreates = dyn.frag_creates;
2573 stats->dwNumIf = cmpt_dyn.num_ifs;
2574 stats->dwNumAddr = cmpt_dyn.num_addrs;
2575 stats->dwNumRoutes = cmpt_dyn.num_routes;
2577 return err;
2580 /* Gets the DNS server list into the list beginning at list. Assumes that
2581 * a single server address may be placed at list if *len is at least
2582 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2583 * and assumes that all remaining DNS servers are contiguously located
2584 * beginning at second. On input, *len is assumed to be the total number
2585 * of bytes available for all DNS servers, and is ignored if list is NULL.
2586 * On return, *len is set to the total number of bytes required for all DNS
2587 * servers.
2588 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2589 * ERROR_SUCCESS otherwise.
2591 static DWORD get_dns_server_list( const NET_LUID *luid, IP_ADDR_STRING *list, IP_ADDR_STRING *second, DWORD *len )
2593 char buf[FIELD_OFFSET(IP4_ARRAY, AddrArray[3])];
2594 IP4_ARRAY *servers = (IP4_ARRAY *)buf;
2595 DWORD needed, num, err, i, array_len = sizeof(buf);
2596 IP_ADDR_STRING *ptr;
2598 if (luid && luid->Info.IfType == MIB_IF_TYPE_LOOPBACK) return ERROR_NO_DATA;
2600 for (;;)
2602 err = DnsQueryConfig( DnsConfigDnsServerList, 0, NULL, NULL, servers, &array_len );
2603 if (err != ERROR_SUCCESS && err != ERROR_MORE_DATA) goto err;
2604 num = (array_len - FIELD_OFFSET(IP4_ARRAY, AddrArray[0])) / sizeof(IP4_ADDRESS);
2605 needed = num * sizeof(IP_ADDR_STRING);
2606 if (!list || *len < needed)
2608 *len = needed;
2609 err = ERROR_BUFFER_OVERFLOW;
2610 goto err;
2612 if (!err) break;
2614 if ((char *)servers != buf) heap_free( servers );
2615 servers = heap_alloc( array_len );
2616 if (!servers)
2618 err = ERROR_NOT_ENOUGH_MEMORY;
2619 goto err;
2623 *len = needed;
2625 for (i = 0, ptr = list; i < num; i++, ptr = ptr->Next)
2627 RtlIpv4AddressToStringA( (IN_ADDR *)&servers->AddrArray[i], ptr->IpAddress.String );
2628 if (i == num - 1) ptr->Next = NULL;
2629 else if (i == 0) ptr->Next = second;
2630 else ptr->Next = ptr + 1;
2633 err:
2634 if ((char *)servers != buf) heap_free( servers );
2635 return err;
2638 /******************************************************************
2639 * GetNetworkParams (IPHLPAPI.@)
2641 * Get the network parameters for the local computer.
2643 * PARAMS
2644 * info [Out] buffer for network parameters
2645 * size [In/Out] length of output buffer
2647 * RETURNS
2648 * Success: NO_ERROR
2649 * Failure: error code from winerror.h
2651 * NOTES
2652 * If size is less than required, the function will return
2653 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2654 * size.
2656 DWORD WINAPI GetNetworkParams( FIXED_INFO *info, ULONG *size )
2658 DWORD needed = sizeof(*info), dns_size, err;
2659 MIB_IPSTATS ip_stats;
2660 HKEY key;
2662 TRACE( "info %p, size %p\n", info, size );
2663 if (!size) return ERROR_INVALID_PARAMETER;
2665 if (get_dns_server_list( NULL, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2666 needed += dns_size - sizeof(IP_ADDR_STRING);
2667 if (!info || *size < needed)
2669 *size = needed;
2670 return ERROR_BUFFER_OVERFLOW;
2673 *size = needed;
2674 memset( info, 0, needed );
2675 needed = sizeof(info->HostName);
2676 GetComputerNameExA( ComputerNameDnsHostname, info->HostName, &needed );
2677 needed = sizeof(info->DomainName);
2678 GetComputerNameExA( ComputerNameDnsDomain, info->DomainName, &needed );
2679 get_dns_server_list( NULL, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2680 info->CurrentDnsServer = &info->DnsServerList;
2681 info->NodeType = HYBRID_NODETYPE;
2682 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2683 0, KEY_READ, &key );
2684 if (err)
2685 err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2686 0, KEY_READ, &key );
2687 if (!err)
2689 needed = sizeof(info->ScopeId);
2690 RegQueryValueExA( key, "ScopeID", NULL, NULL, (BYTE *)info->ScopeId, &needed );
2691 RegCloseKey( key );
2694 if (!GetIpStatistics( &ip_stats ))
2695 info->EnableRouting = (ip_stats.Forwarding == MIB_IP_FORWARDING);
2697 return ERROR_SUCCESS;
2701 /******************************************************************
2702 * GetNumberOfInterfaces (IPHLPAPI.@)
2704 * Get the number of interfaces.
2706 * PARAMS
2707 * pdwNumIf [Out] number of interfaces
2709 * RETURNS
2710 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2712 DWORD WINAPI GetNumberOfInterfaces( DWORD *count )
2714 DWORD err, num;
2716 TRACE( "count %p\n", count );
2717 if (!count) return ERROR_INVALID_PARAMETER;
2719 err = NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0,
2720 NULL, 0, NULL, 0, NULL, 0, &num );
2721 *count = err ? 0 : num;
2722 return err;
2725 /******************************************************************
2726 * GetPerAdapterInfo (IPHLPAPI.@)
2728 * Get information about an adapter corresponding to an interface.
2730 * PARAMS
2731 * IfIndex [In] interface info
2732 * pPerAdapterInfo [Out] buffer for per adapter info
2733 * pOutBufLen [In/Out] length of output buffer
2735 * RETURNS
2736 * Success: NO_ERROR
2737 * Failure: error code from winerror.h
2739 DWORD WINAPI GetPerAdapterInfo( ULONG index, IP_PER_ADAPTER_INFO *info, ULONG *size )
2741 DWORD needed = sizeof(*info), dns_size;
2742 NET_LUID luid;
2744 TRACE( "(index %ld, info %p, size %p)\n", index, info, size );
2746 if (!size) return ERROR_INVALID_PARAMETER;
2747 if (ConvertInterfaceIndexToLuid( index, &luid )) return ERROR_NO_DATA;
2749 if (get_dns_server_list( &luid, NULL, NULL, &dns_size ) == ERROR_BUFFER_OVERFLOW)
2750 needed += dns_size - sizeof(IP_ADDR_STRING);
2752 if (!info || *size < needed)
2754 *size = needed;
2755 return ERROR_BUFFER_OVERFLOW;
2758 memset( info, 0, needed );
2759 get_dns_server_list( &luid, &info->DnsServerList, (IP_ADDR_STRING *)(info + 1), &dns_size );
2760 info->CurrentDnsServer = &info->DnsServerList;
2762 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2763 return ERROR_SUCCESS;
2767 /******************************************************************
2768 * GetRTTAndHopCount (IPHLPAPI.@)
2770 * Get round-trip time (RTT) and hop count.
2772 * PARAMS
2774 * DestIpAddress [In] destination address to get the info for
2775 * HopCount [Out] retrieved hop count
2776 * MaxHops [In] maximum hops to search for the destination
2777 * RTT [Out] RTT in milliseconds
2779 * RETURNS
2780 * Success: TRUE
2781 * Failure: FALSE
2783 * FIXME
2784 * Stub, returns FALSE.
2786 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2788 FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
2789 DestIpAddress, HopCount, MaxHops, RTT);
2790 return FALSE;
2793 /******************************************************************
2794 * GetTcpStatistics (IPHLPAPI.@)
2796 * Get the TCP statistics for the local computer.
2798 * PARAMS
2799 * stats [Out] buffer for TCP statistics
2801 * RETURNS
2802 * Success: NO_ERROR
2803 * Failure: error code from winerror.h
2805 DWORD WINAPI GetTcpStatistics( MIB_TCPSTATS *stats )
2807 return GetTcpStatisticsEx( stats, AF_INET );
2810 /******************************************************************
2811 * GetTcpStatisticsEx (IPHLPAPI.@)
2813 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2815 * PARAMS
2816 * stats [Out] buffer for TCP statistics
2817 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2819 * RETURNS
2820 * Success: NO_ERROR
2821 * Failure: error code from winerror.h
2823 DWORD WINAPI GetTcpStatisticsEx( MIB_TCPSTATS *stats, DWORD family )
2825 struct nsi_tcp_stats_dynamic dyn;
2826 struct nsi_tcp_stats_static stat;
2827 USHORT key = (USHORT)family;
2828 DWORD err;
2830 if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
2831 memset( stats, 0, sizeof(*stats) );
2833 err = NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID, NSI_TCP_STATS_TABLE, &key, sizeof(key), NULL, 0,
2834 &dyn, sizeof(dyn), &stat, sizeof(stat) );
2835 if (err) return err;
2837 stats->RtoAlgorithm = stat.rto_algo;
2838 stats->dwRtoMin = stat.rto_min;
2839 stats->dwRtoMax = stat.rto_max;
2840 stats->dwMaxConn = stat.max_conns;
2841 stats->dwActiveOpens = dyn.active_opens;
2842 stats->dwPassiveOpens = dyn.passive_opens;
2843 stats->dwAttemptFails = dyn.attempt_fails;
2844 stats->dwEstabResets = dyn.est_rsts;
2845 stats->dwCurrEstab = dyn.cur_est;
2846 stats->dwInSegs = (DWORD)dyn.in_segs;
2847 stats->dwOutSegs = (DWORD)dyn.out_segs;
2848 stats->dwRetransSegs = dyn.retrans_segs;
2849 stats->dwInErrs = dyn.in_errs;
2850 stats->dwOutRsts = dyn.out_rsts;
2851 stats->dwNumConns = dyn.num_conns;
2853 return err;
2856 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2858 static DWORD tcp_table_id( ULONG table_class )
2860 switch (table_class)
2862 case TCP_TABLE_BASIC_LISTENER:
2863 case TCP_TABLE_OWNER_PID_LISTENER:
2864 case TCP_TABLE_OWNER_MODULE_LISTENER:
2865 return NSI_TCP_LISTEN_TABLE;
2867 case TCP_TABLE_BASIC_CONNECTIONS:
2868 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2869 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2870 return NSI_TCP_ESTAB_TABLE;
2872 case TCP_TABLE_BASIC_ALL:
2873 case TCP_TABLE_OWNER_PID_ALL:
2874 case TCP_TABLE_OWNER_MODULE_ALL:
2875 case TCP_TABLE2:
2876 return NSI_TCP_ALL_TABLE;
2878 default:
2879 ERR( "unhandled class %lu\n", table_class );
2880 return ~0u;
2884 static DWORD tcp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
2886 switch (table_class)
2888 case TCP_TABLE_BASIC_LISTENER:
2889 case TCP_TABLE_BASIC_CONNECTIONS:
2890 case TCP_TABLE_BASIC_ALL:
2891 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW) : sizeof(MIB_TCP6ROW);
2892 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE, table[row_count]) :
2893 FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
2895 case TCP_TABLE_OWNER_PID_LISTENER:
2896 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2897 case TCP_TABLE_OWNER_PID_ALL:
2898 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW_OWNER_PID) : sizeof(MIB_TCP6ROW_OWNER_PID);
2899 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]) :
2900 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
2902 case TCP_TABLE_OWNER_MODULE_LISTENER:
2903 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2904 case TCP_TABLE_OWNER_MODULE_ALL:
2905 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW_OWNER_MODULE) : sizeof(MIB_TCP6ROW_OWNER_MODULE);
2906 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]) :
2907 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
2909 case TCP_TABLE2:
2910 *row_size = (family == AF_INET) ? sizeof(MIB_TCPROW2) : sizeof(MIB_TCP6ROW2);
2911 return (family == AF_INET) ? FIELD_OFFSET(MIB_TCPTABLE2, table[row_count]) :
2912 FIELD_OFFSET(MIB_TCP6TABLE2, table[row_count]);
2914 default:
2915 ERR( "unhandled class %lu\n", table_class );
2916 return 0;
2920 static void tcp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
2921 struct nsi_tcp_conn_key *key, struct nsi_tcp_conn_dynamic *dyn,
2922 struct nsi_tcp_conn_static *stat )
2924 if (family == AF_INET)
2926 switch (table_class)
2928 case TCP_TABLE_BASIC_LISTENER:
2929 case TCP_TABLE_BASIC_CONNECTIONS:
2930 case TCP_TABLE_BASIC_ALL:
2932 MIB_TCPROW *row = ((MIB_TCPTABLE *)table)->table + num;
2933 row->dwState = dyn->state;
2934 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2935 row->dwLocalPort = key->local.Ipv4.sin_port;
2936 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2937 row->dwRemotePort = key->remote.Ipv4.sin_port;
2938 return;
2940 case TCP_TABLE_OWNER_PID_LISTENER:
2941 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2942 case TCP_TABLE_OWNER_PID_ALL:
2944 MIB_TCPROW_OWNER_PID *row = ((MIB_TCPTABLE_OWNER_PID *)table)->table + num;
2945 row->dwState = dyn->state;
2946 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2947 row->dwLocalPort = key->local.Ipv4.sin_port;
2948 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2949 row->dwRemotePort = key->remote.Ipv4.sin_port;
2950 row->dwOwningPid = stat->pid;
2951 return;
2953 case TCP_TABLE_OWNER_MODULE_LISTENER:
2954 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2955 case TCP_TABLE_OWNER_MODULE_ALL:
2957 MIB_TCPROW_OWNER_MODULE *row = ((MIB_TCPTABLE_OWNER_MODULE *)table)->table + num;
2958 row->dwState = dyn->state;
2959 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2960 row->dwLocalPort = key->local.Ipv4.sin_port;
2961 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2962 row->dwRemotePort = key->remote.Ipv4.sin_port;
2963 row->dwOwningPid = stat->pid;
2964 row->liCreateTimestamp.QuadPart = stat->create_time;
2965 row->OwningModuleInfo[0] = stat->mod_info;
2966 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
2967 return;
2969 case TCP_TABLE2:
2971 MIB_TCPROW2 *row = ((MIB_TCPTABLE2 *)table)->table + num;
2972 row->dwState = dyn->state;
2973 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
2974 row->dwLocalPort = key->local.Ipv4.sin_port;
2975 row->dwRemoteAddr = key->remote.Ipv4.sin_addr.s_addr;
2976 row->dwRemotePort = key->remote.Ipv4.sin_port;
2977 row->dwOwningPid = stat->pid;
2978 row->dwOffloadState = 0; /* FIXME */
2979 return;
2981 default:
2982 ERR( "Unknown class %ld\n", table_class );
2983 return;
2986 else
2988 switch (table_class)
2990 case TCP_TABLE_BASIC_LISTENER:
2991 case TCP_TABLE_BASIC_CONNECTIONS:
2992 case TCP_TABLE_BASIC_ALL:
2994 MIB_TCP6ROW *row = ((MIB_TCP6TABLE *)table)->table + num;
2995 row->State = dyn->state;
2996 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
2997 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
2998 row->dwLocalPort = key->local.Ipv6.sin6_port;
2999 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
3000 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3001 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3002 return;
3004 case TCP_TABLE_OWNER_PID_LISTENER:
3005 case TCP_TABLE_OWNER_PID_CONNECTIONS:
3006 case TCP_TABLE_OWNER_PID_ALL:
3008 MIB_TCP6ROW_OWNER_PID *row = ((MIB_TCP6TABLE_OWNER_PID *)table)->table + num;
3009 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3010 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3011 row->dwLocalPort = key->local.Ipv6.sin6_port;
3012 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3013 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3014 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3015 row->dwState = dyn->state;
3016 row->dwOwningPid = stat->pid;
3017 return;
3019 case TCP_TABLE_OWNER_MODULE_LISTENER:
3020 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
3021 case TCP_TABLE_OWNER_MODULE_ALL:
3023 MIB_TCP6ROW_OWNER_MODULE *row = ((MIB_TCP6TABLE_OWNER_MODULE *)table)->table + num;
3024 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3025 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3026 row->dwLocalPort = key->local.Ipv6.sin6_port;
3027 memcpy( &row->ucRemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->ucRemoteAddr) );
3028 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3029 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3030 row->dwState = dyn->state;
3031 row->dwOwningPid = stat->pid;
3032 row->liCreateTimestamp.QuadPart = stat->create_time;
3033 row->OwningModuleInfo[0] = stat->mod_info;
3034 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3035 return;
3037 case TCP_TABLE2:
3039 MIB_TCP6ROW2 *row = ((MIB_TCP6TABLE2 *)table)->table + num;
3040 memcpy( &row->LocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->LocalAddr) );
3041 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3042 row->dwLocalPort = key->local.Ipv6.sin6_port;
3043 memcpy( &row->RemoteAddr, &key->remote.Ipv6.sin6_addr, sizeof(row->RemoteAddr) );
3044 row->dwRemoteScopeId = key->remote.Ipv6.sin6_scope_id;
3045 row->dwRemotePort = key->remote.Ipv6.sin6_port;
3046 row->State = dyn->state;
3047 row->dwOwningPid = stat->pid;
3048 row->dwOffloadState = 0; /* FIXME */
3049 return;
3051 default:
3052 ERR( "Unknown class %ld\n", table_class );
3053 return;
3056 ERR( "Unknown family %ld\n", family );
3059 static int tcp_row_cmp( const void *a, const void *b )
3061 const MIB_TCPROW *rowA = a, *rowB = b;
3062 int ret;
3064 if ((ret = DWORD_cmp(RtlUshortByteSwap( rowA->dwLocalAddr ), RtlUshortByteSwap( rowB->dwLocalAddr ))) != 0) return ret;
3065 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3066 if ((ret = DWORD_cmp(RtlUshortByteSwap( rowA->dwRemoteAddr ), RtlUshortByteSwap( rowB->dwRemoteAddr ))) != 0) return ret;
3067 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3070 static int tcp6_row_basic_cmp( const void *a, const void *b )
3072 const MIB_TCP6ROW *rowA = a;
3073 const MIB_TCP6ROW *rowB = b;
3074 int ret;
3076 if ((ret = memcmp( &rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr) )) != 0) return ret;
3077 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3078 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3079 if ((ret = memcmp( &rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr) )) != 0) return ret;
3080 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3081 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3084 static int tcp6_row_owner_cmp( const void *a, const void *b )
3086 const MIB_TCP6ROW_OWNER_PID *rowA = a;
3087 const MIB_TCP6ROW_OWNER_PID *rowB = b;
3088 int ret;
3090 if ((ret = memcmp( &rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr) )) != 0) return ret;
3091 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3092 if ((ret = RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort )) != 0) return ret;
3093 if ((ret = memcmp( &rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr) )) != 0) return ret;
3094 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
3095 return RtlUshortByteSwap( rowA->dwRemotePort ) - RtlUshortByteSwap( rowB->dwRemotePort );
3098 static BOOL tcp_table_needs_pids( ULONG table_class )
3100 switch (table_class)
3102 case TCP_TABLE_BASIC_LISTENER:
3103 case TCP_TABLE_BASIC_CONNECTIONS:
3104 case TCP_TABLE_BASIC_ALL:
3105 return FALSE;
3108 return TRUE;
3111 /*************************************************************************************
3112 * get_extended_tcp_table
3114 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3115 * corresponding to GetTcp(6)Table2()
3117 static DWORD get_extended_tcp_table( void *table, DWORD *size, BOOL sort, ULONG family, ULONG table_class )
3119 DWORD err, count, needed, i, num = 0, row_size = 0;
3120 struct nsi_tcp_conn_key *key;
3121 struct nsi_tcp_conn_dynamic *dyn;
3122 struct nsi_tcp_conn_static *stat = NULL;
3124 if (!size) return ERROR_INVALID_PARAMETER;
3126 if (tcp_table_needs_pids( table_class ))
3127 err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
3128 NULL, 0, (void **)&dyn, sizeof(*dyn),
3129 (void **)&stat, sizeof(*stat), &count, 0 );
3130 else /* Don't retrieve the static data if not required as this is expensive to compute */
3131 err = NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID, tcp_table_id( table_class ), (void **)&key, sizeof(*key),
3132 NULL, 0, (void **)&dyn, sizeof(*dyn),
3133 NULL, 0, &count, 0 );
3135 if (err) return err;
3137 for (i = 0; i < count; i++)
3138 if (key[i].local.si_family == family)
3139 num++;
3141 needed = tcp_table_size( family, table_class, num, &row_size );
3142 if (!table || *size < needed)
3144 *size = needed;
3145 err = ERROR_INSUFFICIENT_BUFFER;
3147 else
3149 *size = needed;
3150 *(DWORD *)table = num;
3151 num = 0;
3152 for (i = 0; i < count; i++)
3154 if (key[i].local.si_family != family) continue;
3155 tcp_row_fill( table, num++, family, table_class, key + i, dyn + i, stat + i );
3159 if (!err && sort)
3161 int (*fn)(const void *, const void *);
3162 DWORD offset;
3164 if (family == AF_INET) fn = tcp_row_cmp;
3165 else if (row_size == sizeof(MIB_TCP6ROW)) fn = tcp6_row_basic_cmp;
3166 else fn = tcp6_row_owner_cmp;
3168 offset = tcp_table_size( family, table_class, 0, &row_size );
3169 qsort( (BYTE *)table + offset, num, row_size, fn );
3172 NsiFreeTable( key, NULL, dyn, stat );
3173 return err;
3176 /******************************************************************
3177 * GetExtendedTcpTable (IPHLPAPI.@)
3179 DWORD WINAPI GetExtendedTcpTable( void *table, DWORD *size, BOOL sort, ULONG family,
3180 TCP_TABLE_CLASS table_class, ULONG reserved )
3182 TRACE( "table %p, size %p, sort %d, family %lu, class %u, reserved %lu\n",
3183 table, size, sort, family, table_class, reserved );
3185 if (!ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3186 return get_extended_tcp_table( table, size, sort, family, table_class );
3189 /******************************************************************
3190 * GetTcpTable (IPHLPAPI.@)
3192 * Get the table of active TCP connections.
3194 * PARAMS
3195 * table [Out] buffer for TCP connections table
3196 * size [In/Out] length of output buffer
3197 * sort [In] whether to order the table
3199 * RETURNS
3200 * Success: NO_ERROR
3201 * Failure: error code from winerror.h
3203 * NOTES
3204 * If size is less than required, the function will return
3205 * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
3206 * the required byte size.
3207 * If sort is true, the returned table will be sorted, first by
3208 * local address and port number, then by remote address and port
3209 * number.
3211 DWORD WINAPI GetTcpTable( MIB_TCPTABLE *table, DWORD *size, BOOL sort )
3213 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3214 return get_extended_tcp_table( table, size, sort, AF_INET, TCP_TABLE_BASIC_ALL );
3217 /******************************************************************
3218 * GetTcp6Table (IPHLPAPI.@)
3220 ULONG WINAPI GetTcp6Table( MIB_TCP6TABLE *table, ULONG *size, BOOL sort )
3222 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3223 return get_extended_tcp_table( table, size, sort, AF_INET6, TCP_TABLE_BASIC_ALL );
3226 /******************************************************************
3227 * GetTcpTable2 (IPHLPAPI.@)
3229 ULONG WINAPI GetTcpTable2( MIB_TCPTABLE2 *table, ULONG *size, BOOL sort )
3231 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3232 return get_extended_tcp_table( table, size, sort, AF_INET, TCP_TABLE2 );
3235 /******************************************************************
3236 * GetTcp6Table2 (IPHLPAPI.@)
3238 ULONG WINAPI GetTcp6Table2( MIB_TCP6TABLE2 *table, ULONG *size, BOOL sort )
3240 TRACE( "table %p, size %p, sort %d\n", table, size, sort );
3241 return get_extended_tcp_table( table, size, sort, AF_INET6, TCP_TABLE2 );
3244 static DWORD allocate_tcp_table( void **table, BOOL sort, HANDLE heap, DWORD flags,
3245 ULONG family, ULONG table_class )
3247 DWORD err, size = 0x100, attempt;
3249 for (attempt = 0; attempt < 5; attempt++)
3251 *table = HeapAlloc( heap, flags, size );
3252 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
3253 err = get_extended_tcp_table( *table, &size, sort, family, table_class );
3254 if (!err) break;
3255 HeapFree( heap, flags, *table );
3256 *table = NULL;
3257 if (err != ERROR_INSUFFICIENT_BUFFER) break;
3259 return err;
3262 /******************************************************************
3263 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
3265 DWORD WINAPI AllocateAndGetTcpTableFromStack( MIB_TCPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
3267 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
3269 if (!table) return ERROR_INVALID_PARAMETER;
3271 return allocate_tcp_table( (void **)table, sort, heap, flags, AF_INET, TCP_TABLE_BASIC_ALL );
3274 /******************************************************************
3275 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
3277 DWORD WINAPI AllocateAndGetTcpExTableFromStack( void **table, BOOL sort, HANDLE heap, DWORD flags, DWORD family )
3279 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx, family %lu\n", table, sort, heap, flags, family );
3281 if (!table || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3282 if (family == AF_INET6) return ERROR_NOT_SUPPORTED;
3284 return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
3287 /******************************************************************
3288 * GetUdpStatistics (IPHLPAPI.@)
3290 * Get the UDP statistics for the local computer.
3292 * PARAMS
3293 * stats [Out] buffer for UDP statistics
3295 DWORD WINAPI GetUdpStatistics( MIB_UDPSTATS *stats )
3297 return GetUdpStatisticsEx( stats, AF_INET );
3300 /******************************************************************
3301 * GetUdpStatisticsEx (IPHLPAPI.@)
3303 * Get the IPv4 and IPv6 UDP statistics for the local computer.
3305 * PARAMS
3306 * stats [Out] buffer for UDP statistics
3307 * family [In] specifies whether IPv4 or IPv6 statistics are returned
3309 * RETURNS
3310 * Success: NO_ERROR
3311 * Failure: error code from winerror.h
3313 DWORD WINAPI GetUdpStatisticsEx( MIB_UDPSTATS *stats, DWORD family )
3315 struct nsi_udp_stats_dynamic dyn;
3316 USHORT key = (USHORT)family;
3317 DWORD err;
3319 if (!stats || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3320 memset( stats, 0, sizeof(*stats) );
3322 err = NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_STATS_TABLE, &key, sizeof(key), NULL, 0,
3323 &dyn, sizeof(dyn), NULL, 0 );
3324 if (err) return err;
3326 stats->dwInDatagrams = dyn.in_dgrams;
3327 stats->dwNoPorts = dyn.no_ports;
3328 stats->dwInErrors = dyn.in_errs;
3329 stats->dwOutDatagrams = dyn.out_dgrams;
3330 stats->dwNumAddrs = dyn.num_addrs;
3331 return err;
3334 /******************************************************************
3335 * GetUdpTable (IPHLPAPI.@)
3337 * Get a table of active UDP connections.
3339 * PARAMS
3340 * table [Out] buffer for UDP connections table
3341 * size [In/Out] length of output buffer
3342 * sort [In] whether to order the table
3345 DWORD WINAPI GetUdpTable( MIB_UDPTABLE *table, DWORD *size, BOOL sort )
3347 return GetExtendedUdpTable( table, size, sort, AF_INET, UDP_TABLE_BASIC, 0 );
3350 /******************************************************************
3351 * GetUdp6Table (IPHLPAPI.@)
3353 DWORD WINAPI GetUdp6Table( MIB_UDP6TABLE *table, DWORD *size, BOOL sort )
3355 return GetExtendedUdpTable( table, size, sort, AF_INET6, UDP_TABLE_BASIC, 0 );
3358 static DWORD udp_table_size( ULONG family, ULONG table_class, DWORD row_count, DWORD *row_size )
3360 switch (table_class)
3362 case UDP_TABLE_BASIC:
3363 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW) : sizeof(MIB_UDP6ROW);
3364 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE, table[row_count]) :
3365 FIELD_OFFSET(MIB_UDP6TABLE, table[row_count]);
3367 case UDP_TABLE_OWNER_PID:
3368 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW_OWNER_PID) : sizeof(MIB_UDP6ROW_OWNER_PID);
3369 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]) :
3370 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID, table[row_count]);
3372 case UDP_TABLE_OWNER_MODULE:
3373 *row_size = (family == AF_INET) ? sizeof(MIB_UDPROW_OWNER_MODULE) : sizeof(MIB_UDP6ROW_OWNER_MODULE);
3374 return (family == AF_INET) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]) :
3375 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE, table[row_count]);
3377 default:
3378 ERR( "unhandled class %lu\n", table_class );
3379 return 0;
3383 static void udp_row_fill( void *table, DWORD num, ULONG family, ULONG table_class,
3384 struct nsi_udp_endpoint_key *key,
3385 struct nsi_udp_endpoint_static *stat )
3387 if (family == AF_INET)
3389 switch (table_class)
3391 case UDP_TABLE_BASIC:
3393 MIB_UDPROW *row = ((MIB_UDPTABLE *)table)->table + num;
3394 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3395 row->dwLocalPort = key->local.Ipv4.sin_port;
3396 return;
3398 case UDP_TABLE_OWNER_PID:
3400 MIB_UDPROW_OWNER_PID *row = ((MIB_UDPTABLE_OWNER_PID *)table)->table + num;
3401 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3402 row->dwLocalPort = key->local.Ipv4.sin_port;
3403 row->dwOwningPid = stat->pid;
3404 return;
3406 case UDP_TABLE_OWNER_MODULE:
3408 MIB_UDPROW_OWNER_MODULE *row = ((MIB_UDPTABLE_OWNER_MODULE *)table)->table + num;
3409 row->dwLocalAddr = key->local.Ipv4.sin_addr.s_addr;
3410 row->dwLocalPort = key->local.Ipv4.sin_port;
3411 row->dwOwningPid = stat->pid;
3412 row->liCreateTimestamp.QuadPart = stat->create_time;
3413 row->dwFlags = stat->flags;
3414 row->OwningModuleInfo[0] = stat->mod_info;
3415 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3416 return;
3418 default:
3419 ERR( "Unknown class %ld\n", table_class );
3420 return;
3423 else
3425 switch (table_class)
3427 case UDP_TABLE_BASIC:
3429 MIB_UDP6ROW *row = ((MIB_UDP6TABLE *)table)->table + num;
3430 memcpy( &row->dwLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->dwLocalAddr) );
3431 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3432 row->dwLocalPort = key->local.Ipv6.sin6_port;
3433 return;
3435 case UDP_TABLE_OWNER_PID:
3437 MIB_UDP6ROW_OWNER_PID *row = ((MIB_UDP6TABLE_OWNER_PID *)table)->table + num;
3438 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3439 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3440 row->dwLocalPort = key->local.Ipv6.sin6_port;
3441 row->dwOwningPid = stat->pid;
3442 return;
3444 case UDP_TABLE_OWNER_MODULE:
3446 MIB_UDP6ROW_OWNER_MODULE *row = ((MIB_UDP6TABLE_OWNER_MODULE *)table)->table + num;
3447 memcpy( &row->ucLocalAddr, &key->local.Ipv6.sin6_addr, sizeof(row->ucLocalAddr) );
3448 row->dwLocalScopeId = key->local.Ipv6.sin6_scope_id;
3449 row->dwLocalPort = key->local.Ipv6.sin6_port;
3450 row->dwOwningPid = stat->pid;
3451 row->liCreateTimestamp.QuadPart = stat->create_time;
3452 row->dwFlags = stat->flags;
3453 row->OwningModuleInfo[0] = stat->mod_info;
3454 memset( row->OwningModuleInfo + 1, 0, sizeof(row->OwningModuleInfo) - sizeof(row->OwningModuleInfo[0]) );
3455 return;
3457 default:
3458 ERR( "Unknown class %ld\n", table_class );
3459 return;
3462 ERR( "Unknown family %ld\n", family );
3463 return;
3466 static int udp_row_cmp( const void *a, const void *b )
3468 const MIB_UDPROW *rowA = a, *rowB = b;
3470 return DWORD_cmp(RtlUlongByteSwap( rowA->dwLocalAddr), RtlUlongByteSwap( rowB->dwLocalAddr )) ||
3471 RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort );
3474 static int udp6_row_cmp( const void *a, const void *b )
3476 const MIB_UDP6ROW *rowA = a;
3477 const MIB_UDP6ROW *rowB = b;
3478 int ret;
3480 if ((ret = memcmp( &rowA->dwLocalAddr, &rowB->dwLocalAddr, sizeof(rowA->dwLocalAddr) )) != 0) return ret;
3481 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
3482 return RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort );
3485 /******************************************************************
3486 * GetExtendedUdpTable (IPHLPAPI.@)
3488 DWORD WINAPI GetExtendedUdpTable( void *table, DWORD *size, BOOL sort, ULONG family,
3489 UDP_TABLE_CLASS table_class, ULONG reserved )
3491 DWORD err, count, needed, i, num = 0, row_size = 0;
3492 struct nsi_udp_endpoint_key *key;
3493 struct nsi_udp_endpoint_static *stat;
3495 TRACE( "table %p, size %p, sort %d, family %lu, table_class %u, reserved %lu\n",
3496 table, size, sort, family, table_class, reserved );
3498 if (!size || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
3500 err = NsiAllocateAndGetTable( 1, &NPI_MS_UDP_MODULEID, NSI_UDP_ENDPOINT_TABLE, (void **)&key, sizeof(*key),
3501 NULL, 0, NULL, 0, (void **)&stat, sizeof(*stat), &count, 0 );
3502 if (err) return err;
3504 for (i = 0; i < count; i++)
3505 if (key[i].local.si_family == family)
3506 num++;
3508 needed = udp_table_size( family, table_class, num, &row_size );
3509 if (!table || *size < needed)
3511 *size = needed;
3512 err = ERROR_INSUFFICIENT_BUFFER;
3514 else
3516 *size = needed;
3517 *(DWORD *)table = num;
3518 num = 0;
3519 for (i = 0; i < count; i++)
3521 if (key[i].local.si_family != family) continue;
3522 udp_row_fill( table, num++, family, table_class, key + i, stat + i );
3526 if (!err && sort)
3528 int (*fn)(const void *, const void *);
3529 DWORD offset = udp_table_size( family, table_class, 0, &row_size );
3531 if (family == AF_INET) fn = udp_row_cmp;
3532 else fn = udp6_row_cmp;
3534 qsort( (BYTE *)table + offset, num, row_size, fn );
3537 NsiFreeTable( key, NULL, NULL, stat );
3538 return err;
3541 DWORD WINAPI AllocateAndGetUdpTableFromStack( MIB_UDPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
3543 DWORD err, size = 0x100, attempt;
3545 TRACE("table %p, sort %d, heap %p, flags 0x%08lx\n", table, sort, heap, flags );
3547 if (!table) return ERROR_INVALID_PARAMETER;
3549 for (attempt = 0; attempt < 5; attempt++)
3551 *table = HeapAlloc( heap, flags, size );
3552 if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
3553 err = GetExtendedUdpTable( *table, &size, sort, AF_INET, UDP_TABLE_BASIC, 0 );
3554 if (!err) break;
3555 HeapFree( heap, flags, *table );
3556 *table = NULL;
3557 if (err != ERROR_INSUFFICIENT_BUFFER) break;
3559 return err;
3562 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW *row, USHORT fam, void *key, struct nsi_ip_unicast_rw *rw,
3563 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
3565 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key;
3566 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key;
3568 if (fam == AF_INET)
3570 row->Address.Ipv4.sin_family = fam;
3571 row->Address.Ipv4.sin_port = 0;
3572 row->Address.Ipv4.sin_addr = key4->addr;
3573 memset( row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) );
3574 row->InterfaceLuid.Value = key4->luid.Value;
3576 else
3578 row->Address.Ipv6.sin6_family = fam;
3579 row->Address.Ipv6.sin6_port = 0;
3580 row->Address.Ipv6.sin6_flowinfo = 0;
3581 row->Address.Ipv6.sin6_addr = key6->addr;
3582 row->Address.Ipv6.sin6_scope_id = dyn->scope_id;
3583 row->InterfaceLuid.Value = key6->luid.Value;
3586 ConvertInterfaceLuidToIndex( &row->InterfaceLuid, &row->InterfaceIndex );
3587 row->PrefixOrigin = rw->prefix_origin;
3588 row->SuffixOrigin = rw->suffix_origin;
3589 row->ValidLifetime = rw->valid_lifetime;
3590 row->PreferredLifetime = rw->preferred_lifetime;
3591 row->OnLinkPrefixLength = rw->on_link_prefix;
3592 row->SkipAsSource = 0;
3593 row->DadState = dyn->dad_state;
3594 row->ScopeId.Value = dyn->scope_id;
3595 row->CreationTimeStamp.QuadPart = stat->creation_time;
3598 DWORD WINAPI GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW *row)
3600 struct nsi_ipv4_unicast_key key4;
3601 struct nsi_ipv6_unicast_key key6;
3602 struct nsi_ip_unicast_rw rw;
3603 struct nsi_ip_unicast_dynamic dyn;
3604 struct nsi_ip_unicast_static stat;
3605 const NPI_MODULEID *mod;
3606 DWORD err, key_size;
3607 void *key;
3609 TRACE( "%p\n", row );
3611 if (!row) return ERROR_INVALID_PARAMETER;
3612 mod = ip_module_id( row->Address.si_family );
3613 if (!mod) return ERROR_INVALID_PARAMETER;
3615 if (!row->InterfaceLuid.Value)
3617 err = ConvertInterfaceIndexToLuid( row->InterfaceIndex, &row->InterfaceLuid );
3618 if (err) return err;
3621 if (row->Address.si_family == AF_INET)
3623 key4.luid = row->InterfaceLuid;
3624 key4.addr = row->Address.Ipv4.sin_addr;
3625 key4.pad = 0;
3626 key = &key4;
3627 key_size = sizeof(key4);
3629 else if (row->Address.si_family == AF_INET6)
3631 key6.luid = row->InterfaceLuid;
3632 key6.addr = row->Address.Ipv6.sin6_addr;
3633 key = &key6;
3634 key_size = sizeof(key6);
3636 else return ERROR_INVALID_PARAMETER;
3638 err = NsiGetAllParameters( 1, mod, NSI_IP_UNICAST_TABLE, key, key_size, &rw, sizeof(rw),
3639 &dyn, sizeof(dyn), &stat, sizeof(stat) );
3640 if (!err) unicast_row_fill( row, row->Address.si_family, key, &rw, &dyn, &stat );
3641 return err;
3644 DWORD WINAPI GetUnicastIpAddressTable(ADDRESS_FAMILY family, MIB_UNICASTIPADDRESS_TABLE **table)
3646 void *key[2] = { NULL, NULL };
3647 struct nsi_ip_unicast_rw *rw[2] = { NULL, NULL };
3648 struct nsi_ip_unicast_dynamic *dyn[2] = { NULL, NULL };
3649 struct nsi_ip_unicast_static *stat[2] = { NULL, NULL };
3650 static const USHORT fam[2] = { AF_INET, AF_INET6 };
3651 static const DWORD key_size[2] = { sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ipv6_unicast_key) };
3652 DWORD err, i, size, count[2] = { 0, 0 };
3654 TRACE( "%u, %p\n", family, table );
3656 if (!table || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
3657 return ERROR_INVALID_PARAMETER;
3659 for (i = 0; i < 2; i++)
3661 if (family != AF_UNSPEC && family != fam[i]) continue;
3663 err = NsiAllocateAndGetTable( 1, ip_module_id( fam[i] ), NSI_IP_UNICAST_TABLE, key + i, key_size[i],
3664 (void **)rw + i, sizeof(**rw), (void **)dyn + i, sizeof(**dyn),
3665 (void **)stat + i, sizeof(**stat), count + i, 0 );
3666 if (err) goto err;
3669 size = FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE, Table[ count[0] + count[1] ]);
3670 *table = heap_alloc( size );
3671 if (!*table)
3673 err = ERROR_NOT_ENOUGH_MEMORY;
3674 goto err;
3677 (*table)->NumEntries = count[0] + count[1];
3678 for (i = 0; i < count[0]; i++)
3680 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + i;
3681 struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key[0];
3683 unicast_row_fill( row, fam[0], (void *)(key4 + i), rw[0] + i, dyn[0] + i, stat[0] + i );
3686 for (i = 0; i < count[1]; i++)
3688 MIB_UNICASTIPADDRESS_ROW *row = (*table)->Table + count[0] + i;
3689 struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key[1];
3691 unicast_row_fill( row, fam[1], (void *)(key6 + i), rw[1] + i, dyn[1] + i, stat[1] + i );
3694 err:
3695 for (i = 0; i < 2; i++) NsiFreeTable( key[i], rw[i], dyn[i], stat[i] );
3696 return err;
3699 /******************************************************************
3700 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3702 * This is a Win98-only function to get information on "unidirectional"
3703 * adapters. Since this is pretty nonsensical in other contexts, it
3704 * never returns anything.
3706 * PARAMS
3707 * pIPIfInfo [Out] buffer for adapter infos
3708 * dwOutBufLen [Out] length of the output buffer
3710 * RETURNS
3711 * Success: NO_ERROR
3712 * Failure: error code from winerror.h
3714 * FIXME
3715 * Stub, returns ERROR_NOT_SUPPORTED.
3717 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
3719 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
3720 /* a unidirectional adapter?? not bloody likely! */
3721 return ERROR_NOT_SUPPORTED;
3725 /******************************************************************
3726 * IpReleaseAddress (IPHLPAPI.@)
3728 * Release an IP obtained through DHCP,
3730 * PARAMS
3731 * AdapterInfo [In] adapter to release IP address
3733 * RETURNS
3734 * Success: NO_ERROR
3735 * Failure: error code from winerror.h
3737 * NOTES
3738 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3739 * this function does nothing.
3741 * FIXME
3742 * Stub, returns ERROR_NOT_SUPPORTED.
3744 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3746 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3747 return ERROR_NOT_SUPPORTED;
3751 /******************************************************************
3752 * IpRenewAddress (IPHLPAPI.@)
3754 * Renew an IP obtained through DHCP.
3756 * PARAMS
3757 * AdapterInfo [In] adapter to renew IP address
3759 * RETURNS
3760 * Success: NO_ERROR
3761 * Failure: error code from winerror.h
3763 * NOTES
3764 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3765 * this function does nothing.
3767 * FIXME
3768 * Stub, returns ERROR_NOT_SUPPORTED.
3770 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
3772 FIXME("Stub AdapterInfo %p\n", AdapterInfo);
3773 return ERROR_NOT_SUPPORTED;
3777 /******************************************************************
3778 * NotifyAddrChange (IPHLPAPI.@)
3780 * Notify caller whenever the ip-interface map is changed.
3782 * PARAMS
3783 * Handle [Out] handle usable in asynchronous notification
3784 * overlapped [In] overlapped structure that notifies the caller
3786 * RETURNS
3787 * Success: NO_ERROR
3788 * Failure: error code from winerror.h
3790 * FIXME
3791 * Stub, returns ERROR_NOT_SUPPORTED.
3793 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3795 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3796 if (Handle) *Handle = INVALID_HANDLE_VALUE;
3797 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
3798 return ERROR_IO_PENDING;
3802 /******************************************************************
3803 * NotifyIpInterfaceChange (IPHLPAPI.@)
3805 DWORD WINAPI NotifyIpInterfaceChange(ADDRESS_FAMILY family, PIPINTERFACE_CHANGE_CALLBACK callback,
3806 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3808 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3809 family, callback, context, init_notify, handle);
3810 if (handle) *handle = NULL;
3811 return NO_ERROR;
3814 /******************************************************************
3815 * NotifyRouteChange2 (IPHLPAPI.@)
3817 DWORD WINAPI NotifyRouteChange2(ADDRESS_FAMILY family, PIPFORWARD_CHANGE_CALLBACK callback, VOID* context,
3818 BOOLEAN init_notify, HANDLE* handle)
3820 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3821 family, callback, context, init_notify, handle);
3822 if (handle) *handle = NULL;
3823 return NO_ERROR;
3827 /******************************************************************
3828 * NotifyRouteChange (IPHLPAPI.@)
3830 * Notify caller whenever the ip routing table is changed.
3832 * PARAMS
3833 * Handle [Out] handle usable in asynchronous notification
3834 * overlapped [In] overlapped structure that notifies the caller
3836 * RETURNS
3837 * Success: NO_ERROR
3838 * Failure: error code from winerror.h
3840 * FIXME
3841 * Stub, returns ERROR_NOT_SUPPORTED.
3843 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
3845 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
3846 return ERROR_NOT_SUPPORTED;
3850 /******************************************************************
3851 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3853 DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback,
3854 PVOID context, BOOLEAN init_notify, PHANDLE handle)
3856 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3857 family, callback, context, init_notify, handle);
3858 if (handle) *handle = NULL;
3860 if (init_notify)
3861 callback(context, NULL, MibInitialNotification);
3863 return NO_ERROR;
3866 /******************************************************************
3867 * SendARP (IPHLPAPI.@)
3869 * Send an ARP request.
3871 * PARAMS
3872 * DestIP [In] attempt to obtain this IP
3873 * SrcIP [In] optional sender IP address
3874 * pMacAddr [Out] buffer for the mac address
3875 * PhyAddrLen [In/Out] length of the output buffer
3877 * RETURNS
3878 * Success: NO_ERROR
3879 * Failure: error code from winerror.h
3881 * FIXME
3882 * Stub, returns ERROR_NOT_SUPPORTED.
3884 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
3886 FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
3887 DestIP, SrcIP, pMacAddr, PhyAddrLen);
3888 return ERROR_NOT_SUPPORTED;
3892 /******************************************************************
3893 * SetIfEntry (IPHLPAPI.@)
3895 * Set the administrative status of an interface.
3897 * PARAMS
3898 * pIfRow [In] dwAdminStatus member specifies the new status.
3900 * RETURNS
3901 * Success: NO_ERROR
3902 * Failure: error code from winerror.h
3904 * FIXME
3905 * Stub, returns ERROR_NOT_SUPPORTED.
3907 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
3909 FIXME("(pIfRow %p): stub\n", pIfRow);
3910 /* this is supposed to set an interface administratively up or down.
3911 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3912 this sort of down is indistinguishable from other sorts of down (e.g. no
3913 link). */
3914 return ERROR_NOT_SUPPORTED;
3918 /******************************************************************
3919 * SetIpForwardEntry (IPHLPAPI.@)
3921 * Modify an existing route.
3923 * PARAMS
3924 * pRoute [In] route with the new information
3926 * RETURNS
3927 * Success: NO_ERROR
3928 * Failure: error code from winerror.h
3930 * FIXME
3931 * Stub, returns NO_ERROR.
3933 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
3935 FIXME("(pRoute %p): stub\n", pRoute);
3936 /* this is to add a route entry, how's it distinguishable from
3937 CreateIpForwardEntry?
3938 could use SIOCADDRT, not sure I want to */
3939 return 0;
3943 /******************************************************************
3944 * SetIpNetEntry (IPHLPAPI.@)
3946 * Modify an existing ARP entry.
3948 * PARAMS
3949 * pArpEntry [In] ARP entry with the new information
3951 * RETURNS
3952 * Success: NO_ERROR
3953 * Failure: error code from winerror.h
3955 * FIXME
3956 * Stub, returns NO_ERROR.
3958 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3960 FIXME("(pArpEntry %p): stub\n", pArpEntry);
3961 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3962 return 0;
3966 /******************************************************************
3967 * SetIpStatistics (IPHLPAPI.@)
3969 * Toggle IP forwarding and det the default TTL value.
3971 * PARAMS
3972 * pIpStats [In] IP statistics with the new information
3974 * RETURNS
3975 * Success: NO_ERROR
3976 * Failure: error code from winerror.h
3978 * FIXME
3979 * Stub, returns NO_ERROR.
3981 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3983 FIXME("(pIpStats %p): stub\n", pIpStats);
3984 return 0;
3988 /******************************************************************
3989 * SetIpTTL (IPHLPAPI.@)
3991 * Set the default TTL value.
3993 * PARAMS
3994 * nTTL [In] new TTL value
3996 * RETURNS
3997 * Success: NO_ERROR
3998 * Failure: error code from winerror.h
4000 * FIXME
4001 * Stub, returns NO_ERROR.
4003 DWORD WINAPI SetIpTTL(UINT nTTL)
4005 FIXME("(nTTL %d): stub\n", nTTL);
4006 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
4007 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
4008 return 0;
4012 /******************************************************************
4013 * SetTcpEntry (IPHLPAPI.@)
4015 * Set the state of a TCP connection.
4017 * PARAMS
4018 * pTcpRow [In] specifies connection with new state
4020 * RETURNS
4021 * Success: NO_ERROR
4022 * Failure: error code from winerror.h
4024 * FIXME
4025 * Stub, returns NO_ERROR.
4027 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
4029 FIXME("(pTcpRow %p): stub\n", pTcpRow);
4030 return 0;
4033 /***********************************************************************
4034 * GetPerTcpConnectionEStats (IPHLPAPI.@)
4036 ULONG WINAPI GetPerTcpConnectionEStats(MIB_TCPROW *row, TCP_ESTATS_TYPE stats, UCHAR *rw, ULONG rw_version,
4037 ULONG rw_size, UCHAR *ro_static, ULONG ro_static_version,
4038 ULONG ro_static_size, UCHAR *ro_dynamic, ULONG ro_dynamic_version,
4039 ULONG ro_dynamic_size)
4041 FIXME( "(%p, %d, %p, %ld, %ld, %p, %ld, %ld, %p, %ld, %ld): stub\n", row, stats, rw, rw_version, rw_size,
4042 ro_static, ro_static_version, ro_static_size, ro_dynamic, ro_dynamic_version, ro_dynamic_size );
4043 return ERROR_CALL_NOT_IMPLEMENTED;
4046 /******************************************************************
4047 * SetPerTcpConnectionEStats (IPHLPAPI.@)
4049 DWORD WINAPI SetPerTcpConnectionEStats(PMIB_TCPROW row, TCP_ESTATS_TYPE state, PBYTE rw,
4050 ULONG version, ULONG size, ULONG offset)
4052 FIXME("(row %p, state %d, rw %p, version %lu, size %lu, offset %lu): stub\n",
4053 row, state, rw, version, size, offset);
4054 return ERROR_NOT_SUPPORTED;
4058 /******************************************************************
4059 * UnenableRouter (IPHLPAPI.@)
4061 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
4062 * if it reaches zero.
4064 * PARAMS
4065 * pOverlapped [In/Out] should be the same as in EnableRouter()
4066 * lpdwEnableCount [Out] optional, receives reference count
4068 * RETURNS
4069 * Success: NO_ERROR
4070 * Failure: error code from winerror.h
4072 * FIXME
4073 * Stub, returns ERROR_NOT_SUPPORTED.
4075 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
4077 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
4078 lpdwEnableCount);
4079 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
4080 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
4082 return ERROR_NOT_SUPPORTED;
4085 /******************************************************************
4086 * PfCreateInterface (IPHLPAPI.@)
4088 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
4089 BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
4091 FIXME("(%ld %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
4092 return ERROR_CALL_NOT_IMPLEMENTED;
4095 /******************************************************************
4096 * PfUnBindInterface (IPHLPAPI.@)
4098 DWORD WINAPI PfUnBindInterface(INTERFACE_HANDLE interface)
4100 FIXME("(%p) stub\n", interface);
4101 return ERROR_CALL_NOT_IMPLEMENTED;
4104 /******************************************************************
4105 * PfDeleteInterface(IPHLPAPI.@)
4107 DWORD WINAPI PfDeleteInterface(INTERFACE_HANDLE interface)
4109 FIXME("(%p) stub\n", interface);
4110 return ERROR_CALL_NOT_IMPLEMENTED;
4113 /******************************************************************
4114 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
4116 DWORD WINAPI PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface, PFADDRESSTYPE type, PBYTE ip)
4118 FIXME("(%p %d %p) stub\n", interface, type, ip);
4119 return ERROR_CALL_NOT_IMPLEMENTED;
4122 /******************************************************************
4123 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
4125 DWORD WINAPI ConvertInterfaceAliasToLuid( const WCHAR *alias, NET_LUID *luid )
4127 struct nsi_ndis_ifinfo_rw *data;
4128 DWORD err, count, i, len;
4129 NET_LUID *keys;
4131 TRACE( "(%s %p)\n", debugstr_w(alias), luid );
4133 if (!alias || !*alias || !luid) return ERROR_INVALID_PARAMETER;
4134 luid->Value = 0;
4135 len = wcslen( alias );
4137 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
4138 (void **)&data, sizeof(*data), NULL, 0, NULL, 0, &count, 0 );
4139 if (err) return err;
4141 err = ERROR_INVALID_PARAMETER;
4142 for (i = 0; i < count; i++)
4144 if (data[i].alias.Length == len * 2 && !memcmp( data[i].alias.String, alias, len * 2 ))
4146 luid->Value = keys[i].Value;
4147 err = ERROR_SUCCESS;
4148 break;
4151 NsiFreeTable( keys, data, NULL, NULL );
4152 return err;
4155 /******************************************************************
4156 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
4158 DWORD WINAPI ConvertInterfaceGuidToLuid(const GUID *guid, NET_LUID *luid)
4160 struct nsi_ndis_ifinfo_static *data;
4161 DWORD err, count, i;
4162 NET_LUID *keys;
4164 TRACE( "(%s %p)\n", debugstr_guid(guid), luid );
4166 if (!guid || !luid) return ERROR_INVALID_PARAMETER;
4167 luid->Value = 0;
4169 err = NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, (void **)&keys, sizeof(*keys),
4170 NULL, 0, NULL, 0, (void **)&data, sizeof(*data), &count, 0 );
4171 if (err) return err;
4173 err = ERROR_INVALID_PARAMETER;
4174 for (i = 0; i < count; i++)
4176 if (IsEqualGUID( &data[i].if_guid, guid ))
4178 luid->Value = keys[i].Value;
4179 err = ERROR_SUCCESS;
4180 break;
4183 NsiFreeTable( keys, NULL, NULL, data );
4184 return err;
4187 /******************************************************************
4188 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
4190 DWORD WINAPI ConvertInterfaceIndexToLuid(NET_IFINDEX index, NET_LUID *luid)
4192 DWORD err;
4194 TRACE( "(%lu %p)\n", index, luid );
4196 if (!luid) return ERROR_INVALID_PARAMETER;
4198 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &index, sizeof(index),
4199 NSI_PARAM_TYPE_STATIC, luid, sizeof(*luid), 0 );
4200 if (err) luid->Value = 0;
4201 return err;
4204 /******************************************************************
4205 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4207 DWORD WINAPI ConvertInterfaceLuidToAlias( const NET_LUID *luid, WCHAR *alias, SIZE_T len )
4209 DWORD err;
4210 IF_COUNTED_STRING name;
4212 TRACE( "(%p %p %Iu)\n", luid, alias, len );
4214 if (!luid || !alias) return ERROR_INVALID_PARAMETER;
4216 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4217 NSI_PARAM_TYPE_RW, &name, sizeof(name),
4218 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw, alias) );
4219 if (err) return err;
4221 if (len <= name.Length / sizeof(WCHAR)) return ERROR_NOT_ENOUGH_MEMORY;
4222 memcpy( alias, name.String, name.Length );
4223 alias[name.Length / sizeof(WCHAR)] = '\0';
4225 return err;
4228 /******************************************************************
4229 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4231 DWORD WINAPI ConvertInterfaceLuidToGuid(const NET_LUID *luid, GUID *guid)
4233 DWORD err;
4235 TRACE( "(%p %p)\n", luid, guid );
4237 if (!luid || !guid) return ERROR_INVALID_PARAMETER;
4239 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4240 NSI_PARAM_TYPE_STATIC, guid, sizeof(*guid),
4241 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_guid) );
4242 if (err) memset( guid, 0, sizeof(*guid) );
4243 return err;
4246 /******************************************************************
4247 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4249 DWORD WINAPI ConvertInterfaceLuidToIndex(const NET_LUID *luid, NET_IFINDEX *index)
4251 DWORD err;
4253 TRACE( "(%p %p)\n", luid, index );
4255 if (!luid || !index) return ERROR_INVALID_PARAMETER;
4257 err = NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid, sizeof(*luid),
4258 NSI_PARAM_TYPE_STATIC, index, sizeof(*index),
4259 FIELD_OFFSET(struct nsi_ndis_ifinfo_static, if_index) );
4260 if (err) *index = 0;
4261 return err;
4264 /******************************************************************
4265 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4267 DWORD WINAPI ConvertInterfaceLuidToNameA(const NET_LUID *luid, char *name, SIZE_T len)
4269 DWORD err;
4270 WCHAR nameW[IF_MAX_STRING_SIZE + 1];
4272 TRACE( "(%p %p %Iu)\n", luid, name, len );
4274 if (!luid) return ERROR_INVALID_PARAMETER;
4275 if (!name || !len) return ERROR_NOT_ENOUGH_MEMORY;
4277 err = ConvertInterfaceLuidToNameW( luid, nameW, ARRAY_SIZE(nameW) );
4278 if (err) return err;
4280 if (!WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, len, NULL, NULL ))
4281 err = GetLastError();
4282 return err;
4285 struct name_prefix
4287 const WCHAR *prefix;
4288 DWORD type;
4290 static const struct name_prefix name_prefixes[] =
4292 { L"other", IF_TYPE_OTHER },
4293 { L"ethernet", IF_TYPE_ETHERNET_CSMACD },
4294 { L"tokenring", IF_TYPE_ISO88025_TOKENRING },
4295 { L"ppp", IF_TYPE_PPP },
4296 { L"loopback", IF_TYPE_SOFTWARE_LOOPBACK },
4297 { L"atm", IF_TYPE_ATM },
4298 { L"wireless", IF_TYPE_IEEE80211 },
4299 { L"tunnel", IF_TYPE_TUNNEL },
4300 { L"ieee1394", IF_TYPE_IEEE1394 }
4303 /******************************************************************
4304 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4306 DWORD WINAPI ConvertInterfaceLuidToNameW(const NET_LUID *luid, WCHAR *name, SIZE_T len)
4308 DWORD i, needed;
4309 const WCHAR *prefix = NULL;
4310 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4312 TRACE( "(%p %p %Iu)\n", luid, name, len );
4314 if (!luid || !name) return ERROR_INVALID_PARAMETER;
4316 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4318 if (luid->Info.IfType == name_prefixes[i].type)
4320 prefix = name_prefixes[i].prefix;
4321 break;
4325 if (prefix) needed = swprintf( buf, len, L"%s_%d", prefix, luid->Info.NetLuidIndex );
4326 else needed = swprintf( buf, len, L"iftype%d_%d", luid->Info.IfType, luid->Info.NetLuidIndex );
4328 if (needed >= len) return ERROR_NOT_ENOUGH_MEMORY;
4329 memcpy( name, buf, (needed + 1) * sizeof(WCHAR) );
4330 return ERROR_SUCCESS;
4333 /******************************************************************
4334 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4336 DWORD WINAPI ConvertInterfaceNameToLuidA(const char *name, NET_LUID *luid)
4338 WCHAR nameW[IF_MAX_STRING_SIZE];
4340 TRACE( "(%s %p)\n", debugstr_a(name), luid );
4342 if (!name) return ERROR_INVALID_NAME;
4343 if (!MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW) ))
4344 return GetLastError();
4346 return ConvertInterfaceNameToLuidW( nameW, luid );
4349 /******************************************************************
4350 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4352 DWORD WINAPI ConvertInterfaceNameToLuidW(const WCHAR *name, NET_LUID *luid)
4354 const WCHAR *sep;
4355 DWORD type = ~0u, i;
4356 int iftype_len = wcslen( L"iftype" );
4357 WCHAR buf[IF_MAX_STRING_SIZE + 1];
4359 TRACE( "(%s %p)\n", debugstr_w(name), luid );
4361 if (!luid) return ERROR_INVALID_PARAMETER;
4362 memset( luid, 0, sizeof(*luid) );
4364 if (!name || !(sep = wcschr( name, '_' )) || sep >= name + ARRAY_SIZE(buf)) return ERROR_INVALID_NAME;
4365 memcpy( buf, name, (sep - name) * sizeof(WCHAR) );
4366 buf[sep - name] = '\0';
4368 if (sep - name > iftype_len && !memcmp( buf, L"iftype", iftype_len * sizeof(WCHAR) ))
4370 type = wcstol( buf + iftype_len, NULL, 10 );
4372 else
4374 for (i = 0; i < ARRAY_SIZE(name_prefixes); i++)
4376 if (!wcscmp( buf, name_prefixes[i].prefix ))
4378 type = name_prefixes[i].type;
4379 break;
4383 if (type == ~0u) return ERROR_INVALID_NAME;
4385 luid->Info.NetLuidIndex = wcstol( sep + 1, NULL, 10 );
4386 luid->Info.IfType = type;
4387 return ERROR_SUCCESS;
4390 /******************************************************************
4391 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4393 DWORD WINAPI ConvertLengthToIpv4Mask(ULONG mask_len, ULONG *mask)
4395 if (mask_len > 32)
4397 *mask = INADDR_NONE;
4398 return ERROR_INVALID_PARAMETER;
4401 if (mask_len == 0)
4402 *mask = 0;
4403 else
4404 *mask = htonl(~0u << (32 - mask_len));
4406 return NO_ERROR;
4409 /******************************************************************
4410 * if_nametoindex (IPHLPAPI.@)
4412 IF_INDEX WINAPI IPHLP_if_nametoindex(const char *name)
4414 IF_INDEX index;
4415 NET_LUID luid;
4416 DWORD err;
4418 TRACE( "(%s)\n", name );
4420 err = ConvertInterfaceNameToLuidA( name, &luid );
4421 if (err) return 0;
4423 err = ConvertInterfaceLuidToIndex( &luid, &index );
4424 if (err) index = 0;
4425 return index;
4428 /******************************************************************
4429 * if_indextoname (IPHLPAPI.@)
4431 char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name )
4433 NET_LUID luid;
4434 DWORD err;
4436 TRACE( "(%lu, %p)\n", index, name );
4438 err = ConvertInterfaceIndexToLuid( index, &luid );
4439 if (err) return NULL;
4441 err = ConvertInterfaceLuidToNameA( &luid, name, IF_MAX_STRING_SIZE );
4442 if (err) return NULL;
4443 return name;
4446 /******************************************************************
4447 * GetIpInterfaceTable (IPHLPAPI.@)
4449 DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table)
4451 FIXME("(%u %p): stub\n", family, table);
4452 return ERROR_NOT_SUPPORTED;
4455 /******************************************************************
4456 * GetBestRoute2 (IPHLPAPI.@)
4458 DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
4459 const SOCKADDR_INET *source, const SOCKADDR_INET *destination,
4460 ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
4461 SOCKADDR_INET *bestaddress)
4463 static int once;
4465 if (!once++)
4466 FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid, index, source,
4467 destination, options, bestroute, bestaddress);
4469 if (!destination || !bestroute || !bestaddress)
4470 return ERROR_INVALID_PARAMETER;
4472 return ERROR_NOT_SUPPORTED;
4475 /******************************************************************
4476 * ParseNetworkString (IPHLPAPI.@)
4478 DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
4479 NET_ADDRESS_INFO *info, USHORT *port, BYTE *prefix_len)
4481 IN_ADDR temp_addr4;
4482 IN6_ADDR temp_addr6;
4483 ULONG temp_scope;
4484 USHORT temp_port = 0;
4485 NTSTATUS status;
4487 TRACE("(%s, %ld, %p, %p, %p)\n", debugstr_w(str), type, info, port, prefix_len);
4489 if (!str)
4490 return ERROR_INVALID_PARAMETER;
4492 if (type & NET_STRING_IPV4_ADDRESS)
4494 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4495 if (SUCCEEDED(status) && !temp_port)
4497 if (info)
4499 info->Format = NET_ADDRESS_IPV4;
4500 info->Ipv4Address.sin_addr = temp_addr4;
4501 info->Ipv4Address.sin_port = 0;
4503 if (port) *port = 0;
4504 if (prefix_len) *prefix_len = 255;
4505 return ERROR_SUCCESS;
4508 if (type & NET_STRING_IPV4_SERVICE)
4510 status = RtlIpv4StringToAddressExW(str, TRUE, &temp_addr4, &temp_port);
4511 if (SUCCEEDED(status) && temp_port)
4513 if (info)
4515 info->Format = NET_ADDRESS_IPV4;
4516 info->Ipv4Address.sin_addr = temp_addr4;
4517 info->Ipv4Address.sin_port = temp_port;
4519 if (port) *port = ntohs(temp_port);
4520 if (prefix_len) *prefix_len = 255;
4521 return ERROR_SUCCESS;
4524 if (type & NET_STRING_IPV6_ADDRESS)
4526 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4527 if (SUCCEEDED(status) && !temp_port)
4529 if (info)
4531 info->Format = NET_ADDRESS_IPV6;
4532 info->Ipv6Address.sin6_addr = temp_addr6;
4533 info->Ipv6Address.sin6_scope_id = temp_scope;
4534 info->Ipv6Address.sin6_port = 0;
4536 if (port) *port = 0;
4537 if (prefix_len) *prefix_len = 255;
4538 return ERROR_SUCCESS;
4541 if (type & NET_STRING_IPV6_SERVICE)
4543 status = RtlIpv6StringToAddressExW(str, &temp_addr6, &temp_scope, &temp_port);
4544 if (SUCCEEDED(status) && temp_port)
4546 if (info)
4548 info->Format = NET_ADDRESS_IPV6;
4549 info->Ipv6Address.sin6_addr = temp_addr6;
4550 info->Ipv6Address.sin6_scope_id = temp_scope;
4551 info->Ipv6Address.sin6_port = temp_port;
4553 if (port) *port = ntohs(temp_port);
4554 if (prefix_len) *prefix_len = 255;
4555 return ERROR_SUCCESS;
4559 if (info) info->Format = NET_ADDRESS_FORMAT_UNSPECIFIED;
4561 if (type & ~(NET_STRING_IPV4_ADDRESS|NET_STRING_IPV4_SERVICE|NET_STRING_IPV6_ADDRESS|NET_STRING_IPV6_SERVICE))
4563 FIXME("Unimplemented type 0x%lx\n", type);
4564 return ERROR_NOT_SUPPORTED;
4567 return ERROR_INVALID_PARAMETER;
4570 struct icmp_handle_data
4572 HANDLE nsi_device;
4575 /***********************************************************************
4576 * IcmpCloseHandle (IPHLPAPI.@)
4578 BOOL WINAPI IcmpCloseHandle( HANDLE handle )
4580 struct icmp_handle_data *data;
4582 if (handle == NULL || handle == INVALID_HANDLE_VALUE)
4583 return FALSE;
4585 data = (struct icmp_handle_data *)handle;
4587 CloseHandle( data->nsi_device );
4588 heap_free( data );
4589 return TRUE;
4592 /***********************************************************************
4593 * IcmpCreateFile (IPHLPAPI.@)
4595 HANDLE WINAPI IcmpCreateFile( void )
4597 struct icmp_handle_data *data = heap_alloc( sizeof(*data) );
4599 if (!data)
4601 SetLastError( IP_NO_RESOURCES );
4602 return INVALID_HANDLE_VALUE;
4605 data->nsi_device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
4606 FILE_FLAG_OVERLAPPED, NULL );
4607 if (data->nsi_device == INVALID_HANDLE_VALUE)
4609 heap_free( data );
4610 return INVALID_HANDLE_VALUE;
4613 return (HANDLE)data;
4616 /******************************************************************
4617 * IcmpParseReplies (IPHLPAPI.@)
4619 DWORD WINAPI IcmpParseReplies( void *reply, DWORD reply_size )
4621 ICMP_ECHO_REPLY *icmp_reply = reply;
4622 DWORD num_pkts = icmp_reply->Reserved;
4624 icmp_reply->Reserved = 0;
4625 if (!num_pkts) SetLastError( icmp_reply->Status );
4626 return num_pkts;
4629 /***********************************************************************
4630 * IcmpSendEcho (IPHLPAPI.@)
4632 DWORD WINAPI IcmpSendEcho( HANDLE handle, IPAddr dst, void *request, WORD request_size,
4633 IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size,
4634 DWORD timeout )
4636 return IcmpSendEcho2Ex( handle, NULL, NULL, NULL, INADDR_ANY, dst, request, request_size,
4637 opts, reply, reply_size, timeout );
4640 /***********************************************************************
4641 * IcmpSendEcho2 (IPHLPAPI.@)
4643 DWORD WINAPI IcmpSendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4644 IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
4645 void *reply, DWORD reply_size, DWORD timeout )
4647 return IcmpSendEcho2Ex( handle, event, apc_routine, apc_ctxt, INADDR_ANY, dst, request, request_size,
4648 opts, reply, reply_size, timeout );
4651 struct icmp_apc_ctxt
4653 void *apc_ctxt;
4654 PIO_APC_ROUTINE apc_routine;
4655 IO_STATUS_BLOCK iosb;
4658 void WINAPI icmp_apc_routine( void *context, IO_STATUS_BLOCK *iosb, ULONG reserved )
4660 struct icmp_apc_ctxt *ctxt = context;
4662 ctxt->apc_routine( ctxt->apc_ctxt, iosb, reserved );
4663 heap_free( ctxt );
4666 /***********************************************************************
4667 * IcmpSendEcho2Ex (IPHLPAPI.@)
4669 DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4670 IPAddr src, IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
4671 void *reply, DWORD reply_size, DWORD timeout )
4673 struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
4674 struct icmp_apc_ctxt *ctxt = heap_alloc( sizeof(*ctxt) );
4675 IO_STATUS_BLOCK *iosb = &ctxt->iosb;
4676 DWORD opt_size, in_size, ret = 0;
4677 struct nsiproxy_icmp_echo *in;
4678 HANDLE request_event;
4679 NTSTATUS status;
4681 if (handle == INVALID_HANDLE_VALUE || !reply)
4683 heap_free( ctxt );
4684 SetLastError( ERROR_INVALID_PARAMETER );
4685 return 0;
4688 ctxt->apc_routine = apc_routine;
4689 ctxt->apc_ctxt = apc_ctxt;
4691 opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0;
4692 in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]);
4693 in = heap_alloc_zero( in_size );
4695 if (!in)
4697 heap_free( ctxt );
4698 SetLastError( IP_NO_RESOURCES );
4699 return 0;
4702 in->user_reply_ptr = (ULONG_PTR)reply;
4703 in->bits = sizeof(void*) * 8;
4704 in->src.Ipv4.sin_family = AF_INET;
4705 in->src.Ipv4.sin_addr.s_addr = src;
4706 in->dst.Ipv4.sin_family = AF_INET;
4707 in->dst.Ipv4.sin_addr.s_addr = dst;
4708 if (opts)
4710 in->ttl = opts->Ttl;
4711 in->tos = opts->Tos;
4712 in->flags = opts->Flags;
4713 memcpy( in->data, opts->OptionsData, opts->OptionsSize );
4714 in->opt_size = opts->OptionsSize;
4716 in->req_size = request_size;
4717 in->timeout = timeout;
4718 memcpy( in->data + opt_size, request, request_size );
4720 request_event = event ? event : (apc_routine ? NULL : CreateEventW( NULL, 0, 0, NULL ));
4722 status = NtDeviceIoControlFile( data->nsi_device, request_event, apc_routine ? icmp_apc_routine : NULL,
4723 apc_routine ? ctxt : apc_ctxt, iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO,
4724 in, in_size, reply, reply_size );
4726 if (status == STATUS_PENDING)
4728 if (!event && !apc_routine && !WaitForSingleObject( request_event, INFINITE ))
4729 status = iosb->Status;
4732 if (!status)
4733 ret = IcmpParseReplies( reply, reply_size );
4735 if (!event && request_event) CloseHandle( request_event );
4736 if (!apc_routine || status != STATUS_PENDING) heap_free( ctxt );
4737 heap_free( in );
4739 if (status) SetLastError( RtlNtStatusToDosError( status ) );
4740 return ret;
4743 /***********************************************************************
4744 * Icmp6CreateFile (IPHLPAPI.@)
4746 HANDLE WINAPI Icmp6CreateFile( void )
4748 FIXME( "stub\n" );
4749 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4750 return INVALID_HANDLE_VALUE;
4753 /***********************************************************************
4754 * Icmp6SendEcho2 (IPHLPAPI.@)
4756 DWORD WINAPI Icmp6SendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
4757 struct sockaddr_in6 *src, struct sockaddr_in6 *dst, void *request, WORD request_size,
4758 IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size, DWORD timeout )
4760 FIXME( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld): stub\n", handle, event,
4761 apc_routine, apc_ctxt, src, dst, request, request_size, opts, reply, reply_size, timeout );
4762 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4763 return 0;
4766 /***********************************************************************
4767 * GetCurrentThreadCompartmentId (IPHLPAPI.@)
4769 NET_IF_COMPARTMENT_ID WINAPI GetCurrentThreadCompartmentId( void )
4771 FIXME( "stub\n" );
4772 return NET_IF_COMPARTMENT_ID_PRIMARY;