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
35 #include "ip2string.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
;
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] );
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] );
76 DWORD WINAPI
ConvertStringToGuidW( const WCHAR
*str
, GUID
*guid
)
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.
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
107 * Failure: error code from winerror.h
110 * Stub. Currently returns ERROR_NOT_SUPPORTED.
112 DWORD WINAPI
AddIPAddress(IPAddr Address
, IPMask IpMask
, DWORD IfIndex
, PULONG NTEContext
, PULONG NTEInstance
)
115 return ERROR_NOT_SUPPORTED
;
118 /******************************************************************
119 * CancelIPChangeNotify (IPHLPAPI.@)
121 * Cancel a previous notification created by NotifyAddrChange or
125 * overlapped [In] overlapped structure that notifies the caller
131 BOOL WINAPI
CancelIPChangeNotify(LPOVERLAPPED overlapped
)
135 TRACE("overlapped %p.\n", overlapped
);
137 if ((err
= NsiCancelChangeNotification( overlapped
))) SetLastError( err
);
142 /******************************************************************
143 * CancelMibChangeNotify2 (IPHLPAPI.@)
145 DWORD WINAPI
CancelMibChangeNotify2(HANDLE handle
)
147 FIXME("(handle %p): stub\n", handle
);
152 /******************************************************************
153 * CreateIpForwardEntry (IPHLPAPI.@)
155 * Create a route in the local computer's IP table.
158 * pRoute [In] new route information
162 * Failure: error code from winerror.h
165 * Stub, always returns NO_ERROR.
167 DWORD WINAPI
CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
169 FIXME("(pRoute %p): stub\n", pRoute
);
170 /* could use SIOCADDRT, not sure I want to */
175 /******************************************************************
176 * CreateIpNetEntry (IPHLPAPI.@)
178 * Create entry in the ARP table.
181 * pArpEntry [In] new ARP entry
185 * Failure: error code from winerror.h
188 * Stub, always returns NO_ERROR.
190 DWORD WINAPI
CreateIpNetEntry(PMIB_IPNETROW pArpEntry
)
192 FIXME("(pArpEntry %p)\n", pArpEntry
);
193 /* could use SIOCSARP on systems that support it, not sure I want to */
198 /******************************************************************
199 * CreateProxyArpEntry (IPHLPAPI.@)
201 * Create a Proxy ARP (PARP) entry for an IP address.
204 * dwAddress [In] IP address for which this computer acts as a proxy.
205 * dwMask [In] subnet mask for dwAddress
206 * dwIfIndex [In] interface index
210 * Failure: error code from winerror.h
213 * Stub, returns ERROR_NOT_SUPPORTED.
215 DWORD WINAPI
CreateProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
217 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
218 dwAddress
, dwMask
, dwIfIndex
);
219 return ERROR_NOT_SUPPORTED
;
222 static char *debugstr_ipv6(const struct sockaddr_in6
*sin
, char *buf
)
224 const IN6_ADDR
*addr
= &sin
->sin6_addr
;
227 BOOL in_zero
= FALSE
;
229 for (i
= 0; i
< 7; i
++)
231 if (!addr
->u
.Word
[i
])
243 p
+= sprintf(p
, "%x:", ntohs(addr
->u
.Word
[i
]));
247 sprintf(p
, "%x", ntohs(addr
->u
.Word
[7]));
251 static BOOL
map_address_6to4( const SOCKADDR_IN6
*addr6
, SOCKADDR_IN
*addr4
)
255 if (addr6
->sin6_family
!= AF_INET6
) return FALSE
;
257 for (i
= 0; i
< 5; i
++)
258 if (addr6
->sin6_addr
.u
.Word
[i
]) return FALSE
;
260 if (addr6
->sin6_addr
.u
.Word
[5] != 0xffff) return FALSE
;
262 addr4
->sin_family
= AF_INET
;
263 addr4
->sin_port
= addr6
->sin6_port
;
264 addr4
->sin_addr
.S_un
.S_addr
= addr6
->sin6_addr
.u
.Word
[6] << 16 | addr6
->sin6_addr
.u
.Word
[7];
265 memset( &addr4
->sin_zero
, 0, sizeof(addr4
->sin_zero
) );
270 static BOOL
find_src_address( MIB_IPADDRTABLE
*table
, const SOCKADDR_IN
*dst
, SOCKADDR_IN6
*src
)
272 MIB_IPFORWARDROW row
;
275 if (GetBestRoute( dst
->sin_addr
.S_un
.S_addr
, 0, &row
)) return FALSE
;
277 for (i
= 0; i
< table
->dwNumEntries
; i
++)
279 /* take the first address */
280 if (table
->table
[i
].dwIndex
== row
.dwForwardIfIndex
)
282 src
->sin6_family
= AF_INET6
;
284 src
->sin6_flowinfo
= 0;
285 for (j
= 0; j
< 5; j
++) src
->sin6_addr
.u
.Word
[j
] = 0;
286 src
->sin6_addr
.u
.Word
[5] = 0xffff;
287 src
->sin6_addr
.u
.Word
[6] = table
->table
[i
].dwAddr
& 0xffff;
288 src
->sin6_addr
.u
.Word
[7] = table
->table
[i
].dwAddr
>> 16;
296 /******************************************************************
297 * CreateSortedAddressPairs (IPHLPAPI.@)
299 DWORD WINAPI
CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list
, DWORD src_count
,
300 const PSOCKADDR_IN6 dst_list
, DWORD dst_count
,
301 DWORD options
, PSOCKADDR_IN6_PAIR
*pair_list
,
305 SOCKADDR_IN6_PAIR
*pairs
;
308 MIB_IPADDRTABLE
*table
;
310 FIXME( "(src_list %p src_count %lu dst_list %p dst_count %lu options %lx pair_list %p pair_count %p): stub\n",
311 src_list
, src_count
, dst_list
, dst_count
, options
, pair_list
, pair_count
);
313 if (src_list
|| src_count
|| !dst_list
|| !pair_list
|| !pair_count
|| dst_count
> 500)
314 return ERROR_INVALID_PARAMETER
;
316 for (i
= 0; i
< dst_count
; i
++)
318 if (!map_address_6to4( &dst_list
[i
], &addr4
))
320 FIXME("only mapped IPv4 addresses are supported\n");
321 return ERROR_NOT_SUPPORTED
;
325 size
= dst_count
* sizeof(*pairs
);
326 size
+= dst_count
* sizeof(SOCKADDR_IN6
) * 2; /* source address + destination address */
327 if (!(pairs
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_NOT_ENOUGH_MEMORY
;
328 ptr
= (SOCKADDR_IN6
*)&pairs
[dst_count
];
330 if ((ret
= AllocateAndGetIpAddrTableFromStack( &table
, FALSE
, GetProcessHeap(), 0 )))
332 HeapFree( GetProcessHeap(), 0, pairs
);
336 for (i
= 0; i
< dst_count
; i
++)
338 pairs
[i
].SourceAddress
= ptr
++;
339 if (!map_address_6to4( &dst_list
[i
], &addr4
) ||
340 !find_src_address( table
, &addr4
, pairs
[i
].SourceAddress
))
343 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list
[i
], buf
) );
344 memset( pairs
[i
].SourceAddress
, 0, sizeof(*pairs
[i
].SourceAddress
) );
345 pairs
[i
].SourceAddress
->sin6_family
= AF_INET6
;
348 pairs
[i
].DestinationAddress
= ptr
++;
349 memcpy( pairs
[i
].DestinationAddress
, &dst_list
[i
], sizeof(*pairs
[i
].DestinationAddress
) );
352 *pair_count
= dst_count
;
354 HeapFree( GetProcessHeap(), 0, table
);
359 /******************************************************************
360 * DeleteIPAddress (IPHLPAPI.@)
362 * Delete an IP address added with AddIPAddress().
365 * NTEContext [In] NTE context from AddIPAddress();
369 * Failure: error code from winerror.h
372 * Stub, returns ERROR_NOT_SUPPORTED.
374 DWORD WINAPI
DeleteIPAddress(ULONG NTEContext
)
376 FIXME("(NTEContext %ld): stub\n", NTEContext
);
377 return ERROR_NOT_SUPPORTED
;
381 /******************************************************************
382 * DeleteIpForwardEntry (IPHLPAPI.@)
387 * pRoute [In] route to delete
391 * Failure: error code from winerror.h
394 * Stub, returns NO_ERROR.
396 DWORD WINAPI
DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
398 FIXME("(pRoute %p): stub\n", pRoute
);
399 /* could use SIOCDELRT, not sure I want to */
404 /******************************************************************
405 * DeleteIpNetEntry (IPHLPAPI.@)
407 * Delete an ARP entry.
410 * pArpEntry [In] ARP entry to delete
414 * Failure: error code from winerror.h
417 * Stub, returns NO_ERROR.
419 DWORD WINAPI
DeleteIpNetEntry(PMIB_IPNETROW pArpEntry
)
421 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
422 /* could use SIOCDARP on systems that support it, not sure I want to */
427 /******************************************************************
428 * DeleteProxyArpEntry (IPHLPAPI.@)
430 * Delete a Proxy ARP entry.
433 * dwAddress [In] IP address for which this computer acts as a proxy.
434 * dwMask [In] subnet mask for dwAddress
435 * dwIfIndex [In] interface index
439 * Failure: error code from winerror.h
442 * Stub, returns ERROR_NOT_SUPPORTED.
444 DWORD WINAPI
DeleteProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
446 FIXME("(dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx): stub\n",
447 dwAddress
, dwMask
, dwIfIndex
);
448 return ERROR_NOT_SUPPORTED
;
452 /******************************************************************
453 * EnableRouter (IPHLPAPI.@)
455 * Turn on ip forwarding.
459 * pOverlapped [In/Out] hEvent member should contain a valid handle.
462 * Success: ERROR_IO_PENDING
463 * Failure: error code from winerror.h
466 * Stub, returns ERROR_NOT_SUPPORTED.
468 DWORD WINAPI
EnableRouter(HANDLE
* pHandle
, OVERLAPPED
* pOverlapped
)
470 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle
, pOverlapped
);
471 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
472 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
474 return ERROR_NOT_SUPPORTED
;
478 /******************************************************************
479 * FlushIpNetTable (IPHLPAPI.@)
481 * Delete all ARP entries of an interface
484 * dwIfIndex [In] interface index
488 * Failure: error code from winerror.h
491 * Stub, returns ERROR_NOT_SUPPORTED.
493 DWORD WINAPI
FlushIpNetTable(DWORD dwIfIndex
)
495 FIXME("(dwIfIndex 0x%08lx): stub\n", dwIfIndex
);
496 /* this flushes the arp cache of the given index */
497 return ERROR_NOT_SUPPORTED
;
500 /******************************************************************
501 * FreeMibTable (IPHLPAPI.@)
503 * Free buffer allocated by network functions
506 * ptr [In] pointer to the buffer to free
509 void WINAPI
FreeMibTable( void *ptr
)
511 TRACE( "(%p)\n", ptr
);
515 /******************************************************************
516 * GetAdapterIndex (IPHLPAPI.@)
518 * Get interface index from its name.
521 * adapter_name [In] unicode string with the adapter name
522 * index [Out] returns found interface index
524 DWORD WINAPI
GetAdapterIndex( WCHAR
*adapter_name
, ULONG
*index
)
530 TRACE( "name %s, index %p\n", debugstr_w( adapter_name
), index
);
532 if (wcslen( adapter_name
) < wcslen( device_tcpip
)) return ERROR_INVALID_PARAMETER
;
533 err
= ConvertStringToGuidW( adapter_name
+ wcslen( device_tcpip
), &guid
);
535 err
= ConvertInterfaceGuidToLuid( &guid
, &luid
);
537 return ConvertInterfaceLuidToIndex( &luid
, index
);
540 static DWORD
get_wins_servers( SOCKADDR_INET
**servers
)
544 DWORD size
, i
, count
= 0;
545 static const char *values
[] = { "WinsServer", "BackupWinsServer" };
546 IN_ADDR addrs
[ARRAY_SIZE(values
)];
549 /* @@ Wine registry key: HKCU\Software\Wine\Network */
550 if (RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Network", &key
)) return 0;
552 for (i
= 0; i
< ARRAY_SIZE(values
); i
++)
555 if (!RegQueryValueExA( key
, values
[i
], NULL
, NULL
, (LPBYTE
)buf
, &size
))
556 if (!RtlIpv4StringToAddressA( buf
, TRUE
, NULL
, addrs
+ count
) &&
557 addrs
[count
].s_addr
!= INADDR_NONE
&& addrs
[count
].s_addr
!= INADDR_ANY
)
564 *servers
= heap_alloc_zero( count
* sizeof(**servers
) );
565 if (!*servers
) return 0;
566 for (i
= 0; i
< count
; i
++)
568 (*servers
)[i
].Ipv4
.sin_family
= AF_INET
;
569 (*servers
)[i
].Ipv4
.sin_addr
= addrs
[i
];
575 static void ip_addr_string_init( IP_ADDR_STRING
*s
, const IN_ADDR
*addr
, const IN_ADDR
*mask
, DWORD ctxt
)
579 if (addr
) RtlIpv4AddressToStringA( addr
, s
->IpAddress
.String
);
580 else s
->IpAddress
.String
[0] = '\0';
581 if (mask
) RtlIpv4AddressToStringA( mask
, s
->IpMask
.String
);
582 else s
->IpMask
.String
[0] = '\0';
586 /******************************************************************
587 * GetAdaptersInfo (IPHLPAPI.@)
589 * Get information about adapters.
592 * info [Out] buffer for adapter infos
593 * size [In] length of output buffer
595 DWORD WINAPI
GetAdaptersInfo( IP_ADAPTER_INFO
*info
, ULONG
*size
)
597 DWORD err
, if_count
, if_num
= 0, uni_count
, fwd_count
, needed
, wins_server_count
;
598 DWORD len
, i
, uni
, fwd
;
599 NET_LUID
*if_keys
= NULL
;
600 struct nsi_ndis_ifinfo_rw
*if_rw
= NULL
;
601 struct nsi_ndis_ifinfo_static
*if_stat
= NULL
;
602 struct nsi_ipv4_unicast_key
*uni_keys
= NULL
;
603 struct nsi_ip_unicast_rw
*uni_rw
= NULL
;
604 struct nsi_ipv4_forward_key
*fwd_keys
= NULL
;
605 SOCKADDR_INET
*wins_servers
= NULL
;
606 IP_ADDR_STRING
*extra_ip_addrs
, *cursor
;
609 TRACE( "info %p, size %p\n", info
, size
);
610 if (!size
) return ERROR_INVALID_PARAMETER
;
612 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
613 (void **)&if_keys
, sizeof(*if_keys
), (void **)&if_rw
, sizeof(*if_rw
),
614 NULL
, 0, (void **)&if_stat
, sizeof(*if_stat
), &if_count
, 0 );
617 for (i
= 0; i
< if_count
; i
++)
619 if (if_stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
629 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
,
630 (void **)&uni_keys
, sizeof(*uni_keys
), (void **)&uni_rw
, sizeof(*uni_rw
),
631 NULL
, 0, NULL
, 0, &uni_count
, 0 );
634 /* Slightly overestimate the needed size by assuming that all
635 unicast addresses require a separate IP_ADDR_STRING. */
637 needed
= if_num
* sizeof(*info
) + uni_count
* sizeof(IP_ADDR_STRING
);
638 if (!info
|| *size
< needed
)
641 err
= ERROR_BUFFER_OVERFLOW
;
645 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_FORWARD_TABLE
,
646 (void **)&fwd_keys
, sizeof(*fwd_keys
), NULL
, 0,
647 NULL
, 0, NULL
, 0, &fwd_count
, 0 );
650 wins_server_count
= get_wins_servers( &wins_servers
);
652 extra_ip_addrs
= (IP_ADDR_STRING
*)(info
+ if_num
);
653 for (i
= 0; i
< if_count
; i
++)
655 if (if_stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
657 info
->Next
= info
+ 1;
658 info
->ComboIndex
= 0;
659 ConvertGuidToStringA( &if_stat
[i
].if_guid
, info
->AdapterName
, sizeof(info
->AdapterName
) );
660 len
= WideCharToMultiByte( CP_ACP
, 0, if_stat
[i
].descr
.String
, if_stat
[i
].descr
.Length
/ sizeof(WCHAR
),
661 info
->Description
, sizeof(info
->Description
) - 1, NULL
, NULL
);
662 info
->Description
[len
] = '\0';
663 info
->AddressLength
= if_rw
[i
].phys_addr
.Length
;
664 if (info
->AddressLength
> sizeof(info
->Address
)) info
->AddressLength
= 0;
665 memcpy( info
->Address
, if_rw
[i
].phys_addr
.Address
, info
->AddressLength
);
666 memset( info
->Address
+ info
->AddressLength
, 0, sizeof(info
->Address
) - info
->AddressLength
);
667 info
->Index
= if_stat
[i
].if_index
;
668 info
->Type
= if_stat
[i
].type
;
669 info
->DhcpEnabled
= TRUE
; /* FIXME */
670 info
->CurrentIpAddress
= NULL
;
673 for (uni
= 0; uni
< uni_count
; uni
++)
675 if (uni_keys
[uni
].luid
.Value
!= if_keys
[i
].Value
) continue;
676 if (!cursor
) cursor
= &info
->IpAddressList
;
679 cursor
->Next
= extra_ip_addrs
++;
680 cursor
= cursor
->Next
;
682 ConvertLengthToIpv4Mask( uni_rw
[uni
].on_link_prefix
, &mask
.s_addr
);
683 ip_addr_string_init( cursor
, &uni_keys
[uni
].addr
, &mask
, 0 );
687 mask
.s_addr
= INADDR_ANY
;
688 ip_addr_string_init( &info
->IpAddressList
, &mask
, &mask
, 0 );
691 gw
.s_addr
= INADDR_ANY
;
692 mask
.s_addr
= INADDR_NONE
;
693 for (fwd
= 0; fwd
< fwd_count
; fwd
++)
694 { /* find the first router on this interface */
695 if (fwd_keys
[fwd
].luid
.Value
== if_keys
[i
].Value
&&
696 fwd_keys
[fwd
].next_hop
.s_addr
!= INADDR_ANY
&&
697 !fwd_keys
[fwd
].prefix_len
)
699 gw
= fwd_keys
[fwd
].next_hop
;
703 ip_addr_string_init( &info
->GatewayList
, &gw
, &mask
, 0 );
705 ip_addr_string_init( &info
->DhcpServer
, NULL
, NULL
, 0 );
707 info
->HaveWins
= !!wins_server_count
;
708 ip_addr_string_init( &info
->PrimaryWinsServer
, NULL
, NULL
, 0 );
709 ip_addr_string_init( &info
->SecondaryWinsServer
, NULL
, NULL
, 0 );
712 mask
.s_addr
= INADDR_NONE
;
713 ip_addr_string_init( &info
->PrimaryWinsServer
, &wins_servers
[0].Ipv4
.sin_addr
, &mask
, 0 );
714 if (wins_server_count
> 1)
715 ip_addr_string_init( &info
->SecondaryWinsServer
, &wins_servers
[1].Ipv4
.sin_addr
, &mask
, 0 );
718 info
->LeaseObtained
= 0;
719 info
->LeaseExpires
= 0;
723 info
[-1].Next
= NULL
;
726 heap_free( wins_servers
);
727 NsiFreeTable( fwd_keys
, NULL
, NULL
, NULL
);
728 NsiFreeTable( uni_keys
, uni_rw
, NULL
, NULL
);
729 NsiFreeTable( if_keys
, if_rw
, NULL
, if_stat
);
733 static void address_entry_free( void *ptr
, ULONG offset
, void *ctxt
)
738 static void address_entry_size( void *ptr
, ULONG offset
, void *ctxt
)
740 IP_ADAPTER_DNS_SERVER_ADDRESS
*src_addr
= ptr
; /* all list types are super-sets of this type */
741 ULONG
*total
= (ULONG
*)ctxt
, align
= sizeof(ULONGLONG
) - 1;
743 *total
= (*total
+ src_addr
->Length
+ src_addr
->Address
.iSockaddrLength
+ align
) & ~align
;
746 struct address_entry_copy_params
748 IP_ADAPTER_ADDRESSES
*src
, *dst
;
754 static void address_entry_copy( void *ptr
, ULONG offset
, void *ctxt
)
756 struct address_entry_copy_params
*params
= ctxt
;
757 IP_ADAPTER_DNS_SERVER_ADDRESS
*src_addr
= ptr
; /* all list types are super-sets of this type */
758 IP_ADAPTER_DNS_SERVER_ADDRESS
*dst_addr
= (IP_ADAPTER_DNS_SERVER_ADDRESS
*)params
->ptr
;
759 ULONG align
= sizeof(ULONGLONG
) - 1;
761 memcpy( dst_addr
, src_addr
, src_addr
->Length
);
762 params
->ptr
+= src_addr
->Length
;
763 dst_addr
->Address
.lpSockaddr
= (SOCKADDR
*)params
->ptr
;
764 memcpy( dst_addr
->Address
.lpSockaddr
, src_addr
->Address
.lpSockaddr
, src_addr
->Address
.iSockaddrLength
);
765 params
->ptr
+= (src_addr
->Address
.iSockaddrLength
+ align
) & ~align
;
767 if (params
->cur_offset
!= offset
) /* new list */
769 params
->next
= (BYTE
*)params
->dst
+ offset
;
770 params
->cur_offset
= offset
;
772 *(IP_ADAPTER_DNS_SERVER_ADDRESS
**)params
->next
= dst_addr
;
773 params
->next
= &dst_addr
->Next
;
776 static void address_lists_iterate( IP_ADAPTER_ADDRESSES
*aa
, void (*fn
)(void *entry
, ULONG offset
, void *ctxt
), void *ctxt
)
778 IP_ADAPTER_UNICAST_ADDRESS
*uni
;
779 IP_ADAPTER_DNS_SERVER_ADDRESS
*dns
;
780 IP_ADAPTER_GATEWAY_ADDRESS
*gw
;
781 IP_ADAPTER_PREFIX
*prefix
;
784 for (uni
= aa
->FirstUnicastAddress
; uni
; uni
= next
)
787 fn( uni
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstUnicastAddress
), ctxt
);
790 for (dns
= aa
->FirstDnsServerAddress
; dns
; dns
= next
)
793 fn( dns
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstDnsServerAddress
), ctxt
);
796 for (gw
= aa
->FirstGatewayAddress
; gw
; gw
= next
)
799 fn( gw
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstGatewayAddress
), ctxt
);
802 for (prefix
= aa
->FirstPrefix
; prefix
; prefix
= next
)
805 fn( prefix
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstPrefix
), ctxt
);
809 static void adapters_addresses_free( IP_ADAPTER_ADDRESSES
*info
)
811 IP_ADAPTER_ADDRESSES
*aa
;
813 for (aa
= info
; aa
; aa
= aa
->Next
)
815 address_lists_iterate( aa
, address_entry_free
, NULL
);
817 heap_free( aa
->DnsSuffix
);
822 static ULONG
adapters_addresses_size( IP_ADAPTER_ADDRESSES
*info
)
824 IP_ADAPTER_ADDRESSES
*aa
;
825 ULONG size
= 0, align
= sizeof(ULONGLONG
) - 1;
827 for (aa
= info
; aa
; aa
= aa
->Next
)
829 size
+= sizeof(*aa
) + ((strlen( aa
->AdapterName
) + 1 + 1) & ~1);
830 size
+= (wcslen( aa
->Description
) + 1 + wcslen( aa
->DnsSuffix
) + 1) * sizeof(WCHAR
);
831 if (aa
->FriendlyName
) size
+= (wcslen( aa
->FriendlyName
) + 1) * sizeof(WCHAR
);
832 size
= (size
+ align
) & ~align
;
833 address_lists_iterate( aa
, address_entry_size
, &size
);
838 static void adapters_addresses_copy( IP_ADAPTER_ADDRESSES
*dst
, IP_ADAPTER_ADDRESSES
*src
)
842 UINT_PTR align
= sizeof(ULONGLONG
) - 1;
843 struct address_entry_copy_params params
;
847 ptr
= (char *)(dst
+ 1);
849 dst
->AdapterName
= ptr
;
850 len
= strlen( src
->AdapterName
) + 1;
851 memcpy( dst
->AdapterName
, src
->AdapterName
, len
);
852 ptr
+= (len
+ 1) & ~1;
853 dst
->Description
= (WCHAR
*)ptr
;
854 len
= (wcslen( src
->Description
) + 1) * sizeof(WCHAR
);
855 memcpy( dst
->Description
, src
->Description
, len
);
857 dst
->DnsSuffix
= (WCHAR
*)ptr
;
858 len
= (wcslen( src
->DnsSuffix
) + 1) * sizeof(WCHAR
);
859 memcpy( dst
->DnsSuffix
, src
->DnsSuffix
, len
);
861 if (src
->FriendlyName
)
863 dst
->FriendlyName
= (WCHAR
*)ptr
;
864 len
= (wcslen( src
->FriendlyName
) + 1) * sizeof(WCHAR
);
865 memcpy( dst
->FriendlyName
, src
->FriendlyName
, len
);
868 ptr
= (char *)(((UINT_PTR
)ptr
+ align
) & ~align
);
874 params
.cur_offset
= ~0u;
875 address_lists_iterate( src
, address_entry_copy
, ¶ms
);
880 dst
->Next
= (IP_ADAPTER_ADDRESSES
*)ptr
;
887 static BOOL
sockaddr_is_loopback( SOCKADDR
*sock
)
889 if (sock
->sa_family
== AF_INET
)
891 SOCKADDR_IN
*sin
= (SOCKADDR_IN
*)sock
;
892 return (sin
->sin_addr
.s_addr
& 0xff) == 127;
894 else if (sock
->sa_family
== AF_INET6
)
896 SOCKADDR_IN6
*sin6
= (SOCKADDR_IN6
*)sock
;
897 return IN6_IS_ADDR_LOOPBACK( &sin6
->sin6_addr
);
902 static BOOL
sockaddr_is_linklocal( SOCKADDR
*sock
)
904 if (sock
->sa_family
== AF_INET6
)
906 SOCKADDR_IN6
*sin6
= (SOCKADDR_IN6
*)sock
;
907 return IN6_IS_ADDR_LINKLOCAL( &sin6
->sin6_addr
);
912 static BOOL
unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS
*uni
)
914 return !sockaddr_is_loopback( uni
->Address
.lpSockaddr
) &&
915 !sockaddr_is_linklocal( uni
->Address
.lpSockaddr
);
918 static DWORD
unicast_addresses_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
920 struct nsi_ipv4_unicast_key
*key4
;
921 struct nsi_ipv6_unicast_key
*key6
;
922 struct nsi_ip_unicast_rw
*rw
;
923 struct nsi_ip_unicast_dynamic
*dyn
;
924 struct nsi_ip_unicast_static
*stat
;
925 IP_ADAPTER_UNICAST_ADDRESS
*addr
, **next
;
926 DWORD err
, count
, i
, key_size
= (family
== AF_INET
) ? sizeof(*key4
) : sizeof(*key6
);
927 DWORD sockaddr_size
= (family
== AF_INET
) ? sizeof(SOCKADDR_IN
) : sizeof(SOCKADDR_IN6
);
931 err
= NsiAllocateAndGetTable( 1, ip_module_id( family
), NSI_IP_UNICAST_TABLE
, &key
, key_size
,
932 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
933 (void **)&stat
, sizeof(*stat
), &count
, 0 );
939 for (next
= &aa
->FirstUnicastAddress
; *next
; next
= &(*next
)->Next
)
942 for (i
= 0; i
< count
; i
++)
944 key4
= (struct nsi_ipv4_unicast_key
*)key
+ i
;
945 key6
= (struct nsi_ipv6_unicast_key
*)key
+ i
;
946 luid
= (family
== AF_INET
) ? &key4
->luid
: &key6
->luid
;
947 if (luid
->Value
!= aa
->Luid
.Value
) continue;
948 addr
= heap_alloc_zero( sizeof(*addr
) + sockaddr_size
);
951 err
= ERROR_NOT_ENOUGH_MEMORY
;
954 addr
->Length
= sizeof(*addr
);
955 addr
->Address
.lpSockaddr
= (SOCKADDR
*)(addr
+ 1);
956 addr
->Address
.iSockaddrLength
= sockaddr_size
;
957 addr
->Address
.lpSockaddr
->sa_family
= family
;
958 if (family
== AF_INET
)
960 SOCKADDR_IN
*in
= (SOCKADDR_IN
*)addr
->Address
.lpSockaddr
;
961 in
->sin_addr
= key4
->addr
;
962 aa
->Ipv4Enabled
= TRUE
;
966 SOCKADDR_IN6
*in6
= (SOCKADDR_IN6
*)addr
->Address
.lpSockaddr
;
967 in6
->sin6_addr
= key6
->addr
;
968 in6
->sin6_scope_id
= dyn
[i
].scope_id
;
969 aa
->Ipv6Enabled
= TRUE
;
971 addr
->PrefixOrigin
= rw
[i
].prefix_origin
;
972 addr
->SuffixOrigin
= rw
[i
].suffix_origin
;
973 addr
->DadState
= dyn
[i
].dad_state
;
974 addr
->ValidLifetime
= rw
[i
].valid_lifetime
;
975 addr
->PreferredLifetime
= rw
[i
].preferred_lifetime
;
976 addr
->LeaseLifetime
= rw
[i
].valid_lifetime
; /* FIXME */
977 addr
->OnLinkPrefixLength
= rw
[i
].on_link_prefix
;
978 if (unicast_is_dns_eligible( addr
)) addr
->Flags
|= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE
;
987 NsiFreeTable( key
, rw
, dyn
, stat
);
991 static DWORD
gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
993 struct nsi_ipv4_forward_key
*key4
;
994 struct nsi_ipv6_forward_key
*key6
;
995 IP_ADAPTER_GATEWAY_ADDRESS
*gw
, **gw_next
;
996 IP_ADAPTER_PREFIX
*prefix
, **prefix_next
;
997 DWORD err
, count
, i
, prefix_len
, key_size
= (family
== AF_INET
) ? sizeof(*key4
) : sizeof(*key6
);
998 DWORD sockaddr_size
= (family
== AF_INET
) ? sizeof(SOCKADDR_IN
) : sizeof(SOCKADDR_IN6
);
999 SOCKADDR_INET sockaddr
;
1003 err
= NsiAllocateAndGetTable( 1, ip_module_id( family
), NSI_IP_FORWARD_TABLE
, &key
, key_size
,
1004 NULL
, 0, NULL
, 0, NULL
, 0, &count
, 0 );
1005 if (err
) return err
;
1009 for (gw_next
= &aa
->FirstGatewayAddress
; *gw_next
; gw_next
= &(*gw_next
)->Next
)
1011 for (prefix_next
= &aa
->FirstPrefix
; *prefix_next
; prefix_next
= &(*prefix_next
)->Next
)
1014 for (i
= 0; i
< count
; i
++)
1016 key4
= (struct nsi_ipv4_forward_key
*)key
+ i
;
1017 key6
= (struct nsi_ipv6_forward_key
*)key
+ i
;
1018 luid
= (family
== AF_INET
) ? &key4
->luid
: &key6
->luid
;
1019 if (luid
->Value
!= aa
->Luid
.Value
) continue;
1021 if (flags
& GAA_FLAG_INCLUDE_GATEWAYS
)
1023 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1024 if (family
== AF_INET
)
1026 if (key4
->next_hop
.s_addr
!= 0)
1028 sockaddr
.si_family
= family
;
1029 sockaddr
.Ipv4
.sin_addr
= key4
->next_hop
;
1034 static const IN6_ADDR zero
;
1035 if (memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1037 sockaddr
.si_family
= family
;
1038 sockaddr
.Ipv6
.sin6_addr
= key6
->next_hop
;
1042 if (sockaddr
.si_family
)
1044 gw
= heap_alloc_zero( sizeof(*gw
) + sockaddr_size
);
1047 err
= ERROR_NOT_ENOUGH_MEMORY
;
1050 gw
->Length
= sizeof(*gw
);
1051 gw
->Address
.lpSockaddr
= (SOCKADDR
*)(gw
+ 1);
1052 gw
->Address
.iSockaddrLength
= sockaddr_size
;
1053 memcpy( gw
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1055 gw_next
= &gw
->Next
;
1059 if (flags
& GAA_FLAG_INCLUDE_PREFIX
)
1061 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1063 if (family
== AF_INET
)
1065 if (!key4
->next_hop
.s_addr
)
1067 sockaddr
.si_family
= family
;
1068 sockaddr
.Ipv4
.sin_addr
= key4
->prefix
;
1069 prefix_len
= key4
->prefix_len
;
1074 static const IN6_ADDR zero
;
1075 if (!memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1077 sockaddr
.si_family
= family
;
1078 sockaddr
.Ipv6
.sin6_addr
= key6
->prefix
;
1079 prefix_len
= key6
->prefix_len
;
1083 if (sockaddr
.si_family
)
1085 prefix
= heap_alloc_zero( sizeof(*prefix
) + sockaddr_size
);
1088 err
= ERROR_NOT_ENOUGH_MEMORY
;
1091 prefix
->Length
= sizeof(*prefix
);
1092 prefix
->Address
.lpSockaddr
= (SOCKADDR
*)(prefix
+ 1);
1093 prefix
->Address
.iSockaddrLength
= sockaddr_size
;
1094 memcpy( prefix
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1095 prefix
->PrefixLength
= prefix_len
;
1096 *prefix_next
= prefix
;
1097 prefix_next
= &prefix
->Next
;
1105 NsiFreeTable( key
, NULL
, NULL
, NULL
);
1109 static DWORD
call_families( DWORD (*fn
)( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
),
1110 IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1114 if (family
!= AF_INET
)
1116 err
= fn( aa
, AF_INET6
, flags
);
1117 if (err
) return err
;
1120 if (family
!= AF_INET6
)
1122 err
= fn( aa
, AF_INET
, flags
);
1123 if (err
) return err
;
1128 static DWORD
dns_servers_query_code( ULONG family
)
1130 if (family
== AF_INET
) return DnsConfigDnsServersIpv4
;
1131 if (family
== AF_INET6
) return DnsConfigDnsServersIpv6
;
1132 return DnsConfigDnsServersUnspec
;
1135 static DWORD
dns_info_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1137 char buf
[FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[3])];
1138 IP_ADAPTER_DNS_SERVER_ADDRESS
*dns
, **next
;
1139 DWORD query
= dns_servers_query_code( family
);
1140 DWORD err
, i
, size
, attempt
, sockaddr_len
;
1141 WCHAR name
[MAX_ADAPTER_NAME_LENGTH
+ 1];
1142 DNS_ADDR_ARRAY
*servers
;
1147 MultiByteToWideChar( CP_ACP
, 0, aa
->AdapterName
, -1, name
, ARRAY_SIZE(name
) );
1148 if (!(flags
& GAA_FLAG_SKIP_DNS_SERVER
))
1150 servers
= (DNS_ADDR_ARRAY
*)buf
;
1151 for (attempt
= 0; attempt
< 5; attempt
++)
1153 err
= DnsQueryConfig( query
, 0, name
, NULL
, servers
, &size
);
1154 if (err
!= ERROR_MORE_DATA
) break;
1155 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1156 servers
= heap_alloc( size
);
1159 err
= ERROR_NOT_ENOUGH_MEMORY
;
1165 next
= &aa
->FirstDnsServerAddress
;
1166 for (i
= 0; i
< servers
->AddrCount
; i
++)
1168 sockaddr_len
= servers
->AddrArray
[i
].Data
.DnsAddrUserDword
[0];
1169 if (sockaddr_len
> sizeof(servers
->AddrArray
[i
].MaxSa
))
1170 sockaddr_len
= sizeof(servers
->AddrArray
[i
].MaxSa
);
1171 dns
= heap_alloc_zero( sizeof(*dns
) + sockaddr_len
);
1174 err
= ERROR_NOT_ENOUGH_MEMORY
;
1177 dns
->Length
= sizeof(*dns
);
1178 dns
->Address
.lpSockaddr
= (SOCKADDR
*)(dns
+ 1);
1179 dns
->Address
.iSockaddrLength
= sockaddr_len
;
1180 memcpy( dns
->Address
.lpSockaddr
, servers
->AddrArray
[i
].MaxSa
, sockaddr_len
);
1185 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1186 if (err
) return err
;
1189 aa
->DnsSuffix
= heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH
* sizeof(WCHAR
) );
1190 if (!aa
->DnsSuffix
) return ERROR_NOT_ENOUGH_MEMORY
;
1191 aa
->DnsSuffix
[0] = '\0';
1193 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, NULL
, &size
) &&
1194 (search
= heap_alloc( size
)))
1196 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, search
, &size
) &&
1197 search
[0] && wcslen( search
) < MAX_DNS_SUFFIX_STRING_LENGTH
)
1199 wcscpy( aa
->DnsSuffix
, search
);
1201 heap_free( search
);
1207 return ERROR_SUCCESS
;
1210 static DWORD
adapters_addresses_alloc( ULONG family
, ULONG flags
, IP_ADAPTER_ADDRESSES
**info
)
1212 IP_ADAPTER_ADDRESSES
*aa
;
1214 struct nsi_ndis_ifinfo_rw
*rw
;
1215 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1216 struct nsi_ndis_ifinfo_static
*stat
;
1217 DWORD err
, i
, count
, needed
;
1221 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&luids
, sizeof(*luids
),
1222 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1223 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1224 if (err
) return err
;
1226 needed
= count
* (sizeof(*aa
) + ((CHARS_IN_GUID
+ 1) & ~1) + sizeof(stat
->descr
.String
));
1227 needed
+= count
* sizeof(rw
->alias
.String
); /* GAA_FLAG_SKIP_FRIENDLY_NAME is ignored */
1229 aa
= heap_alloc_zero( needed
);
1232 err
= ERROR_NOT_ENOUGH_MEMORY
;
1236 str_ptr
= (char *)(aa
+ count
);
1237 for (i
= 0; i
< count
; i
++)
1239 aa
[i
].Length
= sizeof(*aa
);
1240 aa
[i
].IfIndex
= stat
[i
].if_index
;
1241 if (i
< count
- 1) aa
[i
].Next
= aa
+ i
+ 1;
1242 ConvertInterfaceLuidToGuid( luids
+ i
, &guid
);
1243 ConvertGuidToStringA( &guid
, str_ptr
, CHARS_IN_GUID
);
1244 aa
[i
].AdapterName
= str_ptr
;
1245 str_ptr
+= (CHARS_IN_GUID
+ 1) & ~1;
1246 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(stat
[i
].descr
.String
), &stat
[i
].descr
);
1247 aa
[i
].Description
= (WCHAR
*)str_ptr
;
1248 str_ptr
+= sizeof(stat
[i
].descr
.String
);
1249 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(rw
[i
].alias
.String
), &rw
[i
].alias
);
1250 aa
[i
].FriendlyName
= (WCHAR
*)str_ptr
;
1251 str_ptr
+= sizeof(rw
[i
].alias
.String
);
1252 aa
[i
].PhysicalAddressLength
= rw
[i
].phys_addr
.Length
;
1253 if (aa
[i
].PhysicalAddressLength
> sizeof(aa
[i
].PhysicalAddress
)) aa
[i
].PhysicalAddressLength
= 0;
1254 memcpy( aa
[i
].PhysicalAddress
, rw
[i
].phys_addr
.Address
, aa
[i
].PhysicalAddressLength
);
1255 aa
[i
].Mtu
= dyn
[i
].mtu
;
1256 aa
[i
].IfType
= stat
[i
].type
;
1257 aa
[i
].OperStatus
= dyn
[i
].oper_status
;
1258 aa
[i
].TransmitLinkSpeed
= dyn
[i
].xmit_speed
;
1259 aa
[i
].ReceiveLinkSpeed
= dyn
[i
].rcv_speed
;
1260 aa
[i
].Luid
= luids
[i
];
1261 aa
[i
].NetworkGuid
= rw
[i
].network_guid
;
1262 aa
[i
].ConnectionType
= stat
[i
].conn_type
;
1265 if (!(flags
& GAA_FLAG_SKIP_UNICAST
))
1267 err
= call_families( unicast_addresses_alloc
, aa
, family
, flags
);
1271 if (flags
& (GAA_FLAG_INCLUDE_GATEWAYS
| GAA_FLAG_INCLUDE_PREFIX
))
1273 err
= call_families( gateway_and_prefix_addresses_alloc
, aa
, family
, flags
);
1277 err
= dns_info_alloc( aa
, family
, flags
);
1281 NsiFreeTable( luids
, rw
, dyn
, stat
);
1282 if (!err
) *info
= aa
;
1283 else adapters_addresses_free( aa
);
1287 ULONG WINAPI DECLSPEC_HOTPATCH
GetAdaptersAddresses( ULONG family
, ULONG flags
, void *reserved
,
1288 IP_ADAPTER_ADDRESSES
*aa
, ULONG
*size
)
1290 IP_ADAPTER_ADDRESSES
*info
;
1293 TRACE( "(%ld, %08lx, %p, %p, %p)\n", family
, flags
, reserved
, aa
, size
);
1295 if (!size
) return ERROR_INVALID_PARAMETER
;
1297 err
= adapters_addresses_alloc( family
, flags
, &info
);
1298 if (err
) return err
;
1300 needed
= adapters_addresses_size( info
);
1301 if (!aa
|| *size
< needed
)
1304 err
= ERROR_BUFFER_OVERFLOW
;
1307 adapters_addresses_copy( aa
, info
);
1309 adapters_addresses_free( info
);
1313 /******************************************************************
1314 * GetBestInterface (IPHLPAPI.@)
1316 * Get the interface, with the best route for the given IP address.
1319 * dwDestAddr [In] IP address to search the interface for
1320 * pdwBestIfIndex [Out] found best interface
1324 * Failure: error code from winerror.h
1326 DWORD WINAPI
GetBestInterface(IPAddr dwDestAddr
, PDWORD pdwBestIfIndex
)
1328 struct sockaddr_in sa_in
;
1329 memset(&sa_in
, 0, sizeof(sa_in
));
1330 sa_in
.sin_family
= AF_INET
;
1331 sa_in
.sin_addr
.S_un
.S_addr
= dwDestAddr
;
1332 return GetBestInterfaceEx((struct sockaddr
*)&sa_in
, pdwBestIfIndex
);
1335 /******************************************************************
1336 * GetBestInterfaceEx (IPHLPAPI.@)
1338 * Get the interface, with the best route for the given IP address.
1341 * dwDestAddr [In] IP address to search the interface for
1342 * pdwBestIfIndex [Out] found best interface
1346 * Failure: error code from winerror.h
1348 DWORD WINAPI
GetBestInterfaceEx(struct sockaddr
*pDestAddr
, PDWORD pdwBestIfIndex
)
1352 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr
, pdwBestIfIndex
);
1353 if (!pDestAddr
|| !pdwBestIfIndex
)
1354 ret
= ERROR_INVALID_PARAMETER
;
1356 MIB_IPFORWARDROW ipRow
;
1358 if (pDestAddr
->sa_family
== AF_INET
) {
1359 ret
= GetBestRoute(((struct sockaddr_in
*)pDestAddr
)->sin_addr
.S_un
.S_addr
, 0, &ipRow
);
1360 if (ret
== ERROR_SUCCESS
)
1361 *pdwBestIfIndex
= ipRow
.dwForwardIfIndex
;
1363 FIXME("address family %d not supported\n", pDestAddr
->sa_family
);
1364 ret
= ERROR_NOT_SUPPORTED
;
1367 TRACE("returning %ld\n", ret
);
1372 /******************************************************************
1373 * GetBestRoute (IPHLPAPI.@)
1375 * Get the best route for the given IP address.
1378 * dwDestAddr [In] IP address to search the best route for
1379 * dwSourceAddr [In] optional source IP address
1380 * pBestRoute [Out] found best route
1384 * Failure: error code from winerror.h
1386 DWORD WINAPI
GetBestRoute(DWORD dwDestAddr
, DWORD dwSourceAddr
, PMIB_IPFORWARDROW pBestRoute
)
1388 PMIB_IPFORWARDTABLE table
;
1391 TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr
,
1392 dwSourceAddr
, pBestRoute
);
1394 return ERROR_INVALID_PARAMETER
;
1396 ret
= AllocateAndGetIpForwardTableFromStack(&table
, FALSE
, GetProcessHeap(), 0);
1398 DWORD ndx
, matchedBits
, matchedNdx
= table
->dwNumEntries
;
1400 for (ndx
= 0, matchedBits
= 0; ndx
< table
->dwNumEntries
; ndx
++) {
1401 if (table
->table
[ndx
].ForwardType
!= MIB_IPROUTE_TYPE_INVALID
&&
1402 (dwDestAddr
& table
->table
[ndx
].dwForwardMask
) ==
1403 (table
->table
[ndx
].dwForwardDest
& table
->table
[ndx
].dwForwardMask
)) {
1404 DWORD numShifts
, mask
;
1406 for (numShifts
= 0, mask
= table
->table
[ndx
].dwForwardMask
;
1407 mask
&& mask
& 1; mask
>>= 1, numShifts
++)
1409 if (numShifts
> matchedBits
) {
1410 matchedBits
= numShifts
;
1413 else if (!matchedBits
) {
1418 if (matchedNdx
< table
->dwNumEntries
) {
1419 memcpy(pBestRoute
, &table
->table
[matchedNdx
], sizeof(MIB_IPFORWARDROW
));
1420 ret
= ERROR_SUCCESS
;
1423 /* No route matches, which can happen if there's no default route. */
1424 ret
= ERROR_HOST_UNREACHABLE
;
1426 HeapFree(GetProcessHeap(), 0, table
);
1428 TRACE("returning %ld\n", ret
);
1433 /******************************************************************
1434 * GetFriendlyIfIndex (IPHLPAPI.@)
1436 * Get a "friendly" version of IfIndex, which is one that doesn't
1437 * have the top byte set. Doesn't validate whether IfIndex is a valid
1441 * IfIndex [In] interface index to get the friendly one for
1444 * A friendly version of IfIndex.
1446 DWORD WINAPI
GetFriendlyIfIndex(DWORD IfIndex
)
1448 /* windows doesn't validate these, either, just makes sure the top byte is
1449 cleared. I assume my ifenum module never gives an index with the top
1451 TRACE("returning %ld\n", IfIndex
);
1455 static void icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX
*stats_ex
, MIBICMPSTATS
*stats
)
1457 stats
->dwMsgs
= stats_ex
->dwMsgs
;
1458 stats
->dwErrors
= stats_ex
->dwErrors
;
1459 stats
->dwDestUnreachs
= stats_ex
->rgdwTypeCount
[ICMP4_DST_UNREACH
];
1460 stats
->dwTimeExcds
= stats_ex
->rgdwTypeCount
[ICMP4_TIME_EXCEEDED
];
1461 stats
->dwParmProbs
= stats_ex
->rgdwTypeCount
[ICMP4_PARAM_PROB
];
1462 stats
->dwSrcQuenchs
= stats_ex
->rgdwTypeCount
[ICMP4_SOURCE_QUENCH
];
1463 stats
->dwRedirects
= stats_ex
->rgdwTypeCount
[ICMP4_REDIRECT
];
1464 stats
->dwEchos
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REQUEST
];
1465 stats
->dwEchoReps
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REPLY
];
1466 stats
->dwTimestamps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
];
1467 stats
->dwTimestampReps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
];
1468 stats
->dwAddrMasks
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REQUEST
];
1469 stats
->dwAddrMaskReps
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REPLY
];
1472 /******************************************************************
1473 * GetIcmpStatistics (IPHLPAPI.@)
1475 * Get the ICMP statistics for the local computer.
1478 * stats [Out] buffer for ICMP statistics
1482 * Failure: error code from winerror.h
1484 DWORD WINAPI
GetIcmpStatistics( MIB_ICMP
*stats
)
1486 MIB_ICMP_EX stats_ex
;
1487 DWORD err
= GetIcmpStatisticsEx( &stats_ex
, AF_INET
);
1489 if (err
) return err
;
1491 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpInStats
, &stats
->stats
.icmpInStats
);
1492 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpOutStats
, &stats
->stats
.icmpOutStats
);
1496 /******************************************************************
1497 * GetIcmpStatisticsEx (IPHLPAPI.@)
1499 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1502 * stats [Out] buffer for ICMP statistics
1503 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1507 * Failure: error code from winerror.h
1509 DWORD WINAPI
GetIcmpStatisticsEx( MIB_ICMP_EX
*stats
, DWORD family
)
1511 const NPI_MODULEID
*mod
= ip_module_id( family
);
1512 struct nsi_ip_icmpstats_dynamic dyn
;
1515 if (!stats
|| !mod
) return ERROR_INVALID_PARAMETER
;
1516 memset( stats
, 0, sizeof(*stats
) );
1518 err
= NsiGetAllParameters( 1, mod
, NSI_IP_ICMPSTATS_TABLE
, NULL
, 0, NULL
, 0,
1519 &dyn
, sizeof(dyn
), NULL
, 0 );
1520 if (err
) return err
;
1522 stats
->icmpInStats
.dwMsgs
= dyn
.in_msgs
;
1523 stats
->icmpInStats
.dwErrors
= dyn
.in_errors
;
1524 memcpy( stats
->icmpInStats
.rgdwTypeCount
, dyn
.in_type_counts
, sizeof( dyn
.in_type_counts
) );
1525 stats
->icmpOutStats
.dwMsgs
= dyn
.out_msgs
;
1526 stats
->icmpOutStats
.dwErrors
= dyn
.out_errors
;
1527 memcpy( stats
->icmpOutStats
.rgdwTypeCount
, dyn
.out_type_counts
, sizeof( dyn
.out_type_counts
) );
1529 return ERROR_SUCCESS
;
1532 static void if_row_fill( MIB_IFROW
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1533 struct nsi_ndis_ifinfo_static
*stat
)
1535 wcscpy( row
->wszName
, device_tcpip
);
1536 ConvertGuidToStringW( &stat
->if_guid
, row
->wszName
+ wcslen( device_tcpip
), CHARS_IN_GUID
);
1537 row
->dwIndex
= stat
->if_index
;
1538 row
->dwType
= stat
->type
;
1539 row
->dwMtu
= dyn
->mtu
;
1540 row
->dwSpeed
= dyn
->rcv_speed
;
1541 row
->dwPhysAddrLen
= rw
->phys_addr
.Length
;
1542 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
1543 memcpy( row
->bPhysAddr
, rw
->phys_addr
.Address
, row
->dwPhysAddrLen
);
1544 row
->dwAdminStatus
= rw
->admin_status
;
1545 row
->dwOperStatus
= (dyn
->oper_status
== IfOperStatusUp
) ? MIB_IF_OPER_STATUS_OPERATIONAL
: MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
1546 row
->dwLastChange
= 0;
1547 row
->dwInOctets
= dyn
->in_octets
;
1548 row
->dwInUcastPkts
= dyn
->in_ucast_pkts
;
1549 row
->dwInNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1550 row
->dwInDiscards
= dyn
->in_discards
;
1551 row
->dwInErrors
= dyn
->in_errors
;
1552 row
->dwInUnknownProtos
= 0;
1553 row
->dwOutOctets
= dyn
->out_octets
;
1554 row
->dwOutUcastPkts
= dyn
->out_ucast_pkts
;
1555 row
->dwOutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1556 row
->dwOutDiscards
= dyn
->out_discards
;
1557 row
->dwOutErrors
= dyn
->out_errors
;
1559 row
->dwDescrLen
= WideCharToMultiByte( CP_ACP
, 0, stat
->descr
.String
, stat
->descr
.Length
/ sizeof(WCHAR
),
1560 (char *)row
->bDescr
, sizeof(row
->bDescr
) - 1, NULL
, NULL
);
1561 row
->bDescr
[row
->dwDescrLen
] = '\0';
1564 /******************************************************************
1565 * GetIfEntry (IPHLPAPI.@)
1567 * Get information about an interface.
1570 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1571 * Out: interface information
1575 * Failure: error code from winerror.h
1577 DWORD WINAPI
GetIfEntry( MIB_IFROW
*row
)
1579 struct nsi_ndis_ifinfo_rw rw
;
1580 struct nsi_ndis_ifinfo_dynamic dyn
;
1581 struct nsi_ndis_ifinfo_static stat
;
1585 TRACE( "row %p\n", row
);
1586 if (!row
) return ERROR_INVALID_PARAMETER
;
1588 err
= ConvertInterfaceIndexToLuid( row
->dwIndex
, &luid
);
1589 if (err
) return err
;
1591 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1592 &luid
, sizeof(luid
), &rw
, sizeof(rw
),
1593 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1594 if (!err
) if_row_fill( row
, &rw
, &dyn
, &stat
);
1598 static int DWORD_cmp( DWORD a
, DWORD b
)
1600 return a
< b
? -1 : a
> b
? 1 : 0; /* a subtraction would overflow */
1603 static int ifrow_cmp( const void *a
, const void *b
)
1605 const MIB_IFROW
*rowA
= a
, *rowB
= b
;
1606 return DWORD_cmp(rowA
->dwIndex
, rowB
->dwIndex
);
1609 /******************************************************************
1610 * GetIfTable (IPHLPAPI.@)
1612 * Get a table of local interfaces.
1615 * table [Out] buffer for local interfaces table
1616 * size [In/Out] length of output buffer
1617 * sort [In] whether to sort the table
1621 * Failure: error code from winerror.h
1624 * If size is less than required, the function will return
1625 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1627 * If sort is true, the returned table will be sorted by interface index.
1629 DWORD WINAPI
GetIfTable( MIB_IFTABLE
*table
, ULONG
*size
, BOOL sort
)
1631 DWORD i
, count
, needed
, err
;
1633 struct nsi_ndis_ifinfo_rw
*rw
;
1634 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1635 struct nsi_ndis_ifinfo_static
*stat
;
1637 if (!size
) return ERROR_INVALID_PARAMETER
;
1639 /* While this could be implemented on top of GetIfTable2(), it would require
1640 an additional copy of the data */
1641 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1642 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1643 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1644 if (err
) return err
;
1646 needed
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1648 if (!table
|| *size
< needed
)
1651 err
= ERROR_INSUFFICIENT_BUFFER
;
1655 table
->dwNumEntries
= count
;
1656 for (i
= 0; i
< count
; i
++)
1658 MIB_IFROW
*row
= table
->table
+ i
;
1660 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1663 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1666 NsiFreeTable( keys
, rw
, dyn
, stat
);
1670 /******************************************************************
1671 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1673 * Get table of local interfaces.
1674 * Like GetIfTable(), but allocate the returned table from heap.
1677 * table [Out] pointer into which the MIB_IFTABLE is
1678 * allocated and returned.
1679 * sort [In] whether to sort the table
1680 * heap [In] heap from which the table is allocated
1681 * flags [In] flags to HeapAlloc
1684 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1685 * GetIfTable() returns otherwise.
1687 DWORD WINAPI
AllocateAndGetIfTableFromStack( MIB_IFTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
1689 DWORD i
, count
, size
, err
;
1691 struct nsi_ndis_ifinfo_rw
*rw
;
1692 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1693 struct nsi_ndis_ifinfo_static
*stat
;
1695 if (!table
) return ERROR_INVALID_PARAMETER
;
1697 /* While this could be implemented on top of GetIfTable(), it would require
1698 an additional call to retrieve the size */
1699 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1700 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1701 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1702 if (err
) return err
;
1704 size
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1705 *table
= HeapAlloc( heap
, flags
, size
);
1708 err
= ERROR_NOT_ENOUGH_MEMORY
;
1712 (*table
)->dwNumEntries
= count
;
1713 for (i
= 0; i
< count
; i
++)
1715 MIB_IFROW
*row
= (*table
)->table
+ i
;
1717 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1719 if (sort
) qsort( (*table
)->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1722 NsiFreeTable( keys
, rw
, dyn
, stat
);
1726 static void if_row2_fill( MIB_IF_ROW2
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1727 struct nsi_ndis_ifinfo_static
*stat
)
1729 row
->InterfaceIndex
= stat
->if_index
;
1730 row
->InterfaceGuid
= stat
->if_guid
;
1731 if_counted_string_copy( row
->Alias
, ARRAY_SIZE(row
->Alias
), &rw
->alias
);
1732 if_counted_string_copy( row
->Description
, ARRAY_SIZE(row
->Description
), &stat
->descr
);
1733 row
->PhysicalAddressLength
= rw
->phys_addr
.Length
;
1734 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
)) row
->PhysicalAddressLength
= 0;
1735 memcpy( row
->PhysicalAddress
, rw
->phys_addr
.Address
, row
->PhysicalAddressLength
);
1736 memcpy( row
->PermanentPhysicalAddress
, stat
->perm_phys_addr
.Address
, row
->PhysicalAddressLength
);
1737 row
->Mtu
= dyn
->mtu
;
1738 row
->Type
= stat
->type
;
1739 row
->TunnelType
= TUNNEL_TYPE_NONE
; /* fixme */
1740 row
->MediaType
= stat
->media_type
;
1741 row
->PhysicalMediumType
= stat
->phys_medium_type
;
1742 row
->AccessType
= stat
->access_type
;
1743 row
->DirectionType
= NET_IF_DIRECTION_SENDRECEIVE
; /* fixme */
1744 row
->InterfaceAndOperStatusFlags
.HardwareInterface
= stat
->flags
.hw
;
1745 row
->InterfaceAndOperStatusFlags
.FilterInterface
= stat
->flags
.filter
;
1746 row
->InterfaceAndOperStatusFlags
.ConnectorPresent
= !!stat
->conn_present
;
1747 row
->InterfaceAndOperStatusFlags
.NotAuthenticated
= 0; /* fixme */
1748 row
->InterfaceAndOperStatusFlags
.NotMediaConnected
= dyn
->flags
.not_media_conn
;
1749 row
->InterfaceAndOperStatusFlags
.Paused
= 0; /* fixme */
1750 row
->InterfaceAndOperStatusFlags
.LowPower
= 0; /* fixme */
1751 row
->InterfaceAndOperStatusFlags
.EndPointInterface
= 0; /* fixme */
1752 row
->OperStatus
= dyn
->oper_status
;
1753 row
->AdminStatus
= rw
->admin_status
;
1754 row
->MediaConnectState
= dyn
->media_conn_state
;
1755 row
->NetworkGuid
= rw
->network_guid
;
1756 row
->ConnectionType
= stat
->conn_type
;
1757 row
->TransmitLinkSpeed
= dyn
->xmit_speed
;
1758 row
->ReceiveLinkSpeed
= dyn
->rcv_speed
;
1759 row
->InOctets
= dyn
->in_octets
;
1760 row
->InUcastPkts
= dyn
->in_ucast_pkts
;
1761 row
->InNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1762 row
->InDiscards
= dyn
->in_discards
;
1763 row
->InErrors
= dyn
->in_errors
;
1764 row
->InUnknownProtos
= 0; /* fixme */
1765 row
->InUcastOctets
= dyn
->in_ucast_octs
;
1766 row
->InMulticastOctets
= dyn
->in_mcast_octs
;
1767 row
->InBroadcastOctets
= dyn
->in_bcast_octs
;
1768 row
->OutOctets
= dyn
->out_octets
;
1769 row
->OutUcastPkts
= dyn
->out_ucast_pkts
;
1770 row
->OutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1771 row
->OutDiscards
= dyn
->out_discards
;
1772 row
->OutErrors
= dyn
->out_errors
;
1773 row
->OutUcastOctets
= dyn
->out_ucast_octs
;
1774 row
->OutMulticastOctets
= dyn
->out_mcast_octs
;
1775 row
->OutBroadcastOctets
= dyn
->out_bcast_octs
;
1776 row
->OutQLen
= 0; /* fixme */
1779 /******************************************************************
1780 * GetIfEntry2Ex (IPHLPAPI.@)
1782 DWORD WINAPI
GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_ROW2
*row
)
1785 struct nsi_ndis_ifinfo_rw rw
;
1786 struct nsi_ndis_ifinfo_dynamic dyn
;
1787 struct nsi_ndis_ifinfo_static stat
;
1789 TRACE( "(%d, %p)\n", level
, row
);
1791 if (level
!= MibIfTableNormal
) FIXME( "level %u not fully supported\n", level
);
1792 if (!row
) return ERROR_INVALID_PARAMETER
;
1794 if (!row
->InterfaceLuid
.Value
)
1796 if (!row
->InterfaceIndex
) return ERROR_INVALID_PARAMETER
;
1797 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
1798 if (err
) return err
;
1801 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1802 &row
->InterfaceLuid
, sizeof(row
->InterfaceLuid
),
1803 &rw
, sizeof(rw
), &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1804 if (!err
) if_row2_fill( row
, &rw
, &dyn
, &stat
);
1808 /******************************************************************
1809 * GetIfEntry2 (IPHLPAPI.@)
1811 DWORD WINAPI
GetIfEntry2( MIB_IF_ROW2
*row
)
1813 return GetIfEntry2Ex( MibIfTableNormal
, row
);
1816 /******************************************************************
1817 * GetIfTable2Ex (IPHLPAPI.@)
1819 DWORD WINAPI
GetIfTable2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_TABLE2
**table
)
1821 DWORD i
, count
, size
, err
;
1823 struct nsi_ndis_ifinfo_rw
*rw
;
1824 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1825 struct nsi_ndis_ifinfo_static
*stat
;
1827 TRACE( "level %u, table %p\n", level
, table
);
1829 if (!table
|| level
> MibIfTableNormalWithoutStatistics
)
1830 return ERROR_INVALID_PARAMETER
;
1832 if (level
!= MibIfTableNormal
)
1833 FIXME("level %u not fully supported\n", level
);
1835 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1836 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1837 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1838 if (err
) return err
;
1840 size
= FIELD_OFFSET( MIB_IF_TABLE2
, Table
[count
] );
1842 if (!(*table
= heap_alloc_zero( size
)))
1844 err
= ERROR_OUTOFMEMORY
;
1848 (*table
)->NumEntries
= count
;
1849 for (i
= 0; i
< count
; i
++)
1851 MIB_IF_ROW2
*row
= (*table
)->Table
+ i
;
1853 row
->InterfaceLuid
.Value
= keys
[i
].Value
;
1854 if_row2_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1857 NsiFreeTable( keys
, rw
, dyn
, stat
);
1861 /******************************************************************
1862 * GetIfTable2 (IPHLPAPI.@)
1864 DWORD WINAPI
GetIfTable2( MIB_IF_TABLE2
**table
)
1866 TRACE( "table %p\n", table
);
1867 return GetIfTable2Ex( MibIfTableNormal
, table
);
1870 /******************************************************************
1871 * GetInterfaceInfo (IPHLPAPI.@)
1873 * Get a list of network interface adapters.
1876 * pIfTable [Out] buffer for interface adapters
1877 * dwOutBufLen [Out] if buffer is too small, returns required size
1881 * Failure: error code from winerror.h
1884 * MSDN states this should return non-loopback interfaces only.
1886 DWORD WINAPI
GetInterfaceInfo( IP_INTERFACE_INFO
*table
, ULONG
*size
)
1889 struct nsi_ndis_ifinfo_static
*stat
;
1890 DWORD err
, count
, num
= 0, needed
, i
;
1892 TRACE( "table %p, size %p\n", table
, size
);
1893 if (!size
) return ERROR_INVALID_PARAMETER
;
1895 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1896 (void **)&keys
, sizeof(*keys
), NULL
, 0, NULL
, 0,
1897 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1898 if (err
) return err
;
1900 for (i
= 0; i
< count
; i
++)
1902 if (stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
1906 needed
= FIELD_OFFSET(IP_INTERFACE_INFO
, Adapter
[num
]);
1907 if (!table
|| *size
< needed
)
1910 err
= ERROR_INSUFFICIENT_BUFFER
;
1914 table
->NumAdapters
= num
;
1915 for (i
= 0, num
= 0; i
< count
; i
++)
1917 IP_ADAPTER_INDEX_MAP
*row
;
1919 if (stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
1920 row
= table
->Adapter
+ num
++;
1921 row
->Index
= stat
[i
].if_index
;
1922 wcscpy( row
->Name
, device_tcpip
);
1923 ConvertGuidToStringW( &stat
[i
].if_guid
, row
->Name
+ wcslen( device_tcpip
), CHARS_IN_GUID
);
1926 NsiFreeTable( keys
, NULL
, NULL
, stat
);
1930 static int ipaddrrow_cmp( const void *a
, const void *b
)
1932 const MIB_IPADDRROW
*rowA
= a
, *rowB
= b
;
1933 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwAddr
), RtlUlongByteSwap( rowB
->dwAddr
));
1936 /******************************************************************
1937 * GetIpAddrTable (IPHLPAPI.@)
1939 * Get interface-to-IP address mapping table.
1942 * table [Out] buffer for mapping table
1943 * size [In/Out] length of output buffer
1944 * sort [In] whether to sort the table
1948 * Failure: error code from winerror.h
1951 DWORD WINAPI
GetIpAddrTable( MIB_IPADDRTABLE
*table
, ULONG
*size
, BOOL sort
)
1953 DWORD err
, count
, needed
, i
, loopback
, row_num
= 0;
1954 struct nsi_ipv4_unicast_key
*keys
;
1955 struct nsi_ip_unicast_rw
*rw
;
1957 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
1958 if (!size
) return ERROR_INVALID_PARAMETER
;
1960 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&keys
, sizeof(*keys
),
1961 (void **)&rw
, sizeof(*rw
), NULL
, 0, NULL
, 0, &count
, 0 );
1962 if (err
) return err
;
1964 needed
= FIELD_OFFSET( MIB_IPADDRTABLE
, table
[count
] );
1966 if (!table
|| *size
< needed
)
1969 err
= ERROR_INSUFFICIENT_BUFFER
;
1973 table
->dwNumEntries
= count
;
1975 for (loopback
= 0; loopback
< 2; loopback
++) /* Move the loopback addresses to the end */
1977 for (i
= 0; i
< count
; i
++)
1979 MIB_IPADDRROW
*row
= table
->table
+ row_num
;
1981 if (!!loopback
!= (keys
[i
].luid
.Info
.IfType
== MIB_IF_TYPE_LOOPBACK
)) continue;
1983 row
->dwAddr
= keys
[i
].addr
.s_addr
;
1984 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
1985 ConvertLengthToIpv4Mask( rw
[i
].on_link_prefix
, &row
->dwMask
);
1986 row
->dwBCastAddr
= 1;
1987 row
->dwReasmSize
= 0xffff;
1989 row
->wType
= MIB_IPADDR_PRIMARY
;
1994 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPADDRROW
), ipaddrrow_cmp
);
1996 NsiFreeTable( keys
, rw
, NULL
, NULL
);
2002 /******************************************************************
2003 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2005 * Get interface-to-IP address mapping table.
2006 * Like GetIpAddrTable(), but allocate the returned table from heap.
2009 * table [Out] pointer into which the MIB_IPADDRTABLE is
2010 * allocated and returned.
2011 * sort [In] whether to sort the table
2012 * heap [In] heap from which the table is allocated
2013 * flags [In] flags to HeapAlloc
2016 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2018 DWORD err
, size
= FIELD_OFFSET(MIB_IPADDRTABLE
, table
[2]), attempt
;
2020 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2022 for (attempt
= 0; attempt
< 5; attempt
++)
2024 *table
= HeapAlloc( heap
, flags
, size
);
2025 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2027 err
= GetIpAddrTable( *table
, &size
, sort
);
2029 HeapFree( heap
, flags
, *table
);
2030 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2036 static int ipforward_row_cmp( const void *a
, const void *b
)
2038 const MIB_IPFORWARDROW
*rowA
= a
, *rowB
= b
;
2039 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwForwardDest
), RtlUlongByteSwap( rowB
->dwForwardDest
)) ||
2040 DWORD_cmp(rowA
->dwForwardProto
, rowB
->dwForwardProto
) ||
2041 DWORD_cmp(rowA
->dwForwardPolicy
, rowB
->dwForwardPolicy
) ||
2042 DWORD_cmp(RtlUlongByteSwap( rowA
->dwForwardNextHop
), RtlUlongByteSwap( rowB
->dwForwardNextHop
));
2045 /******************************************************************
2046 * GetIpForwardTable (IPHLPAPI.@)
2048 * Get the route table.
2051 * table [Out] buffer for route table
2052 * size [In/Out] length of output buffer
2053 * sort [In] whether to sort the table
2057 * Failure: error code from winerror.h
2059 DWORD WINAPI
GetIpForwardTable( MIB_IPFORWARDTABLE
*table
, ULONG
*size
, BOOL sort
)
2061 DWORD err
, count
, uni_count
, needed
, i
, addr
;
2062 struct nsi_ipv4_forward_key
*keys
;
2063 struct nsi_ip_forward_rw
*rw
;
2064 struct nsi_ipv4_forward_dynamic
*dyn
;
2065 struct nsi_ip_forward_static
*stat
;
2066 struct nsi_ipv4_unicast_key
*uni_keys
= NULL
;
2068 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2069 if (!size
) return ERROR_INVALID_PARAMETER
;
2071 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_FORWARD_TABLE
, (void **)&keys
, sizeof(*keys
),
2072 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2073 (void **)&stat
, sizeof(*stat
), &count
, 0 );
2074 if (err
) return err
;
2076 needed
= FIELD_OFFSET( MIB_IPFORWARDTABLE
, table
[count
] );
2078 if (!table
|| *size
< needed
)
2081 err
= ERROR_INSUFFICIENT_BUFFER
;
2085 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&uni_keys
, sizeof(*uni_keys
),
2086 NULL
, 0, NULL
, 0, NULL
, 0, &uni_count
, 0 );
2089 table
->dwNumEntries
= count
;
2090 for (i
= 0; i
< count
; i
++)
2092 MIB_IPFORWARDROW
*row
= table
->table
+ i
;
2094 row
->dwForwardDest
= keys
[i
].prefix
.s_addr
;
2095 ConvertLengthToIpv4Mask( keys
[i
].prefix_len
, &row
->dwForwardMask
);
2096 row
->dwForwardPolicy
= 0;
2097 row
->dwForwardNextHop
= keys
[i
].next_hop
.s_addr
;
2098 row
->dwForwardType
= row
->dwForwardNextHop
? MIB_IPROUTE_TYPE_INDIRECT
: MIB_IPROUTE_TYPE_DIRECT
;
2099 if (!row
->dwForwardNextHop
) /* find the interface's addr */
2101 for (addr
= 0; addr
< uni_count
; addr
++)
2103 if (uni_keys
[addr
].luid
.Value
== keys
[i
].luid
.Value
)
2105 row
->dwForwardNextHop
= uni_keys
[addr
].addr
.s_addr
;
2110 row
->dwForwardIfIndex
= stat
[i
].if_index
;
2111 row
->dwForwardProto
= rw
[i
].protocol
;
2112 row
->dwForwardAge
= dyn
[i
].age
;
2113 row
->dwForwardNextHopAS
= 0;
2114 row
->dwForwardMetric1
= rw
[i
].metric
; /* FIXME: add interface metric */
2115 row
->dwForwardMetric2
= 0;
2116 row
->dwForwardMetric3
= 0;
2117 row
->dwForwardMetric4
= 0;
2118 row
->dwForwardMetric5
= 0;
2121 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPFORWARDROW
), ipforward_row_cmp
);
2123 NsiFreeTable( uni_keys
, NULL
, NULL
, NULL
);
2124 NsiFreeTable( keys
, rw
, dyn
, stat
);
2129 /******************************************************************
2130 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2132 * Get the route table.
2133 * Like GetIpForwardTable(), but allocate the returned table from heap.
2136 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2137 * allocated and returned.
2138 * sort [In] whether to sort the table
2139 * heap [In] heap from which the table is allocated
2140 * flags [In] flags to HeapAlloc
2143 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2144 * on failure, NO_ERROR on success.
2146 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2148 DWORD err
, size
= FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[2]), attempt
;
2150 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2152 for (attempt
= 0; attempt
< 5; attempt
++)
2154 *table
= HeapAlloc( heap
, flags
, size
);
2155 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2157 err
= GetIpForwardTable( *table
, &size
, sort
);
2159 HeapFree( heap
, flags
, *table
);
2160 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2166 static void forward_row2_fill( MIB_IPFORWARD_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_forward_rw
*rw
,
2167 void *dyn
, struct nsi_ip_forward_static
*stat
)
2169 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
;
2170 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
;
2171 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
;
2172 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
;
2176 row
->InterfaceLuid
= key4
->luid
;
2177 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_family
= fam
;
2178 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_port
= 0;
2179 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_addr
= key4
->prefix
;
2180 memset( &row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
, 0, sizeof(row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
) );
2181 row
->DestinationPrefix
.PrefixLength
= key4
->prefix_len
;
2182 row
->NextHop
.Ipv4
.sin_family
= fam
;
2183 row
->NextHop
.Ipv4
.sin_port
= 0;
2184 row
->NextHop
.Ipv4
.sin_addr
= key4
->next_hop
;
2185 memset( &row
->NextHop
.Ipv4
.sin_zero
, 0, sizeof(row
->NextHop
.Ipv4
.sin_zero
) );
2187 row
->Age
= dyn4
->age
;
2191 row
->InterfaceLuid
= key6
->luid
;
2193 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_family
= fam
;
2194 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_port
= 0;
2195 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_flowinfo
= 0;
2196 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_addr
= key6
->prefix
;
2197 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_scope_id
= 0;
2198 row
->DestinationPrefix
.PrefixLength
= key6
->prefix_len
;
2199 row
->NextHop
.Ipv6
.sin6_family
= fam
;
2200 row
->NextHop
.Ipv6
.sin6_port
= 0;
2201 row
->NextHop
.Ipv6
.sin6_flowinfo
= 0;
2202 row
->NextHop
.Ipv6
.sin6_addr
= key6
->next_hop
;
2203 row
->NextHop
.Ipv6
.sin6_scope_id
= 0;
2205 row
->Age
= dyn6
->age
;
2208 row
->InterfaceIndex
= stat
->if_index
;
2210 row
->SitePrefixLength
= rw
->site_prefix_len
;
2211 row
->ValidLifetime
= rw
->valid_lifetime
;
2212 row
->PreferredLifetime
= rw
->preferred_lifetime
;
2213 row
->Metric
= rw
->metric
;
2214 row
->Protocol
= rw
->protocol
;
2215 row
->Loopback
= rw
->loopback
;
2216 row
->AutoconfigureAddress
= rw
->autoconf
;
2217 row
->Publish
= rw
->publish
;
2218 row
->Immortal
= rw
->immortal
;
2220 row
->Origin
= stat
->origin
;
2223 /******************************************************************
2224 * GetIpForwardTable2 (IPHLPAPI.@)
2226 DWORD WINAPI
GetIpForwardTable2( ADDRESS_FAMILY family
, MIB_IPFORWARD_TABLE2
**table
)
2228 void *key
[2] = { NULL
, NULL
};
2229 struct nsi_ip_forward_rw
*rw
[2] = { NULL
, NULL
};
2230 void *dyn
[2] = { NULL
, NULL
};
2231 struct nsi_ip_forward_static
*stat
[2] = { NULL
, NULL
};
2232 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
2233 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_forward_key
), sizeof(struct nsi_ipv6_forward_key
) };
2234 static const DWORD dyn_size
[2] = { sizeof(struct nsi_ipv4_forward_dynamic
), sizeof(struct nsi_ipv6_forward_dynamic
) };
2235 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2237 TRACE( "%u, %p\n", family
, table
);
2239 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
2240 return ERROR_INVALID_PARAMETER
;
2242 for (i
= 0; i
< 2; i
++)
2244 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
2246 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_FORWARD_TABLE
, key
+ i
, key_size
[i
],
2247 (void **)rw
+ i
, sizeof(**rw
), dyn
+ i
, dyn_size
[i
],
2248 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
2249 if (err
) count
[i
] = 0;
2252 size
= FIELD_OFFSET(MIB_IPFORWARD_TABLE2
, Table
[ count
[0] + count
[1] ]);
2253 *table
= heap_alloc( size
);
2256 err
= ERROR_NOT_ENOUGH_MEMORY
;
2260 (*table
)->NumEntries
= count
[0] + count
[1];
2261 for (i
= 0; i
< count
[0]; i
++)
2263 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ i
;
2264 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
[0];
2265 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
[0];
2267 forward_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn4
+ i
, stat
[0] + i
);
2270 for (i
= 0; i
< count
[1]; i
++)
2272 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2273 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
[1];
2274 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
[1];
2276 forward_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn6
+ i
, stat
[1] + i
);
2280 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
2284 static int ipnetrow_cmp( const void *a
, const void *b
)
2286 const MIB_IPNETROW
*rowA
= a
, *rowB
= b
;
2288 if (rowA
->dwIndex
!= rowB
->dwIndex
) return DWORD_cmp( rowA
->dwIndex
, rowB
->dwIndex
);
2290 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwAddr
), RtlUlongByteSwap( rowB
->dwAddr
));
2293 /******************************************************************
2294 * GetIpNetTable (IPHLPAPI.@)
2296 * Get the IP-to-physical address mapping table.
2299 * table [Out] buffer for mapping table
2300 * size [In/Out] length of output buffer
2301 * sort [In] whether to sort the table
2305 * Failure: error code from winerror.h
2308 DWORD WINAPI
GetIpNetTable( MIB_IPNETTABLE
*table
, ULONG
*size
, BOOL sort
)
2310 DWORD err
, count
, needed
, i
;
2311 struct nsi_ipv4_neighbour_key
*keys
;
2312 struct nsi_ip_neighbour_rw
*rw
;
2313 struct nsi_ip_neighbour_dynamic
*dyn
;
2315 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2317 if (!size
) return ERROR_INVALID_PARAMETER
;
2319 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_NEIGHBOUR_TABLE
, (void **)&keys
, sizeof(*keys
),
2320 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2321 NULL
, 0, &count
, 0 );
2322 if (err
) return err
;
2324 needed
= FIELD_OFFSET( MIB_IPNETTABLE
, table
[count
] );
2326 if (!table
|| *size
< needed
)
2329 err
= ERROR_INSUFFICIENT_BUFFER
;
2333 table
->dwNumEntries
= count
;
2337 err
= ERROR_NO_DATA
;
2341 for (i
= 0; i
< count
; i
++)
2343 MIB_IPNETROW
*row
= table
->table
+ i
;
2345 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
2346 row
->dwPhysAddrLen
= dyn
[i
].phys_addr_len
;
2347 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
2348 memcpy( row
->bPhysAddr
, rw
[i
].phys_addr
, row
->dwPhysAddrLen
);
2349 memset( row
->bPhysAddr
+ row
->dwPhysAddrLen
, 0,
2350 sizeof(row
->bPhysAddr
) - row
->dwPhysAddrLen
);
2351 row
->dwAddr
= keys
[i
].addr
.s_addr
;
2353 switch (dyn
[i
].state
)
2355 case NlnsUnreachable
:
2356 case NlnsIncomplete
:
2357 row
->Type
= MIB_IPNET_TYPE_INVALID
;
2363 row
->Type
= MIB_IPNET_TYPE_DYNAMIC
;
2366 row
->Type
= MIB_IPNET_TYPE_STATIC
;
2369 row
->Type
= MIB_IPNET_TYPE_OTHER
;
2373 if (sort
) qsort( table
->table
, table
->dwNumEntries
, sizeof(*table
->table
), ipnetrow_cmp
);
2376 NsiFreeTable( keys
, rw
, dyn
, NULL
);
2380 /******************************************************************
2381 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2383 DWORD WINAPI
AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2385 DWORD err
, size
= FIELD_OFFSET(MIB_IPNETTABLE
, table
[2]), attempt
;
2387 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2389 for (attempt
= 0; attempt
< 5; attempt
++)
2391 *table
= HeapAlloc( heap
, flags
, size
);
2392 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2394 err
= GetIpNetTable( *table
, &size
, sort
);
2396 HeapFree( heap
, flags
, *table
);
2397 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2403 static void ipnet_row2_fill( MIB_IPNET_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_neighbour_rw
*rw
,
2404 struct nsi_ip_neighbour_dynamic
*dyn
)
2406 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
;
2407 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
;
2411 row
->Address
.Ipv4
.sin_family
= fam
;
2412 row
->Address
.Ipv4
.sin_port
= 0;
2413 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
2414 memset( &row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
2415 row
->InterfaceLuid
= key4
->luid
;
2419 row
->Address
.Ipv6
.sin6_family
= fam
;
2420 row
->Address
.Ipv6
.sin6_port
= 0;
2421 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
2422 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
2423 row
->Address
.Ipv6
.sin6_scope_id
= 0;
2424 row
->InterfaceLuid
= key6
->luid
;
2427 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
2429 row
->PhysicalAddressLength
= dyn
->phys_addr_len
;
2430 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
))
2431 row
->PhysicalAddressLength
= 0;
2432 memcpy( row
->PhysicalAddress
, rw
->phys_addr
, row
->PhysicalAddressLength
);
2433 memset( row
->PhysicalAddress
+ row
->PhysicalAddressLength
, 0,
2434 sizeof(row
->PhysicalAddress
) - row
->PhysicalAddressLength
);
2435 row
->State
= dyn
->state
;
2437 row
->IsRouter
= dyn
->flags
.is_router
;
2438 row
->IsUnreachable
= dyn
->flags
.is_unreachable
;
2439 row
->ReachabilityTime
.LastReachable
= dyn
->time
;
2442 /******************************************************************
2443 * GetIpNetTable2 (IPHLPAPI.@)
2445 DWORD WINAPI
GetIpNetTable2( ADDRESS_FAMILY family
, MIB_IPNET_TABLE2
**table
)
2447 void *key
[2] = { NULL
, NULL
};
2448 struct nsi_ip_neighbour_rw
*rw
[2] = { NULL
, NULL
};
2449 struct nsi_ip_neighbour_dynamic
*dyn
[2] = { NULL
, NULL
};
2450 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
2451 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_neighbour_key
), sizeof(struct nsi_ipv6_neighbour_key
) };
2452 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2454 TRACE( "%u, %p\n", family
, table
);
2456 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
2457 return ERROR_INVALID_PARAMETER
;
2459 for (i
= 0; i
< 2; i
++)
2461 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
2463 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_NEIGHBOUR_TABLE
, key
+ i
, key_size
[i
],
2464 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
2465 NULL
, 0, count
+ i
, 0 );
2466 if (err
) count
[i
] = 0;
2469 size
= FIELD_OFFSET(MIB_IPNET_TABLE2
, Table
[ count
[0] + count
[1] ]);
2470 *table
= heap_alloc( size
);
2473 err
= ERROR_NOT_ENOUGH_MEMORY
;
2477 (*table
)->NumEntries
= count
[0] + count
[1];
2478 for (i
= 0; i
< count
[0]; i
++)
2480 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ i
;
2481 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
[0];
2483 ipnet_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn
[0] + i
);
2486 for (i
= 0; i
< count
[1]; i
++)
2488 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2489 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
[1];
2491 ipnet_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn
[1] + i
);
2495 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], NULL
);
2499 /******************************************************************
2500 * GetIpStatistics (IPHLPAPI.@)
2502 * Get the IP statistics for the local computer.
2505 * stats [Out] buffer for IP statistics
2509 * Failure: error code from winerror.h
2511 DWORD WINAPI
GetIpStatistics( MIB_IPSTATS
*stats
)
2513 return GetIpStatisticsEx( stats
, AF_INET
);
2516 /******************************************************************
2517 * GetIpStatisticsEx (IPHLPAPI.@)
2519 * Get the IPv4 and IPv6 statistics for the local computer.
2522 * stats [Out] buffer for IP statistics
2523 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2527 * Failure: error code from winerror.h
2529 DWORD WINAPI
GetIpStatisticsEx( MIB_IPSTATS
*stats
, DWORD family
)
2531 struct nsi_ip_ipstats_dynamic dyn
;
2532 struct nsi_ip_ipstats_static stat
;
2533 struct nsi_ip_cmpt_rw cmpt_rw
;
2534 struct nsi_ip_cmpt_dynamic cmpt_dyn
;
2535 const NPI_MODULEID
*mod
;
2536 DWORD err
, cmpt
= 1;
2538 TRACE( "%p %ld\n", stats
, family
);
2540 if (!stats
) return ERROR_INVALID_PARAMETER
;
2541 mod
= ip_module_id( family
);
2542 if (!mod
) return ERROR_INVALID_PARAMETER
;
2544 memset( stats
, 0, sizeof(*stats
) );
2546 err
= NsiGetAllParameters( 1, mod
, NSI_IP_IPSTATS_TABLE
, NULL
, 0, NULL
, 0,
2547 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2548 if (err
) return err
;
2550 err
= NsiGetAllParameters( 1, mod
, NSI_IP_COMPARTMENT_TABLE
, &cmpt
, sizeof(cmpt
), &cmpt_rw
, sizeof(cmpt_rw
),
2551 &cmpt_dyn
, sizeof(cmpt_dyn
), NULL
, 0 );
2552 if (err
) return err
;
2554 stats
->Forwarding
= cmpt_rw
.not_forwarding
+ 1;
2555 stats
->dwDefaultTTL
= cmpt_rw
.default_ttl
;
2556 stats
->dwInReceives
= dyn
.in_recv
;
2557 stats
->dwInHdrErrors
= dyn
.in_hdr_errs
;
2558 stats
->dwInAddrErrors
= dyn
.in_addr_errs
;
2559 stats
->dwForwDatagrams
= dyn
.fwd_dgrams
;
2560 stats
->dwInUnknownProtos
= dyn
.in_unk_protos
;
2561 stats
->dwInDiscards
= dyn
.in_discards
;
2562 stats
->dwInDelivers
= dyn
.in_delivers
;
2563 stats
->dwOutRequests
= dyn
.out_reqs
;
2564 stats
->dwRoutingDiscards
= dyn
.routing_discards
;
2565 stats
->dwOutDiscards
= dyn
.out_discards
;
2566 stats
->dwOutNoRoutes
= dyn
.out_no_routes
;
2567 stats
->dwReasmTimeout
= stat
.reasm_timeout
;
2568 stats
->dwReasmReqds
= dyn
.reasm_reqds
;
2569 stats
->dwReasmOks
= dyn
.reasm_oks
;
2570 stats
->dwReasmFails
= dyn
.reasm_fails
;
2571 stats
->dwFragOks
= dyn
.frag_oks
;
2572 stats
->dwFragFails
= dyn
.frag_fails
;
2573 stats
->dwFragCreates
= dyn
.frag_creates
;
2574 stats
->dwNumIf
= cmpt_dyn
.num_ifs
;
2575 stats
->dwNumAddr
= cmpt_dyn
.num_addrs
;
2576 stats
->dwNumRoutes
= cmpt_dyn
.num_routes
;
2581 /* Gets the DNS server list into the list beginning at list. Assumes that
2582 * a single server address may be placed at list if *len is at least
2583 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2584 * and assumes that all remaining DNS servers are contiguously located
2585 * beginning at second. On input, *len is assumed to be the total number
2586 * of bytes available for all DNS servers, and is ignored if list is NULL.
2587 * On return, *len is set to the total number of bytes required for all DNS
2589 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2590 * ERROR_SUCCESS otherwise.
2592 static DWORD
get_dns_server_list( const NET_LUID
*luid
, IP_ADDR_STRING
*list
, IP_ADDR_STRING
*second
, DWORD
*len
)
2594 char buf
[FIELD_OFFSET(IP4_ARRAY
, AddrArray
[3])];
2595 IP4_ARRAY
*servers
= (IP4_ARRAY
*)buf
;
2596 DWORD needed
, num
, err
, i
, array_len
= sizeof(buf
);
2597 IP_ADDR_STRING
*ptr
;
2599 if (luid
&& luid
->Info
.IfType
== MIB_IF_TYPE_LOOPBACK
) return ERROR_NO_DATA
;
2603 err
= DnsQueryConfig( DnsConfigDnsServerList
, 0, NULL
, NULL
, servers
, &array_len
);
2604 if (err
!= ERROR_SUCCESS
&& err
!= ERROR_MORE_DATA
) goto err
;
2605 num
= (array_len
- FIELD_OFFSET(IP4_ARRAY
, AddrArray
[0])) / sizeof(IP4_ADDRESS
);
2606 needed
= num
* sizeof(IP_ADDR_STRING
);
2607 if (!list
|| *len
< needed
)
2610 err
= ERROR_BUFFER_OVERFLOW
;
2615 if ((char *)servers
!= buf
) heap_free( servers
);
2616 servers
= heap_alloc( array_len
);
2619 err
= ERROR_NOT_ENOUGH_MEMORY
;
2626 for (i
= 0, ptr
= list
; i
< num
; i
++, ptr
= ptr
->Next
)
2628 RtlIpv4AddressToStringA( (IN_ADDR
*)&servers
->AddrArray
[i
], ptr
->IpAddress
.String
);
2629 if (i
== num
- 1) ptr
->Next
= NULL
;
2630 else if (i
== 0) ptr
->Next
= second
;
2631 else ptr
->Next
= ptr
+ 1;
2635 if ((char *)servers
!= buf
) heap_free( servers
);
2639 /******************************************************************
2640 * GetNetworkParams (IPHLPAPI.@)
2642 * Get the network parameters for the local computer.
2645 * info [Out] buffer for network parameters
2646 * size [In/Out] length of output buffer
2650 * Failure: error code from winerror.h
2653 * If size is less than required, the function will return
2654 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2657 DWORD WINAPI
GetNetworkParams( FIXED_INFO
*info
, ULONG
*size
)
2659 DWORD needed
= sizeof(*info
), dns_size
, err
;
2660 MIB_IPSTATS ip_stats
;
2663 TRACE( "info %p, size %p\n", info
, size
);
2664 if (!size
) return ERROR_INVALID_PARAMETER
;
2666 if (get_dns_server_list( NULL
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2667 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2668 if (!info
|| *size
< needed
)
2671 return ERROR_BUFFER_OVERFLOW
;
2675 memset( info
, 0, needed
);
2676 needed
= sizeof(info
->HostName
);
2677 GetComputerNameExA( ComputerNameDnsHostname
, info
->HostName
, &needed
);
2678 needed
= sizeof(info
->DomainName
);
2679 GetComputerNameExA( ComputerNameDnsDomain
, info
->DomainName
, &needed
);
2680 get_dns_server_list( NULL
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2681 info
->CurrentDnsServer
= &info
->DnsServerList
;
2682 info
->NodeType
= HYBRID_NODETYPE
;
2683 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2684 0, KEY_READ
, &key
);
2686 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2687 0, KEY_READ
, &key
);
2690 needed
= sizeof(info
->ScopeId
);
2691 RegQueryValueExA( key
, "ScopeID", NULL
, NULL
, (BYTE
*)info
->ScopeId
, &needed
);
2695 if (!GetIpStatistics( &ip_stats
))
2696 info
->EnableRouting
= (ip_stats
.Forwarding
== MIB_IP_FORWARDING
);
2698 return ERROR_SUCCESS
;
2702 /******************************************************************
2703 * GetNumberOfInterfaces (IPHLPAPI.@)
2705 * Get the number of interfaces.
2708 * pdwNumIf [Out] number of interfaces
2711 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2713 DWORD WINAPI
GetNumberOfInterfaces( DWORD
*count
)
2717 TRACE( "count %p\n", count
);
2718 if (!count
) return ERROR_INVALID_PARAMETER
;
2720 err
= NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, NULL
, 0,
2721 NULL
, 0, NULL
, 0, NULL
, 0, &num
);
2722 *count
= err
? 0 : num
;
2726 /******************************************************************
2727 * GetPerAdapterInfo (IPHLPAPI.@)
2729 * Get information about an adapter corresponding to an interface.
2732 * IfIndex [In] interface info
2733 * pPerAdapterInfo [Out] buffer for per adapter info
2734 * pOutBufLen [In/Out] length of output buffer
2738 * Failure: error code from winerror.h
2740 DWORD WINAPI
GetPerAdapterInfo( ULONG index
, IP_PER_ADAPTER_INFO
*info
, ULONG
*size
)
2742 DWORD needed
= sizeof(*info
), dns_size
;
2745 TRACE( "(index %ld, info %p, size %p)\n", index
, info
, size
);
2747 if (!size
) return ERROR_INVALID_PARAMETER
;
2748 if (ConvertInterfaceIndexToLuid( index
, &luid
)) return ERROR_NO_DATA
;
2750 if (get_dns_server_list( &luid
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2751 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2753 if (!info
|| *size
< needed
)
2756 return ERROR_BUFFER_OVERFLOW
;
2759 memset( info
, 0, needed
);
2760 get_dns_server_list( &luid
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2761 info
->CurrentDnsServer
= &info
->DnsServerList
;
2763 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2764 return ERROR_SUCCESS
;
2768 /******************************************************************
2769 * GetRTTAndHopCount (IPHLPAPI.@)
2771 * Get round-trip time (RTT) and hop count.
2775 * DestIpAddress [In] destination address to get the info for
2776 * HopCount [Out] retrieved hop count
2777 * MaxHops [In] maximum hops to search for the destination
2778 * RTT [Out] RTT in milliseconds
2785 * Stub, returns FALSE.
2787 BOOL WINAPI
GetRTTAndHopCount(IPAddr DestIpAddress
, PULONG HopCount
, ULONG MaxHops
, PULONG RTT
)
2789 FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
2790 DestIpAddress
, HopCount
, MaxHops
, RTT
);
2794 /******************************************************************
2795 * GetTcpStatistics (IPHLPAPI.@)
2797 * Get the TCP statistics for the local computer.
2800 * stats [Out] buffer for TCP statistics
2804 * Failure: error code from winerror.h
2806 DWORD WINAPI
GetTcpStatistics( MIB_TCPSTATS
*stats
)
2808 return GetTcpStatisticsEx( stats
, AF_INET
);
2811 /******************************************************************
2812 * GetTcpStatisticsEx (IPHLPAPI.@)
2814 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2817 * stats [Out] buffer for TCP statistics
2818 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2822 * Failure: error code from winerror.h
2824 DWORD WINAPI
GetTcpStatisticsEx( MIB_TCPSTATS
*stats
, DWORD family
)
2826 struct nsi_tcp_stats_dynamic dyn
;
2827 struct nsi_tcp_stats_static stat
;
2828 USHORT key
= (USHORT
)family
;
2831 if (!stats
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
2832 memset( stats
, 0, sizeof(*stats
) );
2834 err
= NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID
, NSI_TCP_STATS_TABLE
, &key
, sizeof(key
), NULL
, 0,
2835 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2836 if (err
) return err
;
2838 stats
->RtoAlgorithm
= stat
.rto_algo
;
2839 stats
->dwRtoMin
= stat
.rto_min
;
2840 stats
->dwRtoMax
= stat
.rto_max
;
2841 stats
->dwMaxConn
= stat
.max_conns
;
2842 stats
->dwActiveOpens
= dyn
.active_opens
;
2843 stats
->dwPassiveOpens
= dyn
.passive_opens
;
2844 stats
->dwAttemptFails
= dyn
.attempt_fails
;
2845 stats
->dwEstabResets
= dyn
.est_rsts
;
2846 stats
->dwCurrEstab
= dyn
.cur_est
;
2847 stats
->dwInSegs
= (DWORD
)dyn
.in_segs
;
2848 stats
->dwOutSegs
= (DWORD
)dyn
.out_segs
;
2849 stats
->dwRetransSegs
= dyn
.retrans_segs
;
2850 stats
->dwInErrs
= dyn
.in_errs
;
2851 stats
->dwOutRsts
= dyn
.out_rsts
;
2852 stats
->dwNumConns
= dyn
.num_conns
;
2857 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2859 static DWORD
tcp_table_id( ULONG table_class
)
2861 switch (table_class
)
2863 case TCP_TABLE_BASIC_LISTENER
:
2864 case TCP_TABLE_OWNER_PID_LISTENER
:
2865 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2866 return NSI_TCP_LISTEN_TABLE
;
2868 case TCP_TABLE_BASIC_CONNECTIONS
:
2869 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2870 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2871 return NSI_TCP_ESTAB_TABLE
;
2873 case TCP_TABLE_BASIC_ALL
:
2874 case TCP_TABLE_OWNER_PID_ALL
:
2875 case TCP_TABLE_OWNER_MODULE_ALL
:
2877 return NSI_TCP_ALL_TABLE
;
2880 ERR( "unhandled class %lu\n", table_class
);
2885 static DWORD
tcp_table_size( ULONG family
, ULONG table_class
, DWORD row_count
, DWORD
*row_size
)
2887 switch (table_class
)
2889 case TCP_TABLE_BASIC_LISTENER
:
2890 case TCP_TABLE_BASIC_CONNECTIONS
:
2891 case TCP_TABLE_BASIC_ALL
:
2892 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW
) : sizeof(MIB_TCP6ROW
);
2893 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE
, table
[row_count
]) :
2894 FIELD_OFFSET(MIB_TCP6TABLE
, table
[row_count
]);
2896 case TCP_TABLE_OWNER_PID_LISTENER
:
2897 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2898 case TCP_TABLE_OWNER_PID_ALL
:
2899 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW_OWNER_PID
) : sizeof(MIB_TCP6ROW_OWNER_PID
);
2900 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID
, table
[row_count
]) :
2901 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID
, table
[row_count
]);
2903 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2904 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2905 case TCP_TABLE_OWNER_MODULE_ALL
:
2906 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW_OWNER_MODULE
) : sizeof(MIB_TCP6ROW_OWNER_MODULE
);
2907 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE
, table
[row_count
]) :
2908 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE
, table
[row_count
]);
2911 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW2
) : sizeof(MIB_TCP6ROW2
);
2912 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE2
, table
[row_count
]) :
2913 FIELD_OFFSET(MIB_TCP6TABLE2
, table
[row_count
]);
2916 ERR( "unhandled class %lu\n", table_class
);
2921 static void tcp_row_fill( void *table
, DWORD num
, ULONG family
, ULONG table_class
,
2922 struct nsi_tcp_conn_key
*key
, struct nsi_tcp_conn_dynamic
*dyn
,
2923 struct nsi_tcp_conn_static
*stat
)
2925 if (family
== AF_INET
)
2927 switch (table_class
)
2929 case TCP_TABLE_BASIC_LISTENER
:
2930 case TCP_TABLE_BASIC_CONNECTIONS
:
2931 case TCP_TABLE_BASIC_ALL
:
2933 MIB_TCPROW
*row
= ((MIB_TCPTABLE
*)table
)->table
+ num
;
2934 row
->dwState
= dyn
->state
;
2935 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2936 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2937 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2938 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2941 case TCP_TABLE_OWNER_PID_LISTENER
:
2942 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2943 case TCP_TABLE_OWNER_PID_ALL
:
2945 MIB_TCPROW_OWNER_PID
*row
= ((MIB_TCPTABLE_OWNER_PID
*)table
)->table
+ num
;
2946 row
->dwState
= dyn
->state
;
2947 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2948 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2949 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2950 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2951 row
->dwOwningPid
= stat
->pid
;
2954 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2955 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2956 case TCP_TABLE_OWNER_MODULE_ALL
:
2958 MIB_TCPROW_OWNER_MODULE
*row
= ((MIB_TCPTABLE_OWNER_MODULE
*)table
)->table
+ num
;
2959 row
->dwState
= dyn
->state
;
2960 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2961 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2962 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2963 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2964 row
->dwOwningPid
= stat
->pid
;
2965 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
2966 row
->OwningModuleInfo
[0] = stat
->mod_info
;
2967 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
2972 MIB_TCPROW2
*row
= ((MIB_TCPTABLE2
*)table
)->table
+ num
;
2973 row
->dwState
= dyn
->state
;
2974 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2975 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2976 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2977 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2978 row
->dwOwningPid
= stat
->pid
;
2979 row
->dwOffloadState
= 0; /* FIXME */
2983 ERR( "Unknown class %ld\n", table_class
);
2989 switch (table_class
)
2991 case TCP_TABLE_BASIC_LISTENER
:
2992 case TCP_TABLE_BASIC_CONNECTIONS
:
2993 case TCP_TABLE_BASIC_ALL
:
2995 MIB_TCP6ROW
*row
= ((MIB_TCP6TABLE
*)table
)->table
+ num
;
2996 row
->State
= dyn
->state
;
2997 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
2998 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
2999 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3000 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
3001 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3002 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3005 case TCP_TABLE_OWNER_PID_LISTENER
:
3006 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
3007 case TCP_TABLE_OWNER_PID_ALL
:
3009 MIB_TCP6ROW_OWNER_PID
*row
= ((MIB_TCP6TABLE_OWNER_PID
*)table
)->table
+ num
;
3010 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3011 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3012 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3013 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3014 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3015 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3016 row
->dwState
= dyn
->state
;
3017 row
->dwOwningPid
= stat
->pid
;
3020 case TCP_TABLE_OWNER_MODULE_LISTENER
:
3021 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
3022 case TCP_TABLE_OWNER_MODULE_ALL
:
3024 MIB_TCP6ROW_OWNER_MODULE
*row
= ((MIB_TCP6TABLE_OWNER_MODULE
*)table
)->table
+ num
;
3025 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3026 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3027 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3028 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3029 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3030 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3031 row
->dwState
= dyn
->state
;
3032 row
->dwOwningPid
= stat
->pid
;
3033 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3034 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3035 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3040 MIB_TCP6ROW2
*row
= ((MIB_TCP6TABLE2
*)table
)->table
+ num
;
3041 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
3042 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3043 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3044 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
3045 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3046 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3047 row
->State
= dyn
->state
;
3048 row
->dwOwningPid
= stat
->pid
;
3049 row
->dwOffloadState
= 0; /* FIXME */
3053 ERR( "Unknown class %ld\n", table_class
);
3057 ERR( "Unknown family %ld\n", family
);
3060 static int tcp_row_cmp( const void *a
, const void *b
)
3062 const MIB_TCPROW
*rowA
= a
, *rowB
= b
;
3065 if ((ret
= DWORD_cmp(RtlUshortByteSwap( rowA
->dwLocalAddr
), RtlUshortByteSwap( rowB
->dwLocalAddr
))) != 0) return ret
;
3066 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3067 if ((ret
= DWORD_cmp(RtlUshortByteSwap( rowA
->dwRemoteAddr
), RtlUshortByteSwap( rowB
->dwRemoteAddr
))) != 0) return ret
;
3068 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3071 static int tcp6_row_basic_cmp( const void *a
, const void *b
)
3073 const MIB_TCP6ROW
*rowA
= a
;
3074 const MIB_TCP6ROW
*rowB
= b
;
3077 if ((ret
= memcmp( &rowA
->LocalAddr
, &rowB
->LocalAddr
, sizeof(rowA
->LocalAddr
) )) != 0) return ret
;
3078 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3079 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3080 if ((ret
= memcmp( &rowA
->RemoteAddr
, &rowB
->RemoteAddr
, sizeof(rowA
->RemoteAddr
) )) != 0) return ret
;
3081 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3082 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3085 static int tcp6_row_owner_cmp( const void *a
, const void *b
)
3087 const MIB_TCP6ROW_OWNER_PID
*rowA
= a
;
3088 const MIB_TCP6ROW_OWNER_PID
*rowB
= b
;
3091 if ((ret
= memcmp( &rowA
->ucLocalAddr
, &rowB
->ucLocalAddr
, sizeof(rowA
->ucLocalAddr
) )) != 0) return ret
;
3092 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3093 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3094 if ((ret
= memcmp( &rowA
->ucRemoteAddr
, &rowB
->ucRemoteAddr
, sizeof(rowA
->ucRemoteAddr
) )) != 0) return ret
;
3095 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3096 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3099 static BOOL
tcp_table_needs_pids( ULONG table_class
)
3101 switch (table_class
)
3103 case TCP_TABLE_BASIC_LISTENER
:
3104 case TCP_TABLE_BASIC_CONNECTIONS
:
3105 case TCP_TABLE_BASIC_ALL
:
3112 /*************************************************************************************
3113 * get_extended_tcp_table
3115 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3116 * corresponding to GetTcp(6)Table2()
3118 static DWORD
get_extended_tcp_table( void *table
, DWORD
*size
, BOOL sort
, ULONG family
, ULONG table_class
)
3120 DWORD err
, count
, needed
, i
, num
= 0, row_size
= 0;
3121 struct nsi_tcp_conn_key
*key
;
3122 struct nsi_tcp_conn_dynamic
*dyn
;
3123 struct nsi_tcp_conn_static
*stat
= NULL
;
3125 if (!size
) return ERROR_INVALID_PARAMETER
;
3127 if (tcp_table_needs_pids( table_class
))
3128 err
= NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID
, tcp_table_id( table_class
), (void **)&key
, sizeof(*key
),
3129 NULL
, 0, (void **)&dyn
, sizeof(*dyn
),
3130 (void **)&stat
, sizeof(*stat
), &count
, 0 );
3131 else /* Don't retrieve the static data if not required as this is expensive to compute */
3132 err
= NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID
, tcp_table_id( table_class
), (void **)&key
, sizeof(*key
),
3133 NULL
, 0, (void **)&dyn
, sizeof(*dyn
),
3134 NULL
, 0, &count
, 0 );
3136 if (err
) return err
;
3138 for (i
= 0; i
< count
; i
++)
3139 if (key
[i
].local
.si_family
== family
)
3142 needed
= tcp_table_size( family
, table_class
, num
, &row_size
);
3143 if (!table
|| *size
< needed
)
3146 err
= ERROR_INSUFFICIENT_BUFFER
;
3151 *(DWORD
*)table
= num
;
3153 for (i
= 0; i
< count
; i
++)
3155 if (key
[i
].local
.si_family
!= family
) continue;
3156 tcp_row_fill( table
, num
++, family
, table_class
, key
+ i
, dyn
+ i
, stat
+ i
);
3162 int (*fn
)(const void *, const void *);
3165 if (family
== AF_INET
) fn
= tcp_row_cmp
;
3166 else if (row_size
== sizeof(MIB_TCP6ROW
)) fn
= tcp6_row_basic_cmp
;
3167 else fn
= tcp6_row_owner_cmp
;
3169 offset
= tcp_table_size( family
, table_class
, 0, &row_size
);
3170 qsort( (BYTE
*)table
+ offset
, num
, row_size
, fn
);
3173 NsiFreeTable( key
, NULL
, dyn
, stat
);
3177 /******************************************************************
3178 * GetExtendedTcpTable (IPHLPAPI.@)
3180 DWORD WINAPI
GetExtendedTcpTable( void *table
, DWORD
*size
, BOOL sort
, ULONG family
,
3181 TCP_TABLE_CLASS table_class
, ULONG reserved
)
3183 TRACE( "table %p, size %p, sort %d, family %lu, class %u, reserved %lu\n",
3184 table
, size
, sort
, family
, table_class
, reserved
);
3186 if (!ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3187 return get_extended_tcp_table( table
, size
, sort
, family
, table_class
);
3190 /******************************************************************
3191 * GetTcpTable (IPHLPAPI.@)
3193 * Get the table of active TCP connections.
3196 * table [Out] buffer for TCP connections table
3197 * size [In/Out] length of output buffer
3198 * sort [In] whether to order the table
3202 * Failure: error code from winerror.h
3205 * If size is less than required, the function will return
3206 * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
3207 * the required byte size.
3208 * If sort is true, the returned table will be sorted, first by
3209 * local address and port number, then by remote address and port
3212 DWORD WINAPI
GetTcpTable( MIB_TCPTABLE
*table
, DWORD
*size
, BOOL sort
)
3214 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3215 return get_extended_tcp_table( table
, size
, sort
, AF_INET
, TCP_TABLE_BASIC_ALL
);
3218 /******************************************************************
3219 * GetTcp6Table (IPHLPAPI.@)
3221 ULONG WINAPI
GetTcp6Table( MIB_TCP6TABLE
*table
, ULONG
*size
, BOOL sort
)
3223 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3224 return get_extended_tcp_table( table
, size
, sort
, AF_INET6
, TCP_TABLE_BASIC_ALL
);
3227 /******************************************************************
3228 * GetTcpTable2 (IPHLPAPI.@)
3230 ULONG WINAPI
GetTcpTable2( MIB_TCPTABLE2
*table
, ULONG
*size
, BOOL sort
)
3232 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3233 return get_extended_tcp_table( table
, size
, sort
, AF_INET
, TCP_TABLE2
);
3236 /******************************************************************
3237 * GetTcp6Table2 (IPHLPAPI.@)
3239 ULONG WINAPI
GetTcp6Table2( MIB_TCP6TABLE2
*table
, ULONG
*size
, BOOL sort
)
3241 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3242 return get_extended_tcp_table( table
, size
, sort
, AF_INET6
, TCP_TABLE2
);
3245 static DWORD
allocate_tcp_table( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
,
3246 ULONG family
, ULONG table_class
)
3248 DWORD err
, size
= 0x100, attempt
;
3250 for (attempt
= 0; attempt
< 5; attempt
++)
3252 *table
= HeapAlloc( heap
, flags
, size
);
3253 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
3254 err
= get_extended_tcp_table( *table
, &size
, sort
, family
, table_class
);
3256 HeapFree( heap
, flags
, *table
);
3258 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
3263 /******************************************************************
3264 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
3266 DWORD WINAPI
AllocateAndGetTcpTableFromStack( MIB_TCPTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
3268 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
3270 if (!table
) return ERROR_INVALID_PARAMETER
;
3272 return allocate_tcp_table( (void **)table
, sort
, heap
, flags
, AF_INET
, TCP_TABLE_BASIC_ALL
);
3275 /******************************************************************
3276 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
3278 DWORD WINAPI
AllocateAndGetTcpExTableFromStack( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
, DWORD family
)
3280 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx, family %lu\n", table
, sort
, heap
, flags
, family
);
3282 if (!table
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3283 if (family
== AF_INET6
) return ERROR_NOT_SUPPORTED
;
3285 return allocate_tcp_table( table
, sort
, heap
, flags
, family
, TCP_TABLE_OWNER_PID_ALL
);
3288 /******************************************************************
3289 * GetUdpStatistics (IPHLPAPI.@)
3291 * Get the UDP statistics for the local computer.
3294 * stats [Out] buffer for UDP statistics
3296 DWORD WINAPI
GetUdpStatistics( MIB_UDPSTATS
*stats
)
3298 return GetUdpStatisticsEx( stats
, AF_INET
);
3301 /******************************************************************
3302 * GetUdpStatisticsEx (IPHLPAPI.@)
3304 * Get the IPv4 and IPv6 UDP statistics for the local computer.
3307 * stats [Out] buffer for UDP statistics
3308 * family [In] specifies whether IPv4 or IPv6 statistics are returned
3312 * Failure: error code from winerror.h
3314 DWORD WINAPI
GetUdpStatisticsEx( MIB_UDPSTATS
*stats
, DWORD family
)
3316 struct nsi_udp_stats_dynamic dyn
;
3317 USHORT key
= (USHORT
)family
;
3320 if (!stats
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3321 memset( stats
, 0, sizeof(*stats
) );
3323 err
= NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID
, NSI_UDP_STATS_TABLE
, &key
, sizeof(key
), NULL
, 0,
3324 &dyn
, sizeof(dyn
), NULL
, 0 );
3325 if (err
) return err
;
3327 stats
->dwInDatagrams
= dyn
.in_dgrams
;
3328 stats
->dwNoPorts
= dyn
.no_ports
;
3329 stats
->dwInErrors
= dyn
.in_errs
;
3330 stats
->dwOutDatagrams
= dyn
.out_dgrams
;
3331 stats
->dwNumAddrs
= dyn
.num_addrs
;
3335 /******************************************************************
3336 * GetUdpTable (IPHLPAPI.@)
3338 * Get a table of active UDP connections.
3341 * table [Out] buffer for UDP connections table
3342 * size [In/Out] length of output buffer
3343 * sort [In] whether to order the table
3346 DWORD WINAPI
GetUdpTable( MIB_UDPTABLE
*table
, DWORD
*size
, BOOL sort
)
3348 return GetExtendedUdpTable( table
, size
, sort
, AF_INET
, UDP_TABLE_BASIC
, 0 );
3351 /******************************************************************
3352 * GetUdp6Table (IPHLPAPI.@)
3354 DWORD WINAPI
GetUdp6Table( MIB_UDP6TABLE
*table
, DWORD
*size
, BOOL sort
)
3356 return GetExtendedUdpTable( table
, size
, sort
, AF_INET6
, UDP_TABLE_BASIC
, 0 );
3359 static DWORD
udp_table_size( ULONG family
, ULONG table_class
, DWORD row_count
, DWORD
*row_size
)
3361 switch (table_class
)
3363 case UDP_TABLE_BASIC
:
3364 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW
) : sizeof(MIB_UDP6ROW
);
3365 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE
, table
[row_count
]) :
3366 FIELD_OFFSET(MIB_UDP6TABLE
, table
[row_count
]);
3368 case UDP_TABLE_OWNER_PID
:
3369 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW_OWNER_PID
) : sizeof(MIB_UDP6ROW_OWNER_PID
);
3370 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID
, table
[row_count
]) :
3371 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID
, table
[row_count
]);
3373 case UDP_TABLE_OWNER_MODULE
:
3374 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW_OWNER_MODULE
) : sizeof(MIB_UDP6ROW_OWNER_MODULE
);
3375 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE
, table
[row_count
]) :
3376 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE
, table
[row_count
]);
3379 ERR( "unhandled class %lu\n", table_class
);
3384 static void udp_row_fill( void *table
, DWORD num
, ULONG family
, ULONG table_class
,
3385 struct nsi_udp_endpoint_key
*key
,
3386 struct nsi_udp_endpoint_static
*stat
)
3388 if (family
== AF_INET
)
3390 switch (table_class
)
3392 case UDP_TABLE_BASIC
:
3394 MIB_UDPROW
*row
= ((MIB_UDPTABLE
*)table
)->table
+ num
;
3395 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3396 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3399 case UDP_TABLE_OWNER_PID
:
3401 MIB_UDPROW_OWNER_PID
*row
= ((MIB_UDPTABLE_OWNER_PID
*)table
)->table
+ num
;
3402 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3403 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3404 row
->dwOwningPid
= stat
->pid
;
3407 case UDP_TABLE_OWNER_MODULE
:
3409 MIB_UDPROW_OWNER_MODULE
*row
= ((MIB_UDPTABLE_OWNER_MODULE
*)table
)->table
+ num
;
3410 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3411 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3412 row
->dwOwningPid
= stat
->pid
;
3413 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3414 row
->dwFlags
= stat
->flags
;
3415 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3416 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3420 ERR( "Unknown class %ld\n", table_class
);
3426 switch (table_class
)
3428 case UDP_TABLE_BASIC
:
3430 MIB_UDP6ROW
*row
= ((MIB_UDP6TABLE
*)table
)->table
+ num
;
3431 memcpy( &row
->dwLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->dwLocalAddr
) );
3432 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3433 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3436 case UDP_TABLE_OWNER_PID
:
3438 MIB_UDP6ROW_OWNER_PID
*row
= ((MIB_UDP6TABLE_OWNER_PID
*)table
)->table
+ num
;
3439 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3440 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3441 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3442 row
->dwOwningPid
= stat
->pid
;
3445 case UDP_TABLE_OWNER_MODULE
:
3447 MIB_UDP6ROW_OWNER_MODULE
*row
= ((MIB_UDP6TABLE_OWNER_MODULE
*)table
)->table
+ num
;
3448 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3449 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3450 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3451 row
->dwOwningPid
= stat
->pid
;
3452 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3453 row
->dwFlags
= stat
->flags
;
3454 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3455 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3459 ERR( "Unknown class %ld\n", table_class
);
3463 ERR( "Unknown family %ld\n", family
);
3467 static int udp_row_cmp( const void *a
, const void *b
)
3469 const MIB_UDPROW
*rowA
= a
, *rowB
= b
;
3471 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwLocalAddr
), RtlUlongByteSwap( rowB
->dwLocalAddr
)) ||
3472 RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
);
3475 static int udp6_row_cmp( const void *a
, const void *b
)
3477 const MIB_UDP6ROW
*rowA
= a
;
3478 const MIB_UDP6ROW
*rowB
= b
;
3481 if ((ret
= memcmp( &rowA
->dwLocalAddr
, &rowB
->dwLocalAddr
, sizeof(rowA
->dwLocalAddr
) )) != 0) return ret
;
3482 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3483 return RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
);
3486 /******************************************************************
3487 * GetExtendedUdpTable (IPHLPAPI.@)
3489 DWORD WINAPI
GetExtendedUdpTable( void *table
, DWORD
*size
, BOOL sort
, ULONG family
,
3490 UDP_TABLE_CLASS table_class
, ULONG reserved
)
3492 DWORD err
, count
, needed
, i
, num
= 0, row_size
= 0;
3493 struct nsi_udp_endpoint_key
*key
;
3494 struct nsi_udp_endpoint_static
*stat
;
3496 TRACE( "table %p, size %p, sort %d, family %lu, table_class %u, reserved %lu\n",
3497 table
, size
, sort
, family
, table_class
, reserved
);
3499 if (!size
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3501 err
= NsiAllocateAndGetTable( 1, &NPI_MS_UDP_MODULEID
, NSI_UDP_ENDPOINT_TABLE
, (void **)&key
, sizeof(*key
),
3502 NULL
, 0, NULL
, 0, (void **)&stat
, sizeof(*stat
), &count
, 0 );
3503 if (err
) return err
;
3505 for (i
= 0; i
< count
; i
++)
3506 if (key
[i
].local
.si_family
== family
)
3509 needed
= udp_table_size( family
, table_class
, num
, &row_size
);
3510 if (!table
|| *size
< needed
)
3513 err
= ERROR_INSUFFICIENT_BUFFER
;
3518 *(DWORD
*)table
= num
;
3520 for (i
= 0; i
< count
; i
++)
3522 if (key
[i
].local
.si_family
!= family
) continue;
3523 udp_row_fill( table
, num
++, family
, table_class
, key
+ i
, stat
+ i
);
3529 int (*fn
)(const void *, const void *);
3530 DWORD offset
= udp_table_size( family
, table_class
, 0, &row_size
);
3532 if (family
== AF_INET
) fn
= udp_row_cmp
;
3533 else fn
= udp6_row_cmp
;
3535 qsort( (BYTE
*)table
+ offset
, num
, row_size
, fn
);
3538 NsiFreeTable( key
, NULL
, NULL
, stat
);
3542 DWORD WINAPI
AllocateAndGetUdpTableFromStack( MIB_UDPTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
3544 DWORD err
, size
= 0x100, attempt
;
3546 TRACE("table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
3548 if (!table
) return ERROR_INVALID_PARAMETER
;
3550 for (attempt
= 0; attempt
< 5; attempt
++)
3552 *table
= HeapAlloc( heap
, flags
, size
);
3553 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
3554 err
= GetExtendedUdpTable( *table
, &size
, sort
, AF_INET
, UDP_TABLE_BASIC
, 0 );
3556 HeapFree( heap
, flags
, *table
);
3558 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
3563 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW
*row
, USHORT fam
, void *key
, struct nsi_ip_unicast_rw
*rw
,
3564 struct nsi_ip_unicast_dynamic
*dyn
, struct nsi_ip_unicast_static
*stat
)
3566 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
;
3567 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
;
3571 row
->Address
.Ipv4
.sin_family
= fam
;
3572 row
->Address
.Ipv4
.sin_port
= 0;
3573 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
3574 memset( row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
3575 row
->InterfaceLuid
.Value
= key4
->luid
.Value
;
3579 row
->Address
.Ipv6
.sin6_family
= fam
;
3580 row
->Address
.Ipv6
.sin6_port
= 0;
3581 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
3582 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
3583 row
->Address
.Ipv6
.sin6_scope_id
= dyn
->scope_id
;
3584 row
->InterfaceLuid
.Value
= key6
->luid
.Value
;
3587 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
3588 row
->PrefixOrigin
= rw
->prefix_origin
;
3589 row
->SuffixOrigin
= rw
->suffix_origin
;
3590 row
->ValidLifetime
= rw
->valid_lifetime
;
3591 row
->PreferredLifetime
= rw
->preferred_lifetime
;
3592 row
->OnLinkPrefixLength
= rw
->on_link_prefix
;
3593 row
->SkipAsSource
= 0;
3594 row
->DadState
= dyn
->dad_state
;
3595 row
->ScopeId
.Value
= dyn
->scope_id
;
3596 row
->CreationTimeStamp
.QuadPart
= stat
->creation_time
;
3599 DWORD WINAPI
GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW
*row
)
3601 struct nsi_ipv4_unicast_key key4
;
3602 struct nsi_ipv6_unicast_key key6
;
3603 struct nsi_ip_unicast_rw rw
;
3604 struct nsi_ip_unicast_dynamic dyn
;
3605 struct nsi_ip_unicast_static stat
;
3606 const NPI_MODULEID
*mod
;
3607 DWORD err
, key_size
;
3610 TRACE( "%p\n", row
);
3612 if (!row
) return ERROR_INVALID_PARAMETER
;
3613 mod
= ip_module_id( row
->Address
.si_family
);
3614 if (!mod
) return ERROR_INVALID_PARAMETER
;
3616 if (!row
->InterfaceLuid
.Value
)
3618 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
3619 if (err
) return err
;
3622 if (row
->Address
.si_family
== AF_INET
)
3624 key4
.luid
= row
->InterfaceLuid
;
3625 key4
.addr
= row
->Address
.Ipv4
.sin_addr
;
3628 key_size
= sizeof(key4
);
3630 else if (row
->Address
.si_family
== AF_INET6
)
3632 key6
.luid
= row
->InterfaceLuid
;
3633 key6
.addr
= row
->Address
.Ipv6
.sin6_addr
;
3635 key_size
= sizeof(key6
);
3637 else return ERROR_INVALID_PARAMETER
;
3639 err
= NsiGetAllParameters( 1, mod
, NSI_IP_UNICAST_TABLE
, key
, key_size
, &rw
, sizeof(rw
),
3640 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
3641 if (!err
) unicast_row_fill( row
, row
->Address
.si_family
, key
, &rw
, &dyn
, &stat
);
3645 DWORD WINAPI
GetUnicastIpAddressTable(ADDRESS_FAMILY family
, MIB_UNICASTIPADDRESS_TABLE
**table
)
3647 void *key
[2] = { NULL
, NULL
};
3648 struct nsi_ip_unicast_rw
*rw
[2] = { NULL
, NULL
};
3649 struct nsi_ip_unicast_dynamic
*dyn
[2] = { NULL
, NULL
};
3650 struct nsi_ip_unicast_static
*stat
[2] = { NULL
, NULL
};
3651 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
3652 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_unicast_key
), sizeof(struct nsi_ipv6_unicast_key
) };
3653 DWORD err
, i
, size
, count
[2] = { 0, 0 };
3655 TRACE( "%u, %p\n", family
, table
);
3657 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
3658 return ERROR_INVALID_PARAMETER
;
3660 for (i
= 0; i
< 2; i
++)
3662 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
3664 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_UNICAST_TABLE
, key
+ i
, key_size
[i
],
3665 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
3666 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
3670 size
= FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE
, Table
[ count
[0] + count
[1] ]);
3671 *table
= heap_alloc( size
);
3674 err
= ERROR_NOT_ENOUGH_MEMORY
;
3678 (*table
)->NumEntries
= count
[0] + count
[1];
3679 for (i
= 0; i
< count
[0]; i
++)
3681 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ i
;
3682 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
[0];
3684 unicast_row_fill( row
, fam
[0], (void *)(key4
+ i
), rw
[0] + i
, dyn
[0] + i
, stat
[0] + i
);
3687 for (i
= 0; i
< count
[1]; i
++)
3689 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ count
[0] + i
;
3690 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
[1];
3692 unicast_row_fill( row
, fam
[1], (void *)(key6
+ i
), rw
[1] + i
, dyn
[1] + i
, stat
[1] + i
);
3696 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
3700 /******************************************************************
3701 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3703 * This is a Win98-only function to get information on "unidirectional"
3704 * adapters. Since this is pretty nonsensical in other contexts, it
3705 * never returns anything.
3708 * pIPIfInfo [Out] buffer for adapter infos
3709 * dwOutBufLen [Out] length of the output buffer
3713 * Failure: error code from winerror.h
3716 * Stub, returns ERROR_NOT_SUPPORTED.
3718 DWORD WINAPI
GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo
, PULONG dwOutBufLen
)
3720 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo
, dwOutBufLen
);
3721 /* a unidirectional adapter?? not bloody likely! */
3722 return ERROR_NOT_SUPPORTED
;
3726 /******************************************************************
3727 * IpReleaseAddress (IPHLPAPI.@)
3729 * Release an IP obtained through DHCP,
3732 * AdapterInfo [In] adapter to release IP address
3736 * Failure: error code from winerror.h
3739 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3740 * this function does nothing.
3743 * Stub, returns ERROR_NOT_SUPPORTED.
3745 DWORD WINAPI
IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3747 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3748 return ERROR_NOT_SUPPORTED
;
3752 /******************************************************************
3753 * IpRenewAddress (IPHLPAPI.@)
3755 * Renew an IP obtained through DHCP.
3758 * AdapterInfo [In] adapter to renew IP address
3762 * Failure: error code from winerror.h
3765 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3766 * this function does nothing.
3769 * Stub, returns ERROR_NOT_SUPPORTED.
3771 DWORD WINAPI
IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3773 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3774 return ERROR_NOT_SUPPORTED
;
3778 /******************************************************************
3779 * NotifyAddrChange (IPHLPAPI.@)
3781 * Notify caller whenever the ip-interface map is changed.
3784 * Handle [Out] handle usable in asynchronous notification
3785 * overlapped [In] overlapped structure that notifies the caller
3789 * Failure: error code from winerror.h
3791 DWORD WINAPI
NotifyAddrChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3793 TRACE("Handle %p, overlapped %p.\n", Handle
, overlapped
);
3795 return NsiRequestChangeNotification(0, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, overlapped
, Handle
);
3799 /******************************************************************
3800 * NotifyIpInterfaceChange (IPHLPAPI.@)
3802 DWORD WINAPI
NotifyIpInterfaceChange(ADDRESS_FAMILY family
, PIPINTERFACE_CHANGE_CALLBACK callback
,
3803 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3805 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3806 family
, callback
, context
, init_notify
, handle
);
3807 if (handle
) *handle
= NULL
;
3811 /******************************************************************
3812 * NotifyRouteChange2 (IPHLPAPI.@)
3814 DWORD WINAPI
NotifyRouteChange2(ADDRESS_FAMILY family
, PIPFORWARD_CHANGE_CALLBACK callback
, VOID
* context
,
3815 BOOLEAN init_notify
, HANDLE
* handle
)
3817 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3818 family
, callback
, context
, init_notify
, handle
);
3819 if (handle
) *handle
= NULL
;
3824 /******************************************************************
3825 * NotifyRouteChange (IPHLPAPI.@)
3827 * Notify caller whenever the ip routing table is changed.
3830 * Handle [Out] handle usable in asynchronous notification
3831 * overlapped [In] overlapped structure that notifies the caller
3835 * Failure: error code from winerror.h
3838 * Stub, returns ERROR_NOT_SUPPORTED.
3840 DWORD WINAPI
NotifyRouteChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3842 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
3843 return ERROR_NOT_SUPPORTED
;
3847 /******************************************************************
3848 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3850 DWORD WINAPI
NotifyUnicastIpAddressChange(ADDRESS_FAMILY family
, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback
,
3851 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3853 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3854 family
, callback
, context
, init_notify
, handle
);
3855 if (handle
) *handle
= NULL
;
3858 callback(context
, NULL
, MibInitialNotification
);
3863 /******************************************************************
3864 * SendARP (IPHLPAPI.@)
3866 * Send an ARP request.
3869 * DestIP [In] attempt to obtain this IP
3870 * SrcIP [In] optional sender IP address
3871 * pMacAddr [Out] buffer for the mac address
3872 * PhyAddrLen [In/Out] length of the output buffer
3876 * Failure: error code from winerror.h
3879 * Stub, returns ERROR_NOT_SUPPORTED.
3881 DWORD WINAPI
SendARP(IPAddr DestIP
, IPAddr SrcIP
, PULONG pMacAddr
, PULONG PhyAddrLen
)
3883 FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
3884 DestIP
, SrcIP
, pMacAddr
, PhyAddrLen
);
3885 return ERROR_NOT_SUPPORTED
;
3889 /******************************************************************
3890 * SetIfEntry (IPHLPAPI.@)
3892 * Set the administrative status of an interface.
3895 * pIfRow [In] dwAdminStatus member specifies the new status.
3899 * Failure: error code from winerror.h
3902 * Stub, returns ERROR_NOT_SUPPORTED.
3904 DWORD WINAPI
SetIfEntry(PMIB_IFROW pIfRow
)
3906 FIXME("(pIfRow %p): stub\n", pIfRow
);
3907 /* this is supposed to set an interface administratively up or down.
3908 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3909 this sort of down is indistinguishable from other sorts of down (e.g. no
3911 return ERROR_NOT_SUPPORTED
;
3915 /******************************************************************
3916 * SetIpForwardEntry (IPHLPAPI.@)
3918 * Modify an existing route.
3921 * pRoute [In] route with the new information
3925 * Failure: error code from winerror.h
3928 * Stub, returns NO_ERROR.
3930 DWORD WINAPI
SetIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
3932 FIXME("(pRoute %p): stub\n", pRoute
);
3933 /* this is to add a route entry, how's it distinguishable from
3934 CreateIpForwardEntry?
3935 could use SIOCADDRT, not sure I want to */
3940 /******************************************************************
3941 * SetIpNetEntry (IPHLPAPI.@)
3943 * Modify an existing ARP entry.
3946 * pArpEntry [In] ARP entry with the new information
3950 * Failure: error code from winerror.h
3953 * Stub, returns NO_ERROR.
3955 DWORD WINAPI
SetIpNetEntry(PMIB_IPNETROW pArpEntry
)
3957 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
3958 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3963 /******************************************************************
3964 * SetIpStatistics (IPHLPAPI.@)
3966 * Toggle IP forwarding and det the default TTL value.
3969 * pIpStats [In] IP statistics with the new information
3973 * Failure: error code from winerror.h
3976 * Stub, returns NO_ERROR.
3978 DWORD WINAPI
SetIpStatistics(PMIB_IPSTATS pIpStats
)
3980 FIXME("(pIpStats %p): stub\n", pIpStats
);
3985 /******************************************************************
3986 * SetIpTTL (IPHLPAPI.@)
3988 * Set the default TTL value.
3991 * nTTL [In] new TTL value
3995 * Failure: error code from winerror.h
3998 * Stub, returns NO_ERROR.
4000 DWORD WINAPI
SetIpTTL(UINT nTTL
)
4002 FIXME("(nTTL %d): stub\n", nTTL
);
4003 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
4004 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
4009 /******************************************************************
4010 * SetTcpEntry (IPHLPAPI.@)
4012 * Set the state of a TCP connection.
4015 * pTcpRow [In] specifies connection with new state
4019 * Failure: error code from winerror.h
4022 * Stub, returns NO_ERROR.
4024 DWORD WINAPI
SetTcpEntry(PMIB_TCPROW pTcpRow
)
4026 FIXME("(pTcpRow %p): stub\n", pTcpRow
);
4030 /***********************************************************************
4031 * GetPerTcpConnectionEStats (IPHLPAPI.@)
4033 ULONG WINAPI
GetPerTcpConnectionEStats(MIB_TCPROW
*row
, TCP_ESTATS_TYPE stats
, UCHAR
*rw
, ULONG rw_version
,
4034 ULONG rw_size
, UCHAR
*ro_static
, ULONG ro_static_version
,
4035 ULONG ro_static_size
, UCHAR
*ro_dynamic
, ULONG ro_dynamic_version
,
4036 ULONG ro_dynamic_size
)
4038 FIXME( "(%p, %d, %p, %ld, %ld, %p, %ld, %ld, %p, %ld, %ld): stub\n", row
, stats
, rw
, rw_version
, rw_size
,
4039 ro_static
, ro_static_version
, ro_static_size
, ro_dynamic
, ro_dynamic_version
, ro_dynamic_size
);
4040 return ERROR_CALL_NOT_IMPLEMENTED
;
4043 /******************************************************************
4044 * SetPerTcpConnectionEStats (IPHLPAPI.@)
4046 DWORD WINAPI
SetPerTcpConnectionEStats(PMIB_TCPROW row
, TCP_ESTATS_TYPE state
, PBYTE rw
,
4047 ULONG version
, ULONG size
, ULONG offset
)
4049 FIXME("(row %p, state %d, rw %p, version %lu, size %lu, offset %lu): stub\n",
4050 row
, state
, rw
, version
, size
, offset
);
4051 return ERROR_NOT_SUPPORTED
;
4055 /******************************************************************
4056 * UnenableRouter (IPHLPAPI.@)
4058 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
4059 * if it reaches zero.
4062 * pOverlapped [In/Out] should be the same as in EnableRouter()
4063 * lpdwEnableCount [Out] optional, receives reference count
4067 * Failure: error code from winerror.h
4070 * Stub, returns ERROR_NOT_SUPPORTED.
4072 DWORD WINAPI
UnenableRouter(OVERLAPPED
* pOverlapped
, LPDWORD lpdwEnableCount
)
4074 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped
,
4076 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
4077 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
4079 return ERROR_NOT_SUPPORTED
;
4082 /******************************************************************
4083 * PfCreateInterface (IPHLPAPI.@)
4085 DWORD WINAPI
PfCreateInterface(DWORD dwName
, PFFORWARD_ACTION inAction
, PFFORWARD_ACTION outAction
,
4086 BOOL bUseLog
, BOOL bMustBeUnique
, INTERFACE_HANDLE
*ppInterface
)
4088 FIXME("(%ld %d %d %x %x %p) stub\n", dwName
, inAction
, outAction
, bUseLog
, bMustBeUnique
, ppInterface
);
4089 return ERROR_CALL_NOT_IMPLEMENTED
;
4092 /******************************************************************
4093 * PfUnBindInterface (IPHLPAPI.@)
4095 DWORD WINAPI
PfUnBindInterface(INTERFACE_HANDLE interface
)
4097 FIXME("(%p) stub\n", interface
);
4098 return ERROR_CALL_NOT_IMPLEMENTED
;
4101 /******************************************************************
4102 * PfDeleteInterface(IPHLPAPI.@)
4104 DWORD WINAPI
PfDeleteInterface(INTERFACE_HANDLE interface
)
4106 FIXME("(%p) stub\n", interface
);
4107 return ERROR_CALL_NOT_IMPLEMENTED
;
4110 /******************************************************************
4111 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
4113 DWORD WINAPI
PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface
, PFADDRESSTYPE type
, PBYTE ip
)
4115 FIXME("(%p %d %p) stub\n", interface
, type
, ip
);
4116 return ERROR_CALL_NOT_IMPLEMENTED
;
4119 /******************************************************************
4120 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
4122 DWORD WINAPI
ConvertInterfaceAliasToLuid( const WCHAR
*alias
, NET_LUID
*luid
)
4124 struct nsi_ndis_ifinfo_rw
*data
;
4125 DWORD err
, count
, i
, len
;
4128 TRACE( "(%s %p)\n", debugstr_w(alias
), luid
);
4130 if (!alias
|| !*alias
|| !luid
) return ERROR_INVALID_PARAMETER
;
4132 len
= wcslen( alias
);
4134 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
4135 (void **)&data
, sizeof(*data
), NULL
, 0, NULL
, 0, &count
, 0 );
4136 if (err
) return err
;
4138 err
= ERROR_INVALID_PARAMETER
;
4139 for (i
= 0; i
< count
; i
++)
4141 if (data
[i
].alias
.Length
== len
* 2 && !memcmp( data
[i
].alias
.String
, alias
, len
* 2 ))
4143 luid
->Value
= keys
[i
].Value
;
4144 err
= ERROR_SUCCESS
;
4148 NsiFreeTable( keys
, data
, NULL
, NULL
);
4152 /******************************************************************
4153 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
4155 DWORD WINAPI
ConvertInterfaceGuidToLuid(const GUID
*guid
, NET_LUID
*luid
)
4157 struct nsi_ndis_ifinfo_static
*data
;
4158 DWORD err
, count
, i
;
4161 TRACE( "(%s %p)\n", debugstr_guid(guid
), luid
);
4163 if (!guid
|| !luid
) return ERROR_INVALID_PARAMETER
;
4166 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
4167 NULL
, 0, NULL
, 0, (void **)&data
, sizeof(*data
), &count
, 0 );
4168 if (err
) return err
;
4170 err
= ERROR_INVALID_PARAMETER
;
4171 for (i
= 0; i
< count
; i
++)
4173 if (IsEqualGUID( &data
[i
].if_guid
, guid
))
4175 luid
->Value
= keys
[i
].Value
;
4176 err
= ERROR_SUCCESS
;
4180 NsiFreeTable( keys
, NULL
, NULL
, data
);
4184 /******************************************************************
4185 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
4187 DWORD WINAPI
ConvertInterfaceIndexToLuid(NET_IFINDEX index
, NET_LUID
*luid
)
4191 TRACE( "(%lu %p)\n", index
, luid
);
4193 if (!luid
) return ERROR_INVALID_PARAMETER
;
4195 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_INDEX_LUID_TABLE
, &index
, sizeof(index
),
4196 NSI_PARAM_TYPE_STATIC
, luid
, sizeof(*luid
), 0 );
4197 if (err
) luid
->Value
= 0;
4201 /******************************************************************
4202 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4204 DWORD WINAPI
ConvertInterfaceLuidToAlias( const NET_LUID
*luid
, WCHAR
*alias
, SIZE_T len
)
4207 IF_COUNTED_STRING name
;
4209 TRACE( "(%p %p %Iu)\n", luid
, alias
, len
);
4211 if (!luid
|| !alias
) return ERROR_INVALID_PARAMETER
;
4213 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4214 NSI_PARAM_TYPE_RW
, &name
, sizeof(name
),
4215 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw
, alias
) );
4216 if (err
) return err
;
4218 if (len
<= name
.Length
/ sizeof(WCHAR
)) return ERROR_NOT_ENOUGH_MEMORY
;
4219 memcpy( alias
, name
.String
, name
.Length
);
4220 alias
[name
.Length
/ sizeof(WCHAR
)] = '\0';
4225 /******************************************************************
4226 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4228 DWORD WINAPI
ConvertInterfaceLuidToGuid(const NET_LUID
*luid
, GUID
*guid
)
4232 TRACE( "(%p %p)\n", luid
, guid
);
4234 if (!luid
|| !guid
) return ERROR_INVALID_PARAMETER
;
4236 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4237 NSI_PARAM_TYPE_STATIC
, guid
, sizeof(*guid
),
4238 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_guid
) );
4239 if (err
) memset( guid
, 0, sizeof(*guid
) );
4243 /******************************************************************
4244 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4246 DWORD WINAPI
ConvertInterfaceLuidToIndex(const NET_LUID
*luid
, NET_IFINDEX
*index
)
4250 TRACE( "(%p %p)\n", luid
, index
);
4252 if (!luid
|| !index
) return ERROR_INVALID_PARAMETER
;
4254 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4255 NSI_PARAM_TYPE_STATIC
, index
, sizeof(*index
),
4256 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_index
) );
4257 if (err
) *index
= 0;
4261 /******************************************************************
4262 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4264 DWORD WINAPI
ConvertInterfaceLuidToNameA(const NET_LUID
*luid
, char *name
, SIZE_T len
)
4267 WCHAR nameW
[IF_MAX_STRING_SIZE
+ 1];
4269 TRACE( "(%p %p %Iu)\n", luid
, name
, len
);
4271 if (!luid
) return ERROR_INVALID_PARAMETER
;
4272 if (!name
|| !len
) return ERROR_NOT_ENOUGH_MEMORY
;
4274 err
= ConvertInterfaceLuidToNameW( luid
, nameW
, ARRAY_SIZE(nameW
) );
4275 if (err
) return err
;
4277 if (!WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, name
, len
, NULL
, NULL
))
4278 err
= GetLastError();
4284 const WCHAR
*prefix
;
4287 static const struct name_prefix name_prefixes
[] =
4289 { L
"other", IF_TYPE_OTHER
},
4290 { L
"ethernet", IF_TYPE_ETHERNET_CSMACD
},
4291 { L
"tokenring", IF_TYPE_ISO88025_TOKENRING
},
4292 { L
"ppp", IF_TYPE_PPP
},
4293 { L
"loopback", IF_TYPE_SOFTWARE_LOOPBACK
},
4294 { L
"atm", IF_TYPE_ATM
},
4295 { L
"wireless", IF_TYPE_IEEE80211
},
4296 { L
"tunnel", IF_TYPE_TUNNEL
},
4297 { L
"ieee1394", IF_TYPE_IEEE1394
}
4300 /******************************************************************
4301 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4303 DWORD WINAPI
ConvertInterfaceLuidToNameW(const NET_LUID
*luid
, WCHAR
*name
, SIZE_T len
)
4306 const WCHAR
*prefix
= NULL
;
4307 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4309 TRACE( "(%p %p %Iu)\n", luid
, name
, len
);
4311 if (!luid
|| !name
) return ERROR_INVALID_PARAMETER
;
4313 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4315 if (luid
->Info
.IfType
== name_prefixes
[i
].type
)
4317 prefix
= name_prefixes
[i
].prefix
;
4322 if (prefix
) needed
= swprintf( buf
, len
, L
"%s_%d", prefix
, luid
->Info
.NetLuidIndex
);
4323 else needed
= swprintf( buf
, len
, L
"iftype%d_%d", luid
->Info
.IfType
, luid
->Info
.NetLuidIndex
);
4325 if (needed
>= len
) return ERROR_NOT_ENOUGH_MEMORY
;
4326 memcpy( name
, buf
, (needed
+ 1) * sizeof(WCHAR
) );
4327 return ERROR_SUCCESS
;
4330 /******************************************************************
4331 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4333 DWORD WINAPI
ConvertInterfaceNameToLuidA(const char *name
, NET_LUID
*luid
)
4335 WCHAR nameW
[IF_MAX_STRING_SIZE
];
4337 TRACE( "(%s %p)\n", debugstr_a(name
), luid
);
4339 if (!name
) return ERROR_INVALID_NAME
;
4340 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, ARRAY_SIZE(nameW
) ))
4341 return GetLastError();
4343 return ConvertInterfaceNameToLuidW( nameW
, luid
);
4346 /******************************************************************
4347 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4349 DWORD WINAPI
ConvertInterfaceNameToLuidW(const WCHAR
*name
, NET_LUID
*luid
)
4352 DWORD type
= ~0u, i
;
4353 int iftype_len
= wcslen( L
"iftype" );
4354 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4356 TRACE( "(%s %p)\n", debugstr_w(name
), luid
);
4358 if (!luid
) return ERROR_INVALID_PARAMETER
;
4359 memset( luid
, 0, sizeof(*luid
) );
4361 if (!name
|| !(sep
= wcschr( name
, '_' )) || sep
>= name
+ ARRAY_SIZE(buf
)) return ERROR_INVALID_NAME
;
4362 memcpy( buf
, name
, (sep
- name
) * sizeof(WCHAR
) );
4363 buf
[sep
- name
] = '\0';
4365 if (sep
- name
> iftype_len
&& !memcmp( buf
, L
"iftype", iftype_len
* sizeof(WCHAR
) ))
4367 type
= wcstol( buf
+ iftype_len
, NULL
, 10 );
4371 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4373 if (!wcscmp( buf
, name_prefixes
[i
].prefix
))
4375 type
= name_prefixes
[i
].type
;
4380 if (type
== ~0u) return ERROR_INVALID_NAME
;
4382 luid
->Info
.NetLuidIndex
= wcstol( sep
+ 1, NULL
, 10 );
4383 luid
->Info
.IfType
= type
;
4384 return ERROR_SUCCESS
;
4387 /******************************************************************
4388 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4390 DWORD WINAPI
ConvertLengthToIpv4Mask(ULONG mask_len
, ULONG
*mask
)
4394 *mask
= INADDR_NONE
;
4395 return ERROR_INVALID_PARAMETER
;
4401 *mask
= htonl(~0u << (32 - mask_len
));
4406 /******************************************************************
4407 * if_nametoindex (IPHLPAPI.@)
4409 IF_INDEX WINAPI
IPHLP_if_nametoindex(const char *name
)
4415 TRACE( "(%s)\n", name
);
4417 err
= ConvertInterfaceNameToLuidA( name
, &luid
);
4420 err
= ConvertInterfaceLuidToIndex( &luid
, &index
);
4425 /******************************************************************
4426 * if_indextoname (IPHLPAPI.@)
4428 char *WINAPI
IPHLP_if_indextoname( NET_IFINDEX index
, char *name
)
4433 TRACE( "(%lu, %p)\n", index
, name
);
4435 err
= ConvertInterfaceIndexToLuid( index
, &luid
);
4436 if (err
) return NULL
;
4438 err
= ConvertInterfaceLuidToNameA( &luid
, name
, IF_MAX_STRING_SIZE
);
4439 if (err
) return NULL
;
4443 /******************************************************************
4444 * GetIpInterfaceTable (IPHLPAPI.@)
4446 DWORD WINAPI
GetIpInterfaceTable(ADDRESS_FAMILY family
, PMIB_IPINTERFACE_TABLE
*table
)
4448 FIXME("(%u %p): stub\n", family
, table
);
4449 return ERROR_NOT_SUPPORTED
;
4452 /******************************************************************
4453 * GetBestRoute2 (IPHLPAPI.@)
4455 DWORD WINAPI
GetBestRoute2(NET_LUID
*luid
, NET_IFINDEX index
,
4456 const SOCKADDR_INET
*source
, const SOCKADDR_INET
*destination
,
4457 ULONG options
, PMIB_IPFORWARD_ROW2 bestroute
,
4458 SOCKADDR_INET
*bestaddress
)
4463 FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid
, index
, source
,
4464 destination
, options
, bestroute
, bestaddress
);
4466 if (!destination
|| !bestroute
|| !bestaddress
)
4467 return ERROR_INVALID_PARAMETER
;
4469 return ERROR_NOT_SUPPORTED
;
4472 /******************************************************************
4473 * ParseNetworkString (IPHLPAPI.@)
4475 DWORD WINAPI
ParseNetworkString(const WCHAR
*str
, DWORD type
,
4476 NET_ADDRESS_INFO
*info
, USHORT
*port
, BYTE
*prefix_len
)
4479 IN6_ADDR temp_addr6
;
4481 USHORT temp_port
= 0;
4484 TRACE("(%s, %ld, %p, %p, %p)\n", debugstr_w(str
), type
, info
, port
, prefix_len
);
4487 return ERROR_INVALID_PARAMETER
;
4489 if (type
& NET_STRING_IPV4_ADDRESS
)
4491 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4492 if (SUCCEEDED(status
) && !temp_port
)
4496 info
->Format
= NET_ADDRESS_IPV4
;
4497 info
->Ipv4Address
.sin_addr
= temp_addr4
;
4498 info
->Ipv4Address
.sin_port
= 0;
4500 if (port
) *port
= 0;
4501 if (prefix_len
) *prefix_len
= 255;
4502 return ERROR_SUCCESS
;
4505 if (type
& NET_STRING_IPV4_SERVICE
)
4507 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4508 if (SUCCEEDED(status
) && temp_port
)
4512 info
->Format
= NET_ADDRESS_IPV4
;
4513 info
->Ipv4Address
.sin_addr
= temp_addr4
;
4514 info
->Ipv4Address
.sin_port
= temp_port
;
4516 if (port
) *port
= ntohs(temp_port
);
4517 if (prefix_len
) *prefix_len
= 255;
4518 return ERROR_SUCCESS
;
4521 if (type
& NET_STRING_IPV6_ADDRESS
)
4523 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4524 if (SUCCEEDED(status
) && !temp_port
)
4528 info
->Format
= NET_ADDRESS_IPV6
;
4529 info
->Ipv6Address
.sin6_addr
= temp_addr6
;
4530 info
->Ipv6Address
.sin6_scope_id
= temp_scope
;
4531 info
->Ipv6Address
.sin6_port
= 0;
4533 if (port
) *port
= 0;
4534 if (prefix_len
) *prefix_len
= 255;
4535 return ERROR_SUCCESS
;
4538 if (type
& NET_STRING_IPV6_SERVICE
)
4540 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4541 if (SUCCEEDED(status
) && temp_port
)
4545 info
->Format
= NET_ADDRESS_IPV6
;
4546 info
->Ipv6Address
.sin6_addr
= temp_addr6
;
4547 info
->Ipv6Address
.sin6_scope_id
= temp_scope
;
4548 info
->Ipv6Address
.sin6_port
= temp_port
;
4550 if (port
) *port
= ntohs(temp_port
);
4551 if (prefix_len
) *prefix_len
= 255;
4552 return ERROR_SUCCESS
;
4556 if (info
) info
->Format
= NET_ADDRESS_FORMAT_UNSPECIFIED
;
4558 if (type
& ~(NET_STRING_IPV4_ADDRESS
|NET_STRING_IPV4_SERVICE
|NET_STRING_IPV6_ADDRESS
|NET_STRING_IPV6_SERVICE
))
4560 FIXME("Unimplemented type 0x%lx\n", type
);
4561 return ERROR_NOT_SUPPORTED
;
4564 return ERROR_INVALID_PARAMETER
;
4567 struct icmp_handle_data
4572 /***********************************************************************
4573 * IcmpCloseHandle (IPHLPAPI.@)
4575 BOOL WINAPI
IcmpCloseHandle( HANDLE handle
)
4577 struct icmp_handle_data
*data
;
4579 if (handle
== NULL
|| handle
== INVALID_HANDLE_VALUE
)
4582 data
= (struct icmp_handle_data
*)handle
;
4584 CloseHandle( data
->nsi_device
);
4589 /***********************************************************************
4590 * IcmpCreateFile (IPHLPAPI.@)
4592 HANDLE WINAPI
IcmpCreateFile( void )
4594 struct icmp_handle_data
*data
= heap_alloc( sizeof(*data
) );
4598 SetLastError( IP_NO_RESOURCES
);
4599 return INVALID_HANDLE_VALUE
;
4602 data
->nsi_device
= CreateFileW( L
"\\\\.\\Nsi", 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
4603 FILE_FLAG_OVERLAPPED
, NULL
);
4604 if (data
->nsi_device
== INVALID_HANDLE_VALUE
)
4607 return INVALID_HANDLE_VALUE
;
4610 return (HANDLE
)data
;
4613 /******************************************************************
4614 * IcmpParseReplies (IPHLPAPI.@)
4616 DWORD WINAPI
IcmpParseReplies( void *reply
, DWORD reply_size
)
4618 ICMP_ECHO_REPLY
*icmp_reply
= reply
;
4619 DWORD num_pkts
= icmp_reply
->Reserved
;
4621 icmp_reply
->Reserved
= 0;
4622 if (!num_pkts
) SetLastError( icmp_reply
->Status
);
4626 /***********************************************************************
4627 * IcmpSendEcho (IPHLPAPI.@)
4629 DWORD WINAPI
IcmpSendEcho( HANDLE handle
, IPAddr dst
, void *request
, WORD request_size
,
4630 IP_OPTION_INFORMATION
*opts
, void *reply
, DWORD reply_size
,
4633 return IcmpSendEcho2Ex( handle
, NULL
, NULL
, NULL
, INADDR_ANY
, dst
, request
, request_size
,
4634 opts
, reply
, reply_size
, timeout
);
4637 /***********************************************************************
4638 * IcmpSendEcho2 (IPHLPAPI.@)
4640 DWORD WINAPI
IcmpSendEcho2( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4641 IPAddr dst
, void *request
, WORD request_size
, IP_OPTION_INFORMATION
*opts
,
4642 void *reply
, DWORD reply_size
, DWORD timeout
)
4644 return IcmpSendEcho2Ex( handle
, event
, apc_routine
, apc_ctxt
, INADDR_ANY
, dst
, request
, request_size
,
4645 opts
, reply
, reply_size
, timeout
);
4648 struct icmp_apc_ctxt
4651 PIO_APC_ROUTINE apc_routine
;
4652 IO_STATUS_BLOCK iosb
;
4655 void WINAPI
icmp_apc_routine( void *context
, IO_STATUS_BLOCK
*iosb
, ULONG reserved
)
4657 struct icmp_apc_ctxt
*ctxt
= context
;
4659 ctxt
->apc_routine( ctxt
->apc_ctxt
, iosb
, reserved
);
4663 /***********************************************************************
4664 * IcmpSendEcho2Ex (IPHLPAPI.@)
4666 DWORD WINAPI
IcmpSendEcho2Ex( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4667 IPAddr src
, IPAddr dst
, void *request
, WORD request_size
, IP_OPTION_INFORMATION
*opts
,
4668 void *reply
, DWORD reply_size
, DWORD timeout
)
4670 struct icmp_handle_data
*data
= (struct icmp_handle_data
*)handle
;
4671 struct icmp_apc_ctxt
*ctxt
= heap_alloc( sizeof(*ctxt
) );
4672 IO_STATUS_BLOCK
*iosb
= &ctxt
->iosb
;
4673 DWORD opt_size
, in_size
, ret
= 0;
4674 struct nsiproxy_icmp_echo
*in
;
4675 HANDLE request_event
;
4678 if (handle
== INVALID_HANDLE_VALUE
|| !reply
)
4681 SetLastError( ERROR_INVALID_PARAMETER
);
4685 ctxt
->apc_routine
= apc_routine
;
4686 ctxt
->apc_ctxt
= apc_ctxt
;
4688 opt_size
= opts
? (opts
->OptionsSize
+ 3) & ~3 : 0;
4689 in_size
= FIELD_OFFSET(struct nsiproxy_icmp_echo
, data
[opt_size
+ request_size
]);
4690 in
= heap_alloc_zero( in_size
);
4695 SetLastError( IP_NO_RESOURCES
);
4699 in
->user_reply_ptr
= (ULONG_PTR
)reply
;
4700 in
->bits
= sizeof(void*) * 8;
4701 in
->src
.Ipv4
.sin_family
= AF_INET
;
4702 in
->src
.Ipv4
.sin_addr
.s_addr
= src
;
4703 in
->dst
.Ipv4
.sin_family
= AF_INET
;
4704 in
->dst
.Ipv4
.sin_addr
.s_addr
= dst
;
4707 in
->ttl
= opts
->Ttl
;
4708 in
->tos
= opts
->Tos
;
4709 in
->flags
= opts
->Flags
;
4710 memcpy( in
->data
, opts
->OptionsData
, opts
->OptionsSize
);
4711 in
->opt_size
= opts
->OptionsSize
;
4713 in
->req_size
= request_size
;
4714 in
->timeout
= timeout
;
4715 memcpy( in
->data
+ opt_size
, request
, request_size
);
4717 request_event
= event
? event
: (apc_routine
? NULL
: CreateEventW( NULL
, 0, 0, NULL
));
4719 status
= NtDeviceIoControlFile( data
->nsi_device
, request_event
, apc_routine
? icmp_apc_routine
: NULL
,
4720 apc_routine
? ctxt
: apc_ctxt
, iosb
, IOCTL_NSIPROXY_WINE_ICMP_ECHO
,
4721 in
, in_size
, reply
, reply_size
);
4723 if (status
== STATUS_PENDING
)
4725 if (!event
&& !apc_routine
&& !WaitForSingleObject( request_event
, INFINITE
))
4726 status
= iosb
->Status
;
4730 ret
= IcmpParseReplies( reply
, reply_size
);
4732 if (!event
&& request_event
) CloseHandle( request_event
);
4733 if (!apc_routine
|| status
!= STATUS_PENDING
) heap_free( ctxt
);
4736 if (status
) SetLastError( RtlNtStatusToDosError( status
) );
4740 /***********************************************************************
4741 * Icmp6CreateFile (IPHLPAPI.@)
4743 HANDLE WINAPI
Icmp6CreateFile( void )
4746 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4747 return INVALID_HANDLE_VALUE
;
4750 /***********************************************************************
4751 * Icmp6SendEcho2 (IPHLPAPI.@)
4753 DWORD WINAPI
Icmp6SendEcho2( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4754 struct sockaddr_in6
*src
, struct sockaddr_in6
*dst
, void *request
, WORD request_size
,
4755 IP_OPTION_INFORMATION
*opts
, void *reply
, DWORD reply_size
, DWORD timeout
)
4757 FIXME( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld): stub\n", handle
, event
,
4758 apc_routine
, apc_ctxt
, src
, dst
, request
, request_size
, opts
, reply
, reply_size
, timeout
);
4759 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4763 /***********************************************************************
4764 * GetCurrentThreadCompartmentId (IPHLPAPI.@)
4766 NET_IF_COMPARTMENT_ID WINAPI
GetCurrentThreadCompartmentId( void )
4769 return NET_IF_COMPARTMENT_ID_PRIMARY
;