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 "tcpestats.h"
36 #include "ip2string.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
46 #define CHARS_IN_GUID 39
48 static const WCHAR
*device_tcpip
= L
"\\DEVICE\\TCPIP_";
50 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
);
52 static const NPI_MODULEID
*ip_module_id( USHORT family
)
54 if (family
== AF_INET
) return &NPI_MS_IPV4_MODULEID
;
55 if (family
== AF_INET6
) return &NPI_MS_IPV6_MODULEID
;
59 DWORD WINAPI
ConvertGuidToStringA( const GUID
*guid
, char *str
, DWORD len
)
61 if (len
< CHARS_IN_GUID
) return ERROR_INSUFFICIENT_BUFFER
;
62 sprintf( str
, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
63 guid
->Data1
, guid
->Data2
, guid
->Data3
, guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2],
64 guid
->Data4
[3], guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
68 DWORD WINAPI
ConvertGuidToStringW( const GUID
*guid
, WCHAR
*str
, DWORD len
)
70 if (len
< CHARS_IN_GUID
) return ERROR_INSUFFICIENT_BUFFER
;
71 swprintf( str
, len
, L
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
72 guid
->Data1
, guid
->Data2
, guid
->Data3
, guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2],
73 guid
->Data4
[3], guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
77 DWORD WINAPI
ConvertStringToGuidW( const WCHAR
*str
, GUID
*guid
)
81 RtlInitUnicodeString( &ustr
, str
);
82 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr
, guid
) );
85 static void if_counted_string_copy( WCHAR
*dst
, unsigned int len
, IF_COUNTED_STRING
*src
)
87 unsigned int copy
= src
->Length
;
89 if (copy
>= len
* sizeof(WCHAR
)) copy
= 0;
90 memcpy( dst
, src
->String
, copy
);
91 memset( (char *)dst
+ copy
, 0, len
* sizeof(WCHAR
) - copy
);
94 /******************************************************************
95 * AddIPAddress (IPHLPAPI.@)
97 * Add an IP address to an adapter.
100 * Address [In] IP address to add to the adapter
101 * IpMask [In] subnet mask for the IP address
102 * IfIndex [In] adapter index to add the address
103 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
104 * NTEInstance [Out] NTE instance for the IP address
108 * Failure: error code from winerror.h
111 * Stub. Currently returns ERROR_NOT_SUPPORTED.
113 DWORD WINAPI
AddIPAddress(IPAddr Address
, IPMask IpMask
, DWORD IfIndex
, PULONG NTEContext
, PULONG NTEInstance
)
116 return ERROR_NOT_SUPPORTED
;
119 /******************************************************************
120 * CancelIPChangeNotify (IPHLPAPI.@)
122 * Cancel a previous notification created by NotifyAddrChange or
126 * overlapped [In] overlapped structure that notifies the caller
133 * Stub, returns FALSE.
135 BOOL WINAPI
CancelIPChangeNotify(LPOVERLAPPED overlapped
)
137 FIXME("(overlapped %p): stub\n", overlapped
);
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
;
965 SOCKADDR_IN6
*in6
= (SOCKADDR_IN6
*)addr
->Address
.lpSockaddr
;
966 in6
->sin6_addr
= key6
->addr
;
967 in6
->sin6_scope_id
= dyn
[i
].scope_id
;
969 addr
->PrefixOrigin
= rw
[i
].prefix_origin
;
970 addr
->SuffixOrigin
= rw
[i
].suffix_origin
;
971 addr
->DadState
= dyn
[i
].dad_state
;
972 addr
->ValidLifetime
= rw
[i
].valid_lifetime
;
973 addr
->PreferredLifetime
= rw
[i
].preferred_lifetime
;
974 addr
->LeaseLifetime
= rw
[i
].valid_lifetime
; /* FIXME */
975 addr
->OnLinkPrefixLength
= rw
[i
].on_link_prefix
;
976 if (unicast_is_dns_eligible( addr
)) addr
->Flags
|= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE
;
985 NsiFreeTable( key
, rw
, dyn
, stat
);
989 static DWORD
gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
991 struct nsi_ipv4_forward_key
*key4
;
992 struct nsi_ipv6_forward_key
*key6
;
993 IP_ADAPTER_GATEWAY_ADDRESS
*gw
, **gw_next
;
994 IP_ADAPTER_PREFIX
*prefix
, **prefix_next
;
995 DWORD err
, count
, i
, prefix_len
, key_size
= (family
== AF_INET
) ? sizeof(*key4
) : sizeof(*key6
);
996 DWORD sockaddr_size
= (family
== AF_INET
) ? sizeof(SOCKADDR_IN
) : sizeof(SOCKADDR_IN6
);
997 SOCKADDR_INET sockaddr
;
1001 err
= NsiAllocateAndGetTable( 1, ip_module_id( family
), NSI_IP_FORWARD_TABLE
, &key
, key_size
,
1002 NULL
, 0, NULL
, 0, NULL
, 0, &count
, 0 );
1003 if (err
) return err
;
1007 for (gw_next
= &aa
->FirstGatewayAddress
; *gw_next
; gw_next
= &(*gw_next
)->Next
)
1009 for (prefix_next
= &aa
->FirstPrefix
; *prefix_next
; prefix_next
= &(*prefix_next
)->Next
)
1012 for (i
= 0; i
< count
; i
++)
1014 key4
= (struct nsi_ipv4_forward_key
*)key
+ i
;
1015 key6
= (struct nsi_ipv6_forward_key
*)key
+ i
;
1016 luid
= (family
== AF_INET
) ? &key4
->luid
: &key6
->luid
;
1017 if (luid
->Value
!= aa
->Luid
.Value
) continue;
1019 if (flags
& GAA_FLAG_INCLUDE_ALL_GATEWAYS
)
1021 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1022 if (family
== AF_INET
)
1024 if (key4
->next_hop
.s_addr
!= 0)
1026 sockaddr
.si_family
= family
;
1027 sockaddr
.Ipv4
.sin_addr
= key4
->next_hop
;
1032 static const IN6_ADDR zero
;
1033 if (memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1035 sockaddr
.si_family
= family
;
1036 sockaddr
.Ipv6
.sin6_addr
= key6
->next_hop
;
1040 if (sockaddr
.si_family
)
1042 gw
= heap_alloc_zero( sizeof(*gw
) + sockaddr_size
);
1045 err
= ERROR_NOT_ENOUGH_MEMORY
;
1048 gw
->Length
= sizeof(*gw
);
1049 gw
->Address
.lpSockaddr
= (SOCKADDR
*)(gw
+ 1);
1050 gw
->Address
.iSockaddrLength
= sockaddr_size
;
1051 memcpy( gw
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1053 gw_next
= &gw
->Next
;
1057 if (flags
& GAA_FLAG_INCLUDE_PREFIX
)
1059 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1061 if (family
== AF_INET
)
1063 if (!key4
->next_hop
.s_addr
)
1065 sockaddr
.si_family
= family
;
1066 sockaddr
.Ipv4
.sin_addr
= key4
->prefix
;
1067 prefix_len
= key4
->prefix_len
;
1072 static const IN6_ADDR zero
;
1073 if (!memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1075 sockaddr
.si_family
= family
;
1076 sockaddr
.Ipv6
.sin6_addr
= key6
->prefix
;
1077 prefix_len
= key6
->prefix_len
;
1081 if (sockaddr
.si_family
)
1083 prefix
= heap_alloc_zero( sizeof(*prefix
) + sockaddr_size
);
1086 err
= ERROR_NOT_ENOUGH_MEMORY
;
1089 prefix
->Length
= sizeof(*prefix
);
1090 prefix
->Address
.lpSockaddr
= (SOCKADDR
*)(prefix
+ 1);
1091 prefix
->Address
.iSockaddrLength
= sockaddr_size
;
1092 memcpy( prefix
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1093 prefix
->PrefixLength
= prefix_len
;
1094 *prefix_next
= prefix
;
1095 prefix_next
= &prefix
->Next
;
1103 NsiFreeTable( key
, NULL
, NULL
, NULL
);
1107 static DWORD
call_families( DWORD (*fn
)( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
),
1108 IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1112 if (family
!= AF_INET
)
1114 err
= fn( aa
, AF_INET6
, flags
);
1115 if (err
) return err
;
1118 if (family
!= AF_INET6
)
1120 err
= fn( aa
, AF_INET
, flags
);
1121 if (err
) return err
;
1126 static DWORD
dns_servers_query_code( ULONG family
)
1128 if (family
== AF_INET
) return DnsConfigDnsServersIpv4
;
1129 if (family
== AF_INET6
) return DnsConfigDnsServersIpv6
;
1130 return DnsConfigDnsServersUnspec
;
1133 static DWORD
dns_info_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1135 char buf
[FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[3])];
1136 IP_ADAPTER_DNS_SERVER_ADDRESS
*dns
, **next
;
1137 DWORD query
= dns_servers_query_code( family
);
1138 DWORD err
, i
, size
, attempt
, sockaddr_len
;
1139 WCHAR name
[MAX_ADAPTER_NAME_LENGTH
+ 1];
1140 DNS_ADDR_ARRAY
*servers
;
1145 MultiByteToWideChar( CP_ACP
, 0, aa
->AdapterName
, -1, name
, ARRAY_SIZE(name
) );
1146 if (!(flags
& GAA_FLAG_SKIP_DNS_SERVER
))
1148 servers
= (DNS_ADDR_ARRAY
*)buf
;
1149 for (attempt
= 0; attempt
< 5; attempt
++)
1151 err
= DnsQueryConfig( query
, 0, name
, NULL
, servers
, &size
);
1152 if (err
!= ERROR_MORE_DATA
) break;
1153 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1154 servers
= heap_alloc( size
);
1157 err
= ERROR_NOT_ENOUGH_MEMORY
;
1163 next
= &aa
->FirstDnsServerAddress
;
1164 for (i
= 0; i
< servers
->AddrCount
; i
++)
1166 sockaddr_len
= servers
->AddrArray
[i
].Data
.DnsAddrUserDword
[0];
1167 if (sockaddr_len
> sizeof(servers
->AddrArray
[i
].MaxSa
))
1168 sockaddr_len
= sizeof(servers
->AddrArray
[i
].MaxSa
);
1169 dns
= heap_alloc_zero( sizeof(*dns
) + sockaddr_len
);
1172 err
= ERROR_NOT_ENOUGH_MEMORY
;
1175 dns
->Length
= sizeof(*dns
);
1176 dns
->Address
.lpSockaddr
= (SOCKADDR
*)(dns
+ 1);
1177 dns
->Address
.iSockaddrLength
= sockaddr_len
;
1178 memcpy( dns
->Address
.lpSockaddr
, servers
->AddrArray
[i
].MaxSa
, sockaddr_len
);
1183 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1184 if (err
) return err
;
1187 aa
->DnsSuffix
= heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH
* sizeof(WCHAR
) );
1188 if (!aa
->DnsSuffix
) return ERROR_NOT_ENOUGH_MEMORY
;
1189 aa
->DnsSuffix
[0] = '\0';
1191 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, NULL
, &size
) &&
1192 (search
= heap_alloc( size
)))
1194 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, search
, &size
) &&
1195 search
[0] && wcslen( search
) < MAX_DNS_SUFFIX_STRING_LENGTH
)
1197 wcscpy( aa
->DnsSuffix
, search
);
1199 heap_free( search
);
1205 return ERROR_SUCCESS
;
1208 static DWORD
adapters_addresses_alloc( ULONG family
, ULONG flags
, IP_ADAPTER_ADDRESSES
**info
)
1210 IP_ADAPTER_ADDRESSES
*aa
;
1212 struct nsi_ndis_ifinfo_rw
*rw
;
1213 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1214 struct nsi_ndis_ifinfo_static
*stat
;
1215 DWORD err
, i
, count
, needed
;
1219 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&luids
, sizeof(*luids
),
1220 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1221 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1222 if (err
) return err
;
1224 needed
= count
* (sizeof(*aa
) + ((CHARS_IN_GUID
+ 1) & ~1) + sizeof(stat
->descr
.String
));
1225 needed
+= count
* sizeof(rw
->alias
.String
); /* GAA_FLAG_SKIP_FRIENDLY_NAME is ignored */
1227 aa
= heap_alloc_zero( needed
);
1230 err
= ERROR_NOT_ENOUGH_MEMORY
;
1234 str_ptr
= (char *)(aa
+ count
);
1235 for (i
= 0; i
< count
; i
++)
1237 aa
[i
].Length
= sizeof(*aa
);
1238 aa
[i
].IfIndex
= stat
[i
].if_index
;
1239 if (i
< count
- 1) aa
[i
].Next
= aa
+ i
+ 1;
1240 ConvertInterfaceLuidToGuid( luids
+ i
, &guid
);
1241 ConvertGuidToStringA( &guid
, str_ptr
, CHARS_IN_GUID
);
1242 aa
[i
].AdapterName
= str_ptr
;
1243 str_ptr
+= (CHARS_IN_GUID
+ 1) & ~1;
1244 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(stat
[i
].descr
.String
), &stat
[i
].descr
);
1245 aa
[i
].Description
= (WCHAR
*)str_ptr
;
1246 str_ptr
+= sizeof(stat
[i
].descr
.String
);
1247 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(rw
[i
].alias
.String
), &rw
[i
].alias
);
1248 aa
[i
].FriendlyName
= (WCHAR
*)str_ptr
;
1249 str_ptr
+= sizeof(rw
[i
].alias
.String
);
1250 aa
[i
].PhysicalAddressLength
= rw
[i
].phys_addr
.Length
;
1251 if (aa
[i
].PhysicalAddressLength
> sizeof(aa
[i
].PhysicalAddress
)) aa
[i
].PhysicalAddressLength
= 0;
1252 memcpy( aa
[i
].PhysicalAddress
, rw
[i
].phys_addr
.Address
, aa
[i
].PhysicalAddressLength
);
1253 aa
[i
].Mtu
= dyn
[i
].mtu
;
1254 aa
[i
].IfType
= stat
[i
].type
;
1255 aa
[i
].OperStatus
= dyn
[i
].oper_status
;
1256 aa
[i
].TransmitLinkSpeed
= dyn
[i
].xmit_speed
;
1257 aa
[i
].ReceiveLinkSpeed
= dyn
[i
].rcv_speed
;
1258 aa
[i
].Luid
= luids
[i
];
1259 aa
[i
].NetworkGuid
= rw
[i
].network_guid
;
1260 aa
[i
].ConnectionType
= stat
[i
].conn_type
;
1263 if (!(flags
& GAA_FLAG_SKIP_UNICAST
))
1265 err
= call_families( unicast_addresses_alloc
, aa
, family
, flags
);
1269 if (flags
& (GAA_FLAG_INCLUDE_ALL_GATEWAYS
| GAA_FLAG_INCLUDE_PREFIX
))
1271 err
= call_families( gateway_and_prefix_addresses_alloc
, aa
, family
, flags
);
1275 err
= dns_info_alloc( aa
, family
, flags
);
1279 NsiFreeTable( luids
, rw
, dyn
, stat
);
1280 if (!err
) *info
= aa
;
1281 else adapters_addresses_free( aa
);
1285 ULONG WINAPI DECLSPEC_HOTPATCH
GetAdaptersAddresses( ULONG family
, ULONG flags
, void *reserved
,
1286 IP_ADAPTER_ADDRESSES
*aa
, ULONG
*size
)
1288 IP_ADAPTER_ADDRESSES
*info
;
1291 TRACE( "(%ld, %08lx, %p, %p, %p)\n", family
, flags
, reserved
, aa
, size
);
1293 if (!size
) return ERROR_INVALID_PARAMETER
;
1295 err
= adapters_addresses_alloc( family
, flags
, &info
);
1296 if (err
) return err
;
1298 needed
= adapters_addresses_size( info
);
1299 if (!aa
|| *size
< needed
)
1302 err
= ERROR_BUFFER_OVERFLOW
;
1305 adapters_addresses_copy( aa
, info
);
1307 adapters_addresses_free( info
);
1311 /******************************************************************
1312 * GetBestInterface (IPHLPAPI.@)
1314 * Get the interface, with the best route for the given IP address.
1317 * dwDestAddr [In] IP address to search the interface for
1318 * pdwBestIfIndex [Out] found best interface
1322 * Failure: error code from winerror.h
1324 DWORD WINAPI
GetBestInterface(IPAddr dwDestAddr
, PDWORD pdwBestIfIndex
)
1326 struct sockaddr_in sa_in
;
1327 memset(&sa_in
, 0, sizeof(sa_in
));
1328 sa_in
.sin_family
= AF_INET
;
1329 sa_in
.sin_addr
.S_un
.S_addr
= dwDestAddr
;
1330 return GetBestInterfaceEx((struct sockaddr
*)&sa_in
, pdwBestIfIndex
);
1333 /******************************************************************
1334 * GetBestInterfaceEx (IPHLPAPI.@)
1336 * Get the interface, with the best route for the given IP address.
1339 * dwDestAddr [In] IP address to search the interface for
1340 * pdwBestIfIndex [Out] found best interface
1344 * Failure: error code from winerror.h
1346 DWORD WINAPI
GetBestInterfaceEx(struct sockaddr
*pDestAddr
, PDWORD pdwBestIfIndex
)
1350 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr
, pdwBestIfIndex
);
1351 if (!pDestAddr
|| !pdwBestIfIndex
)
1352 ret
= ERROR_INVALID_PARAMETER
;
1354 MIB_IPFORWARDROW ipRow
;
1356 if (pDestAddr
->sa_family
== AF_INET
) {
1357 ret
= GetBestRoute(((struct sockaddr_in
*)pDestAddr
)->sin_addr
.S_un
.S_addr
, 0, &ipRow
);
1358 if (ret
== ERROR_SUCCESS
)
1359 *pdwBestIfIndex
= ipRow
.dwForwardIfIndex
;
1361 FIXME("address family %d not supported\n", pDestAddr
->sa_family
);
1362 ret
= ERROR_NOT_SUPPORTED
;
1365 TRACE("returning %ld\n", ret
);
1370 /******************************************************************
1371 * GetBestRoute (IPHLPAPI.@)
1373 * Get the best route for the given IP address.
1376 * dwDestAddr [In] IP address to search the best route for
1377 * dwSourceAddr [In] optional source IP address
1378 * pBestRoute [Out] found best route
1382 * Failure: error code from winerror.h
1384 DWORD WINAPI
GetBestRoute(DWORD dwDestAddr
, DWORD dwSourceAddr
, PMIB_IPFORWARDROW pBestRoute
)
1386 PMIB_IPFORWARDTABLE table
;
1389 TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr
,
1390 dwSourceAddr
, pBestRoute
);
1392 return ERROR_INVALID_PARAMETER
;
1394 ret
= AllocateAndGetIpForwardTableFromStack(&table
, FALSE
, GetProcessHeap(), 0);
1396 DWORD ndx
, matchedBits
, matchedNdx
= table
->dwNumEntries
;
1398 for (ndx
= 0, matchedBits
= 0; ndx
< table
->dwNumEntries
; ndx
++) {
1399 if (table
->table
[ndx
].ForwardType
!= MIB_IPROUTE_TYPE_INVALID
&&
1400 (dwDestAddr
& table
->table
[ndx
].dwForwardMask
) ==
1401 (table
->table
[ndx
].dwForwardDest
& table
->table
[ndx
].dwForwardMask
)) {
1402 DWORD numShifts
, mask
;
1404 for (numShifts
= 0, mask
= table
->table
[ndx
].dwForwardMask
;
1405 mask
&& mask
& 1; mask
>>= 1, numShifts
++)
1407 if (numShifts
> matchedBits
) {
1408 matchedBits
= numShifts
;
1411 else if (!matchedBits
) {
1416 if (matchedNdx
< table
->dwNumEntries
) {
1417 memcpy(pBestRoute
, &table
->table
[matchedNdx
], sizeof(MIB_IPFORWARDROW
));
1418 ret
= ERROR_SUCCESS
;
1421 /* No route matches, which can happen if there's no default route. */
1422 ret
= ERROR_HOST_UNREACHABLE
;
1424 HeapFree(GetProcessHeap(), 0, table
);
1426 TRACE("returning %ld\n", ret
);
1431 /******************************************************************
1432 * GetFriendlyIfIndex (IPHLPAPI.@)
1434 * Get a "friendly" version of IfIndex, which is one that doesn't
1435 * have the top byte set. Doesn't validate whether IfIndex is a valid
1439 * IfIndex [In] interface index to get the friendly one for
1442 * A friendly version of IfIndex.
1444 DWORD WINAPI
GetFriendlyIfIndex(DWORD IfIndex
)
1446 /* windows doesn't validate these, either, just makes sure the top byte is
1447 cleared. I assume my ifenum module never gives an index with the top
1449 TRACE("returning %ld\n", IfIndex
);
1453 static void icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX
*stats_ex
, MIBICMPSTATS
*stats
)
1455 stats
->dwMsgs
= stats_ex
->dwMsgs
;
1456 stats
->dwErrors
= stats_ex
->dwErrors
;
1457 stats
->dwDestUnreachs
= stats_ex
->rgdwTypeCount
[ICMP4_DST_UNREACH
];
1458 stats
->dwTimeExcds
= stats_ex
->rgdwTypeCount
[ICMP4_TIME_EXCEEDED
];
1459 stats
->dwParmProbs
= stats_ex
->rgdwTypeCount
[ICMP4_PARAM_PROB
];
1460 stats
->dwSrcQuenchs
= stats_ex
->rgdwTypeCount
[ICMP4_SOURCE_QUENCH
];
1461 stats
->dwRedirects
= stats_ex
->rgdwTypeCount
[ICMP4_REDIRECT
];
1462 stats
->dwEchos
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REQUEST
];
1463 stats
->dwEchoReps
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REPLY
];
1464 stats
->dwTimestamps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
];
1465 stats
->dwTimestampReps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
];
1466 stats
->dwAddrMasks
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REQUEST
];
1467 stats
->dwAddrMaskReps
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REPLY
];
1470 /******************************************************************
1471 * GetIcmpStatistics (IPHLPAPI.@)
1473 * Get the ICMP statistics for the local computer.
1476 * stats [Out] buffer for ICMP statistics
1480 * Failure: error code from winerror.h
1482 DWORD WINAPI
GetIcmpStatistics( MIB_ICMP
*stats
)
1484 MIB_ICMP_EX stats_ex
;
1485 DWORD err
= GetIcmpStatisticsEx( &stats_ex
, AF_INET
);
1487 if (err
) return err
;
1489 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpInStats
, &stats
->stats
.icmpInStats
);
1490 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpOutStats
, &stats
->stats
.icmpOutStats
);
1494 /******************************************************************
1495 * GetIcmpStatisticsEx (IPHLPAPI.@)
1497 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1500 * stats [Out] buffer for ICMP statistics
1501 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1505 * Failure: error code from winerror.h
1507 DWORD WINAPI
GetIcmpStatisticsEx( MIB_ICMP_EX
*stats
, DWORD family
)
1509 const NPI_MODULEID
*mod
= ip_module_id( family
);
1510 struct nsi_ip_icmpstats_dynamic dyn
;
1513 if (!stats
|| !mod
) return ERROR_INVALID_PARAMETER
;
1514 memset( stats
, 0, sizeof(*stats
) );
1516 err
= NsiGetAllParameters( 1, mod
, NSI_IP_ICMPSTATS_TABLE
, NULL
, 0, NULL
, 0,
1517 &dyn
, sizeof(dyn
), NULL
, 0 );
1518 if (err
) return err
;
1520 stats
->icmpInStats
.dwMsgs
= dyn
.in_msgs
;
1521 stats
->icmpInStats
.dwErrors
= dyn
.in_errors
;
1522 memcpy( stats
->icmpInStats
.rgdwTypeCount
, dyn
.in_type_counts
, sizeof( dyn
.in_type_counts
) );
1523 stats
->icmpOutStats
.dwMsgs
= dyn
.out_msgs
;
1524 stats
->icmpOutStats
.dwErrors
= dyn
.out_errors
;
1525 memcpy( stats
->icmpOutStats
.rgdwTypeCount
, dyn
.out_type_counts
, sizeof( dyn
.out_type_counts
) );
1527 return ERROR_SUCCESS
;
1530 static void if_row_fill( MIB_IFROW
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1531 struct nsi_ndis_ifinfo_static
*stat
)
1533 wcscpy( row
->wszName
, device_tcpip
);
1534 ConvertGuidToStringW( &stat
->if_guid
, row
->wszName
+ wcslen( device_tcpip
), CHARS_IN_GUID
);
1535 row
->dwIndex
= stat
->if_index
;
1536 row
->dwType
= stat
->type
;
1537 row
->dwMtu
= dyn
->mtu
;
1538 row
->dwSpeed
= dyn
->rcv_speed
;
1539 row
->dwPhysAddrLen
= rw
->phys_addr
.Length
;
1540 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
1541 memcpy( row
->bPhysAddr
, rw
->phys_addr
.Address
, row
->dwPhysAddrLen
);
1542 row
->dwAdminStatus
= rw
->admin_status
;
1543 row
->dwOperStatus
= (dyn
->oper_status
== IfOperStatusUp
) ? MIB_IF_OPER_STATUS_OPERATIONAL
: MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
1544 row
->dwLastChange
= 0;
1545 row
->dwInOctets
= dyn
->in_octets
;
1546 row
->dwInUcastPkts
= dyn
->in_ucast_pkts
;
1547 row
->dwInNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1548 row
->dwInDiscards
= dyn
->in_discards
;
1549 row
->dwInErrors
= dyn
->in_errors
;
1550 row
->dwInUnknownProtos
= 0;
1551 row
->dwOutOctets
= dyn
->out_octets
;
1552 row
->dwOutUcastPkts
= dyn
->out_ucast_pkts
;
1553 row
->dwOutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1554 row
->dwOutDiscards
= dyn
->out_discards
;
1555 row
->dwOutErrors
= dyn
->out_errors
;
1557 row
->dwDescrLen
= WideCharToMultiByte( CP_ACP
, 0, stat
->descr
.String
, stat
->descr
.Length
/ sizeof(WCHAR
),
1558 (char *)row
->bDescr
, sizeof(row
->bDescr
) - 1, NULL
, NULL
);
1559 row
->bDescr
[row
->dwDescrLen
] = '\0';
1562 /******************************************************************
1563 * GetIfEntry (IPHLPAPI.@)
1565 * Get information about an interface.
1568 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1569 * Out: interface information
1573 * Failure: error code from winerror.h
1575 DWORD WINAPI
GetIfEntry( MIB_IFROW
*row
)
1577 struct nsi_ndis_ifinfo_rw rw
;
1578 struct nsi_ndis_ifinfo_dynamic dyn
;
1579 struct nsi_ndis_ifinfo_static stat
;
1583 TRACE( "row %p\n", row
);
1584 if (!row
) return ERROR_INVALID_PARAMETER
;
1586 err
= ConvertInterfaceIndexToLuid( row
->dwIndex
, &luid
);
1587 if (err
) return err
;
1589 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1590 &luid
, sizeof(luid
), &rw
, sizeof(rw
),
1591 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1592 if (!err
) if_row_fill( row
, &rw
, &dyn
, &stat
);
1596 static int DWORD_cmp( DWORD a
, DWORD b
)
1598 return a
< b
? -1 : a
> b
? 1 : 0; /* a subtraction would overflow */
1601 static int ifrow_cmp( const void *a
, const void *b
)
1603 const MIB_IFROW
*rowA
= a
, *rowB
= b
;
1604 return DWORD_cmp(rowA
->dwIndex
, rowB
->dwIndex
);
1607 /******************************************************************
1608 * GetIfTable (IPHLPAPI.@)
1610 * Get a table of local interfaces.
1613 * table [Out] buffer for local interfaces table
1614 * size [In/Out] length of output buffer
1615 * sort [In] whether to sort the table
1619 * Failure: error code from winerror.h
1622 * If size is less than required, the function will return
1623 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1625 * If sort is true, the returned table will be sorted by interface index.
1627 DWORD WINAPI
GetIfTable( MIB_IFTABLE
*table
, ULONG
*size
, BOOL sort
)
1629 DWORD i
, count
, needed
, err
;
1631 struct nsi_ndis_ifinfo_rw
*rw
;
1632 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1633 struct nsi_ndis_ifinfo_static
*stat
;
1635 if (!size
) return ERROR_INVALID_PARAMETER
;
1637 /* While this could be implemented on top of GetIfTable2(), it would require
1638 an additional copy of the data */
1639 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1640 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1641 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1642 if (err
) return err
;
1644 needed
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1646 if (!table
|| *size
< needed
)
1649 err
= ERROR_INSUFFICIENT_BUFFER
;
1653 table
->dwNumEntries
= count
;
1654 for (i
= 0; i
< count
; i
++)
1656 MIB_IFROW
*row
= table
->table
+ i
;
1658 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1661 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1664 NsiFreeTable( keys
, rw
, dyn
, stat
);
1668 /******************************************************************
1669 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1671 * Get table of local interfaces.
1672 * Like GetIfTable(), but allocate the returned table from heap.
1675 * table [Out] pointer into which the MIB_IFTABLE is
1676 * allocated and returned.
1677 * sort [In] whether to sort the table
1678 * heap [In] heap from which the table is allocated
1679 * flags [In] flags to HeapAlloc
1682 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1683 * GetIfTable() returns otherwise.
1685 DWORD WINAPI
AllocateAndGetIfTableFromStack( MIB_IFTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
1687 DWORD i
, count
, size
, err
;
1689 struct nsi_ndis_ifinfo_rw
*rw
;
1690 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1691 struct nsi_ndis_ifinfo_static
*stat
;
1693 if (!table
) return ERROR_INVALID_PARAMETER
;
1695 /* While this could be implemented on top of GetIfTable(), it would require
1696 an additional call to retrieve the size */
1697 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1698 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1699 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1700 if (err
) return err
;
1702 size
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1703 *table
= HeapAlloc( heap
, flags
, size
);
1706 err
= ERROR_NOT_ENOUGH_MEMORY
;
1710 (*table
)->dwNumEntries
= count
;
1711 for (i
= 0; i
< count
; i
++)
1713 MIB_IFROW
*row
= (*table
)->table
+ i
;
1715 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1717 if (sort
) qsort( (*table
)->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1720 NsiFreeTable( keys
, rw
, dyn
, stat
);
1724 static void if_row2_fill( MIB_IF_ROW2
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1725 struct nsi_ndis_ifinfo_static
*stat
)
1727 row
->InterfaceIndex
= stat
->if_index
;
1728 row
->InterfaceGuid
= stat
->if_guid
;
1729 if_counted_string_copy( row
->Alias
, ARRAY_SIZE(row
->Alias
), &rw
->alias
);
1730 if_counted_string_copy( row
->Description
, ARRAY_SIZE(row
->Description
), &stat
->descr
);
1731 row
->PhysicalAddressLength
= rw
->phys_addr
.Length
;
1732 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
)) row
->PhysicalAddressLength
= 0;
1733 memcpy( row
->PhysicalAddress
, rw
->phys_addr
.Address
, row
->PhysicalAddressLength
);
1734 memcpy( row
->PermanentPhysicalAddress
, stat
->perm_phys_addr
.Address
, row
->PhysicalAddressLength
);
1735 row
->Mtu
= dyn
->mtu
;
1736 row
->Type
= stat
->type
;
1737 row
->TunnelType
= TUNNEL_TYPE_NONE
; /* fixme */
1738 row
->MediaType
= stat
->media_type
;
1739 row
->PhysicalMediumType
= stat
->phys_medium_type
;
1740 row
->AccessType
= stat
->access_type
;
1741 row
->DirectionType
= NET_IF_DIRECTION_SENDRECEIVE
; /* fixme */
1742 row
->InterfaceAndOperStatusFlags
.HardwareInterface
= stat
->flags
.hw
;
1743 row
->InterfaceAndOperStatusFlags
.FilterInterface
= stat
->flags
.filter
;
1744 row
->InterfaceAndOperStatusFlags
.ConnectorPresent
= !!stat
->conn_present
;
1745 row
->InterfaceAndOperStatusFlags
.NotAuthenticated
= 0; /* fixme */
1746 row
->InterfaceAndOperStatusFlags
.NotMediaConnected
= dyn
->flags
.not_media_conn
;
1747 row
->InterfaceAndOperStatusFlags
.Paused
= 0; /* fixme */
1748 row
->InterfaceAndOperStatusFlags
.LowPower
= 0; /* fixme */
1749 row
->InterfaceAndOperStatusFlags
.EndPointInterface
= 0; /* fixme */
1750 row
->OperStatus
= dyn
->oper_status
;
1751 row
->AdminStatus
= rw
->admin_status
;
1752 row
->MediaConnectState
= dyn
->media_conn_state
;
1753 row
->NetworkGuid
= rw
->network_guid
;
1754 row
->ConnectionType
= stat
->conn_type
;
1755 row
->TransmitLinkSpeed
= dyn
->xmit_speed
;
1756 row
->ReceiveLinkSpeed
= dyn
->rcv_speed
;
1757 row
->InOctets
= dyn
->in_octets
;
1758 row
->InUcastPkts
= dyn
->in_ucast_pkts
;
1759 row
->InNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1760 row
->InDiscards
= dyn
->in_discards
;
1761 row
->InErrors
= dyn
->in_errors
;
1762 row
->InUnknownProtos
= 0; /* fixme */
1763 row
->InUcastOctets
= dyn
->in_ucast_octs
;
1764 row
->InMulticastOctets
= dyn
->in_mcast_octs
;
1765 row
->InBroadcastOctets
= dyn
->in_bcast_octs
;
1766 row
->OutOctets
= dyn
->out_octets
;
1767 row
->OutUcastPkts
= dyn
->out_ucast_pkts
;
1768 row
->OutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1769 row
->OutDiscards
= dyn
->out_discards
;
1770 row
->OutErrors
= dyn
->out_errors
;
1771 row
->OutUcastOctets
= dyn
->out_ucast_octs
;
1772 row
->OutMulticastOctets
= dyn
->out_mcast_octs
;
1773 row
->OutBroadcastOctets
= dyn
->out_bcast_octs
;
1774 row
->OutQLen
= 0; /* fixme */
1777 /******************************************************************
1778 * GetIfEntry2Ex (IPHLPAPI.@)
1780 DWORD WINAPI
GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_ROW2
*row
)
1783 struct nsi_ndis_ifinfo_rw rw
;
1784 struct nsi_ndis_ifinfo_dynamic dyn
;
1785 struct nsi_ndis_ifinfo_static stat
;
1787 TRACE( "(%d, %p)\n", level
, row
);
1789 if (level
!= MibIfTableNormal
) FIXME( "level %u not fully supported\n", level
);
1790 if (!row
) return ERROR_INVALID_PARAMETER
;
1792 if (!row
->InterfaceLuid
.Value
)
1794 if (!row
->InterfaceIndex
) return ERROR_INVALID_PARAMETER
;
1795 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
1796 if (err
) return err
;
1799 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1800 &row
->InterfaceLuid
, sizeof(row
->InterfaceLuid
),
1801 &rw
, sizeof(rw
), &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1802 if (!err
) if_row2_fill( row
, &rw
, &dyn
, &stat
);
1806 /******************************************************************
1807 * GetIfEntry2 (IPHLPAPI.@)
1809 DWORD WINAPI
GetIfEntry2( MIB_IF_ROW2
*row
)
1811 return GetIfEntry2Ex( MibIfTableNormal
, row
);
1814 /******************************************************************
1815 * GetIfTable2Ex (IPHLPAPI.@)
1817 DWORD WINAPI
GetIfTable2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_TABLE2
**table
)
1819 DWORD i
, count
, size
, err
;
1821 struct nsi_ndis_ifinfo_rw
*rw
;
1822 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1823 struct nsi_ndis_ifinfo_static
*stat
;
1825 TRACE( "level %u, table %p\n", level
, table
);
1827 if (!table
|| level
> MibIfTableNormalWithoutStatistics
)
1828 return ERROR_INVALID_PARAMETER
;
1830 if (level
!= MibIfTableNormal
)
1831 FIXME("level %u not fully supported\n", level
);
1833 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1834 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1835 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1836 if (err
) return err
;
1838 size
= FIELD_OFFSET( MIB_IF_TABLE2
, Table
[count
] );
1840 if (!(*table
= heap_alloc_zero( size
)))
1842 err
= ERROR_OUTOFMEMORY
;
1846 (*table
)->NumEntries
= count
;
1847 for (i
= 0; i
< count
; i
++)
1849 MIB_IF_ROW2
*row
= (*table
)->Table
+ i
;
1851 row
->InterfaceLuid
.Value
= keys
[i
].Value
;
1852 if_row2_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1855 NsiFreeTable( keys
, rw
, dyn
, stat
);
1859 /******************************************************************
1860 * GetIfTable2 (IPHLPAPI.@)
1862 DWORD WINAPI
GetIfTable2( MIB_IF_TABLE2
**table
)
1864 TRACE( "table %p\n", table
);
1865 return GetIfTable2Ex( MibIfTableNormal
, table
);
1868 /******************************************************************
1869 * GetInterfaceInfo (IPHLPAPI.@)
1871 * Get a list of network interface adapters.
1874 * pIfTable [Out] buffer for interface adapters
1875 * dwOutBufLen [Out] if buffer is too small, returns required size
1879 * Failure: error code from winerror.h
1882 * MSDN states this should return non-loopback interfaces only.
1884 DWORD WINAPI
GetInterfaceInfo( IP_INTERFACE_INFO
*table
, ULONG
*size
)
1887 struct nsi_ndis_ifinfo_static
*stat
;
1888 DWORD err
, count
, num
= 0, needed
, i
;
1890 TRACE( "table %p, size %p\n", table
, size
);
1891 if (!size
) return ERROR_INVALID_PARAMETER
;
1893 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1894 (void **)&keys
, sizeof(*keys
), NULL
, 0, NULL
, 0,
1895 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1896 if (err
) return err
;
1898 for (i
= 0; i
< count
; i
++)
1900 if (stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
1904 needed
= FIELD_OFFSET(IP_INTERFACE_INFO
, Adapter
[num
]);
1905 if (!table
|| *size
< needed
)
1908 err
= ERROR_INSUFFICIENT_BUFFER
;
1912 table
->NumAdapters
= num
;
1913 for (i
= 0, num
= 0; i
< count
; i
++)
1915 IP_ADAPTER_INDEX_MAP
*row
;
1917 if (stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
1918 row
= table
->Adapter
+ num
++;
1919 row
->Index
= stat
[i
].if_index
;
1920 wcscpy( row
->Name
, device_tcpip
);
1921 ConvertGuidToStringW( &stat
[i
].if_guid
, row
->Name
+ wcslen( device_tcpip
), CHARS_IN_GUID
);
1924 NsiFreeTable( keys
, NULL
, NULL
, stat
);
1928 static int ipaddrrow_cmp( const void *a
, const void *b
)
1930 const MIB_IPADDRROW
*rowA
= a
, *rowB
= b
;
1931 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwAddr
), RtlUlongByteSwap( rowB
->dwAddr
));
1934 /******************************************************************
1935 * GetIpAddrTable (IPHLPAPI.@)
1937 * Get interface-to-IP address mapping table.
1940 * table [Out] buffer for mapping table
1941 * size [In/Out] length of output buffer
1942 * sort [In] whether to sort the table
1946 * Failure: error code from winerror.h
1949 DWORD WINAPI
GetIpAddrTable( MIB_IPADDRTABLE
*table
, ULONG
*size
, BOOL sort
)
1951 DWORD err
, count
, needed
, i
, loopback
, row_num
= 0;
1952 struct nsi_ipv4_unicast_key
*keys
;
1953 struct nsi_ip_unicast_rw
*rw
;
1955 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
1956 if (!size
) return ERROR_INVALID_PARAMETER
;
1958 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&keys
, sizeof(*keys
),
1959 (void **)&rw
, sizeof(*rw
), NULL
, 0, NULL
, 0, &count
, 0 );
1960 if (err
) return err
;
1962 needed
= FIELD_OFFSET( MIB_IPADDRTABLE
, table
[count
] );
1964 if (!table
|| *size
< needed
)
1967 err
= ERROR_INSUFFICIENT_BUFFER
;
1971 table
->dwNumEntries
= count
;
1973 for (loopback
= 0; loopback
< 2; loopback
++) /* Move the loopback addresses to the end */
1975 for (i
= 0; i
< count
; i
++)
1977 MIB_IPADDRROW
*row
= table
->table
+ row_num
;
1979 if (!!loopback
!= (keys
[i
].luid
.Info
.IfType
== MIB_IF_TYPE_LOOPBACK
)) continue;
1981 row
->dwAddr
= keys
[i
].addr
.s_addr
;
1982 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
1983 ConvertLengthToIpv4Mask( rw
[i
].on_link_prefix
, &row
->dwMask
);
1984 row
->dwBCastAddr
= 1;
1985 row
->dwReasmSize
= 0xffff;
1987 row
->wType
= MIB_IPADDR_PRIMARY
;
1992 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPADDRROW
), ipaddrrow_cmp
);
1994 NsiFreeTable( keys
, rw
, NULL
, NULL
);
2000 /******************************************************************
2001 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2003 * Get interface-to-IP address mapping table.
2004 * Like GetIpAddrTable(), but allocate the returned table from heap.
2007 * table [Out] pointer into which the MIB_IPADDRTABLE is
2008 * allocated and returned.
2009 * sort [In] whether to sort the table
2010 * heap [In] heap from which the table is allocated
2011 * flags [In] flags to HeapAlloc
2014 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2016 DWORD err
, size
= FIELD_OFFSET(MIB_IPADDRTABLE
, table
[2]), attempt
;
2018 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2020 for (attempt
= 0; attempt
< 5; attempt
++)
2022 *table
= HeapAlloc( heap
, flags
, size
);
2023 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2025 err
= GetIpAddrTable( *table
, &size
, sort
);
2027 HeapFree( heap
, flags
, *table
);
2028 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2034 static int ipforward_row_cmp( const void *a
, const void *b
)
2036 const MIB_IPFORWARDROW
*rowA
= a
, *rowB
= b
;
2037 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwForwardDest
), RtlUlongByteSwap( rowB
->dwForwardDest
)) ||
2038 DWORD_cmp(rowA
->dwForwardProto
, rowB
->dwForwardProto
) ||
2039 DWORD_cmp(rowA
->dwForwardPolicy
, rowB
->dwForwardPolicy
) ||
2040 DWORD_cmp(RtlUlongByteSwap( rowA
->dwForwardNextHop
), RtlUlongByteSwap( rowB
->dwForwardNextHop
));
2043 /******************************************************************
2044 * GetIpForwardTable (IPHLPAPI.@)
2046 * Get the route table.
2049 * table [Out] buffer for route table
2050 * size [In/Out] length of output buffer
2051 * sort [In] whether to sort the table
2055 * Failure: error code from winerror.h
2057 DWORD WINAPI
GetIpForwardTable( MIB_IPFORWARDTABLE
*table
, ULONG
*size
, BOOL sort
)
2059 DWORD err
, count
, uni_count
, needed
, i
, addr
;
2060 struct nsi_ipv4_forward_key
*keys
;
2061 struct nsi_ip_forward_rw
*rw
;
2062 struct nsi_ipv4_forward_dynamic
*dyn
;
2063 struct nsi_ip_forward_static
*stat
;
2064 struct nsi_ipv4_unicast_key
*uni_keys
= NULL
;
2066 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2067 if (!size
) return ERROR_INVALID_PARAMETER
;
2069 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_FORWARD_TABLE
, (void **)&keys
, sizeof(*keys
),
2070 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2071 (void **)&stat
, sizeof(*stat
), &count
, 0 );
2072 if (err
) return err
;
2074 needed
= FIELD_OFFSET( MIB_IPFORWARDTABLE
, table
[count
] );
2076 if (!table
|| *size
< needed
)
2079 err
= ERROR_INSUFFICIENT_BUFFER
;
2083 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&uni_keys
, sizeof(*uni_keys
),
2084 NULL
, 0, NULL
, 0, NULL
, 0, &uni_count
, 0 );
2087 table
->dwNumEntries
= count
;
2088 for (i
= 0; i
< count
; i
++)
2090 MIB_IPFORWARDROW
*row
= table
->table
+ i
;
2092 row
->dwForwardDest
= keys
[i
].prefix
.s_addr
;
2093 ConvertLengthToIpv4Mask( keys
[i
].prefix_len
, &row
->dwForwardMask
);
2094 row
->dwForwardPolicy
= 0;
2095 row
->dwForwardNextHop
= keys
[i
].next_hop
.s_addr
;
2096 row
->dwForwardType
= row
->dwForwardNextHop
? MIB_IPROUTE_TYPE_INDIRECT
: MIB_IPROUTE_TYPE_DIRECT
;
2097 if (!row
->dwForwardNextHop
) /* find the interface's addr */
2099 for (addr
= 0; addr
< uni_count
; addr
++)
2101 if (uni_keys
[addr
].luid
.Value
== keys
[i
].luid
.Value
)
2103 row
->dwForwardNextHop
= uni_keys
[addr
].addr
.s_addr
;
2108 row
->dwForwardIfIndex
= stat
[i
].if_index
;
2109 row
->dwForwardProto
= rw
[i
].protocol
;
2110 row
->dwForwardAge
= dyn
[i
].age
;
2111 row
->dwForwardNextHopAS
= 0;
2112 row
->dwForwardMetric1
= rw
[i
].metric
; /* FIXME: add interface metric */
2113 row
->dwForwardMetric2
= 0;
2114 row
->dwForwardMetric3
= 0;
2115 row
->dwForwardMetric4
= 0;
2116 row
->dwForwardMetric5
= 0;
2119 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPFORWARDROW
), ipforward_row_cmp
);
2121 NsiFreeTable( uni_keys
, NULL
, NULL
, NULL
);
2122 NsiFreeTable( keys
, rw
, dyn
, stat
);
2127 /******************************************************************
2128 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2130 * Get the route table.
2131 * Like GetIpForwardTable(), but allocate the returned table from heap.
2134 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2135 * allocated and returned.
2136 * sort [In] whether to sort the table
2137 * heap [In] heap from which the table is allocated
2138 * flags [In] flags to HeapAlloc
2141 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2142 * on failure, NO_ERROR on success.
2144 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2146 DWORD err
, size
= FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[2]), attempt
;
2148 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2150 for (attempt
= 0; attempt
< 5; attempt
++)
2152 *table
= HeapAlloc( heap
, flags
, size
);
2153 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2155 err
= GetIpForwardTable( *table
, &size
, sort
);
2157 HeapFree( heap
, flags
, *table
);
2158 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2164 static void forward_row2_fill( MIB_IPFORWARD_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_forward_rw
*rw
,
2165 void *dyn
, struct nsi_ip_forward_static
*stat
)
2167 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
;
2168 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
;
2169 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
;
2170 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
;
2174 row
->InterfaceLuid
= key4
->luid
;
2175 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_family
= fam
;
2176 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_port
= 0;
2177 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_addr
= key4
->prefix
;
2178 memset( &row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
, 0, sizeof(row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
) );
2179 row
->DestinationPrefix
.PrefixLength
= key4
->prefix_len
;
2180 row
->NextHop
.Ipv4
.sin_family
= fam
;
2181 row
->NextHop
.Ipv4
.sin_port
= 0;
2182 row
->NextHop
.Ipv4
.sin_addr
= key4
->next_hop
;
2183 memset( &row
->NextHop
.Ipv4
.sin_zero
, 0, sizeof(row
->NextHop
.Ipv4
.sin_zero
) );
2185 row
->Age
= dyn4
->age
;
2189 row
->InterfaceLuid
= key6
->luid
;
2191 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_family
= fam
;
2192 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_port
= 0;
2193 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_flowinfo
= 0;
2194 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_addr
= key6
->prefix
;
2195 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_scope_id
= 0;
2196 row
->DestinationPrefix
.PrefixLength
= key6
->prefix_len
;
2197 row
->NextHop
.Ipv6
.sin6_family
= fam
;
2198 row
->NextHop
.Ipv6
.sin6_port
= 0;
2199 row
->NextHop
.Ipv6
.sin6_flowinfo
= 0;
2200 row
->NextHop
.Ipv6
.sin6_addr
= key6
->next_hop
;
2201 row
->NextHop
.Ipv6
.sin6_scope_id
= 0;
2203 row
->Age
= dyn6
->age
;
2206 row
->InterfaceIndex
= stat
->if_index
;
2208 row
->SitePrefixLength
= rw
->site_prefix_len
;
2209 row
->ValidLifetime
= rw
->valid_lifetime
;
2210 row
->PreferredLifetime
= rw
->preferred_lifetime
;
2211 row
->Metric
= rw
->metric
;
2212 row
->Protocol
= rw
->protocol
;
2213 row
->Loopback
= rw
->loopback
;
2214 row
->AutoconfigureAddress
= rw
->autoconf
;
2215 row
->Publish
= rw
->publish
;
2216 row
->Immortal
= rw
->immortal
;
2218 row
->Origin
= stat
->origin
;
2221 /******************************************************************
2222 * GetIpForwardTable2 (IPHLPAPI.@)
2224 DWORD WINAPI
GetIpForwardTable2( ADDRESS_FAMILY family
, MIB_IPFORWARD_TABLE2
**table
)
2226 void *key
[2] = { NULL
, NULL
};
2227 struct nsi_ip_forward_rw
*rw
[2] = { NULL
, NULL
};
2228 void *dyn
[2] = { NULL
, NULL
};
2229 struct nsi_ip_forward_static
*stat
[2] = { NULL
, NULL
};
2230 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
2231 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_forward_key
), sizeof(struct nsi_ipv6_forward_key
) };
2232 static const DWORD dyn_size
[2] = { sizeof(struct nsi_ipv4_forward_dynamic
), sizeof(struct nsi_ipv6_forward_dynamic
) };
2233 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2235 TRACE( "%u, %p\n", family
, table
);
2237 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
2238 return ERROR_INVALID_PARAMETER
;
2240 for (i
= 0; i
< 2; i
++)
2242 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
2244 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_FORWARD_TABLE
, key
+ i
, key_size
[i
],
2245 (void **)rw
+ i
, sizeof(**rw
), dyn
+ i
, dyn_size
[i
],
2246 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
2247 if (err
) count
[i
] = 0;
2250 size
= FIELD_OFFSET(MIB_IPFORWARD_TABLE2
, Table
[ count
[0] + count
[1] ]);
2251 *table
= heap_alloc( size
);
2254 err
= ERROR_NOT_ENOUGH_MEMORY
;
2258 (*table
)->NumEntries
= count
[0] + count
[1];
2259 for (i
= 0; i
< count
[0]; i
++)
2261 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ i
;
2262 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
[0];
2263 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
[0];
2265 forward_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn4
+ i
, stat
[0] + i
);
2268 for (i
= 0; i
< count
[1]; i
++)
2270 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2271 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
[1];
2272 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
[1];
2274 forward_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn6
+ i
, stat
[1] + i
);
2278 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
2282 static int ipnetrow_cmp( const void *a
, const void *b
)
2284 const MIB_IPNETROW
*rowA
= a
, *rowB
= b
;
2286 if (rowA
->dwIndex
!= rowB
->dwIndex
) return DWORD_cmp( rowA
->dwIndex
, rowB
->dwIndex
);
2288 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwAddr
), RtlUlongByteSwap( rowB
->dwAddr
));
2291 /******************************************************************
2292 * GetIpNetTable (IPHLPAPI.@)
2294 * Get the IP-to-physical address mapping table.
2297 * table [Out] buffer for mapping table
2298 * size [In/Out] length of output buffer
2299 * sort [In] whether to sort the table
2303 * Failure: error code from winerror.h
2306 DWORD WINAPI
GetIpNetTable( MIB_IPNETTABLE
*table
, ULONG
*size
, BOOL sort
)
2308 DWORD err
, count
, needed
, i
;
2309 struct nsi_ipv4_neighbour_key
*keys
;
2310 struct nsi_ip_neighbour_rw
*rw
;
2311 struct nsi_ip_neighbour_dynamic
*dyn
;
2313 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2315 if (!size
) return ERROR_INVALID_PARAMETER
;
2317 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_NEIGHBOUR_TABLE
, (void **)&keys
, sizeof(*keys
),
2318 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2319 NULL
, 0, &count
, 0 );
2320 if (err
) return err
;
2322 needed
= FIELD_OFFSET( MIB_IPNETTABLE
, table
[count
] );
2324 if (!table
|| *size
< needed
)
2327 err
= ERROR_INSUFFICIENT_BUFFER
;
2331 table
->dwNumEntries
= count
;
2335 err
= ERROR_NO_DATA
;
2339 for (i
= 0; i
< count
; i
++)
2341 MIB_IPNETROW
*row
= table
->table
+ i
;
2343 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
2344 row
->dwPhysAddrLen
= dyn
[i
].phys_addr_len
;
2345 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
2346 memcpy( row
->bPhysAddr
, rw
[i
].phys_addr
, row
->dwPhysAddrLen
);
2347 memset( row
->bPhysAddr
+ row
->dwPhysAddrLen
, 0,
2348 sizeof(row
->bPhysAddr
) - row
->dwPhysAddrLen
);
2349 row
->dwAddr
= keys
[i
].addr
.s_addr
;
2351 switch (dyn
[i
].state
)
2353 case NlnsUnreachable
:
2354 case NlnsIncomplete
:
2355 row
->Type
= MIB_IPNET_TYPE_INVALID
;
2361 row
->Type
= MIB_IPNET_TYPE_DYNAMIC
;
2364 row
->Type
= MIB_IPNET_TYPE_STATIC
;
2367 row
->Type
= MIB_IPNET_TYPE_OTHER
;
2371 if (sort
) qsort( table
->table
, table
->dwNumEntries
, sizeof(*table
->table
), ipnetrow_cmp
);
2374 NsiFreeTable( keys
, rw
, dyn
, NULL
);
2378 /******************************************************************
2379 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2381 DWORD WINAPI
AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2383 DWORD err
, size
= FIELD_OFFSET(MIB_IPNETTABLE
, table
[2]), attempt
;
2385 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
2387 for (attempt
= 0; attempt
< 5; attempt
++)
2389 *table
= HeapAlloc( heap
, flags
, size
);
2390 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2392 err
= GetIpNetTable( *table
, &size
, sort
);
2394 HeapFree( heap
, flags
, *table
);
2395 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2401 static void ipnet_row2_fill( MIB_IPNET_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_neighbour_rw
*rw
,
2402 struct nsi_ip_neighbour_dynamic
*dyn
)
2404 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
;
2405 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
;
2409 row
->Address
.Ipv4
.sin_family
= fam
;
2410 row
->Address
.Ipv4
.sin_port
= 0;
2411 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
2412 memset( &row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
2413 row
->InterfaceLuid
= key4
->luid
;
2417 row
->Address
.Ipv6
.sin6_family
= fam
;
2418 row
->Address
.Ipv6
.sin6_port
= 0;
2419 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
2420 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
2421 row
->Address
.Ipv6
.sin6_scope_id
= 0;
2422 row
->InterfaceLuid
= key6
->luid
;
2425 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
2427 row
->PhysicalAddressLength
= dyn
->phys_addr_len
;
2428 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
))
2429 row
->PhysicalAddressLength
= 0;
2430 memcpy( row
->PhysicalAddress
, rw
->phys_addr
, row
->PhysicalAddressLength
);
2431 memset( row
->PhysicalAddress
+ row
->PhysicalAddressLength
, 0,
2432 sizeof(row
->PhysicalAddress
) - row
->PhysicalAddressLength
);
2433 row
->State
= dyn
->state
;
2435 row
->IsRouter
= dyn
->flags
.is_router
;
2436 row
->IsUnreachable
= dyn
->flags
.is_unreachable
;
2437 row
->ReachabilityTime
.LastReachable
= dyn
->time
;
2440 /******************************************************************
2441 * GetIpNetTable2 (IPHLPAPI.@)
2443 DWORD WINAPI
GetIpNetTable2( ADDRESS_FAMILY family
, MIB_IPNET_TABLE2
**table
)
2445 void *key
[2] = { NULL
, NULL
};
2446 struct nsi_ip_neighbour_rw
*rw
[2] = { NULL
, NULL
};
2447 struct nsi_ip_neighbour_dynamic
*dyn
[2] = { NULL
, NULL
};
2448 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
2449 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_neighbour_key
), sizeof(struct nsi_ipv6_neighbour_key
) };
2450 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2452 TRACE( "%u, %p\n", family
, table
);
2454 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
2455 return ERROR_INVALID_PARAMETER
;
2457 for (i
= 0; i
< 2; i
++)
2459 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
2461 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_NEIGHBOUR_TABLE
, key
+ i
, key_size
[i
],
2462 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
2463 NULL
, 0, count
+ i
, 0 );
2464 if (err
) count
[i
] = 0;
2467 size
= FIELD_OFFSET(MIB_IPNET_TABLE2
, Table
[ count
[0] + count
[1] ]);
2468 *table
= heap_alloc( size
);
2471 err
= ERROR_NOT_ENOUGH_MEMORY
;
2475 (*table
)->NumEntries
= count
[0] + count
[1];
2476 for (i
= 0; i
< count
[0]; i
++)
2478 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ i
;
2479 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
[0];
2481 ipnet_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn
[0] + i
);
2484 for (i
= 0; i
< count
[1]; i
++)
2486 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2487 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
[1];
2489 ipnet_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn
[1] + i
);
2493 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], NULL
);
2497 /******************************************************************
2498 * GetIpStatistics (IPHLPAPI.@)
2500 * Get the IP statistics for the local computer.
2503 * stats [Out] buffer for IP statistics
2507 * Failure: error code from winerror.h
2509 DWORD WINAPI
GetIpStatistics( MIB_IPSTATS
*stats
)
2511 return GetIpStatisticsEx( stats
, AF_INET
);
2514 /******************************************************************
2515 * GetIpStatisticsEx (IPHLPAPI.@)
2517 * Get the IPv4 and IPv6 statistics for the local computer.
2520 * stats [Out] buffer for IP statistics
2521 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2525 * Failure: error code from winerror.h
2527 DWORD WINAPI
GetIpStatisticsEx( MIB_IPSTATS
*stats
, DWORD family
)
2529 struct nsi_ip_ipstats_dynamic dyn
;
2530 struct nsi_ip_ipstats_static stat
;
2531 struct nsi_ip_cmpt_rw cmpt_rw
;
2532 struct nsi_ip_cmpt_dynamic cmpt_dyn
;
2533 const NPI_MODULEID
*mod
;
2534 DWORD err
, cmpt
= 1;
2536 TRACE( "%p %ld\n", stats
, family
);
2538 if (!stats
) return ERROR_INVALID_PARAMETER
;
2539 mod
= ip_module_id( family
);
2540 if (!mod
) return ERROR_INVALID_PARAMETER
;
2542 memset( stats
, 0, sizeof(*stats
) );
2544 err
= NsiGetAllParameters( 1, mod
, NSI_IP_IPSTATS_TABLE
, NULL
, 0, NULL
, 0,
2545 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2546 if (err
) return err
;
2548 err
= NsiGetAllParameters( 1, mod
, NSI_IP_COMPARTMENT_TABLE
, &cmpt
, sizeof(cmpt
), &cmpt_rw
, sizeof(cmpt_rw
),
2549 &cmpt_dyn
, sizeof(cmpt_dyn
), NULL
, 0 );
2550 if (err
) return err
;
2552 stats
->Forwarding
= cmpt_rw
.not_forwarding
+ 1;
2553 stats
->dwDefaultTTL
= cmpt_rw
.default_ttl
;
2554 stats
->dwInReceives
= dyn
.in_recv
;
2555 stats
->dwInHdrErrors
= dyn
.in_hdr_errs
;
2556 stats
->dwInAddrErrors
= dyn
.in_addr_errs
;
2557 stats
->dwForwDatagrams
= dyn
.fwd_dgrams
;
2558 stats
->dwInUnknownProtos
= dyn
.in_unk_protos
;
2559 stats
->dwInDiscards
= dyn
.in_discards
;
2560 stats
->dwInDelivers
= dyn
.in_delivers
;
2561 stats
->dwOutRequests
= dyn
.out_reqs
;
2562 stats
->dwRoutingDiscards
= dyn
.routing_discards
;
2563 stats
->dwOutDiscards
= dyn
.out_discards
;
2564 stats
->dwOutNoRoutes
= dyn
.out_no_routes
;
2565 stats
->dwReasmTimeout
= stat
.reasm_timeout
;
2566 stats
->dwReasmReqds
= dyn
.reasm_reqds
;
2567 stats
->dwReasmOks
= dyn
.reasm_oks
;
2568 stats
->dwReasmFails
= dyn
.reasm_fails
;
2569 stats
->dwFragOks
= dyn
.frag_oks
;
2570 stats
->dwFragFails
= dyn
.frag_fails
;
2571 stats
->dwFragCreates
= dyn
.frag_creates
;
2572 stats
->dwNumIf
= cmpt_dyn
.num_ifs
;
2573 stats
->dwNumAddr
= cmpt_dyn
.num_addrs
;
2574 stats
->dwNumRoutes
= cmpt_dyn
.num_routes
;
2579 /* Gets the DNS server list into the list beginning at list. Assumes that
2580 * a single server address may be placed at list if *len is at least
2581 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2582 * and assumes that all remaining DNS servers are contiguously located
2583 * beginning at second. On input, *len is assumed to be the total number
2584 * of bytes available for all DNS servers, and is ignored if list is NULL.
2585 * On return, *len is set to the total number of bytes required for all DNS
2587 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2588 * ERROR_SUCCESS otherwise.
2590 static DWORD
get_dns_server_list( const NET_LUID
*luid
, IP_ADDR_STRING
*list
, IP_ADDR_STRING
*second
, DWORD
*len
)
2592 char buf
[FIELD_OFFSET(IP4_ARRAY
, AddrArray
[3])];
2593 IP4_ARRAY
*servers
= (IP4_ARRAY
*)buf
;
2594 DWORD needed
, num
, err
, i
, array_len
= sizeof(buf
);
2595 IP_ADDR_STRING
*ptr
;
2597 if (luid
&& luid
->Info
.IfType
== MIB_IF_TYPE_LOOPBACK
) return ERROR_NO_DATA
;
2601 err
= DnsQueryConfig( DnsConfigDnsServerList
, 0, NULL
, NULL
, servers
, &array_len
);
2602 if (err
!= ERROR_SUCCESS
&& err
!= ERROR_MORE_DATA
) goto err
;
2603 num
= (array_len
- FIELD_OFFSET(IP4_ARRAY
, AddrArray
[0])) / sizeof(IP4_ADDRESS
);
2604 needed
= num
* sizeof(IP_ADDR_STRING
);
2605 if (!list
|| *len
< needed
)
2608 err
= ERROR_BUFFER_OVERFLOW
;
2613 if ((char *)servers
!= buf
) heap_free( servers
);
2614 servers
= heap_alloc( array_len
);
2617 err
= ERROR_NOT_ENOUGH_MEMORY
;
2624 for (i
= 0, ptr
= list
; i
< num
; i
++, ptr
= ptr
->Next
)
2626 RtlIpv4AddressToStringA( (IN_ADDR
*)&servers
->AddrArray
[i
], ptr
->IpAddress
.String
);
2627 if (i
== num
- 1) ptr
->Next
= NULL
;
2628 else if (i
== 0) ptr
->Next
= second
;
2629 else ptr
->Next
= ptr
+ 1;
2633 if ((char *)servers
!= buf
) heap_free( servers
);
2637 /******************************************************************
2638 * GetNetworkParams (IPHLPAPI.@)
2640 * Get the network parameters for the local computer.
2643 * info [Out] buffer for network parameters
2644 * size [In/Out] length of output buffer
2648 * Failure: error code from winerror.h
2651 * If size is less than required, the function will return
2652 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2655 DWORD WINAPI
GetNetworkParams( FIXED_INFO
*info
, ULONG
*size
)
2657 DWORD needed
= sizeof(*info
), dns_size
, err
;
2658 MIB_IPSTATS ip_stats
;
2661 TRACE( "info %p, size %p\n", info
, size
);
2662 if (!size
) return ERROR_INVALID_PARAMETER
;
2664 if (get_dns_server_list( NULL
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2665 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2666 if (!info
|| *size
< needed
)
2669 return ERROR_BUFFER_OVERFLOW
;
2673 memset( info
, 0, needed
);
2674 needed
= sizeof(info
->HostName
);
2675 GetComputerNameExA( ComputerNameDnsHostname
, info
->HostName
, &needed
);
2676 needed
= sizeof(info
->DomainName
);
2677 GetComputerNameExA( ComputerNameDnsDomain
, info
->DomainName
, &needed
);
2678 get_dns_server_list( NULL
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2679 info
->CurrentDnsServer
= &info
->DnsServerList
;
2680 info
->NodeType
= HYBRID_NODETYPE
;
2681 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2682 0, KEY_READ
, &key
);
2684 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2685 0, KEY_READ
, &key
);
2688 needed
= sizeof(info
->ScopeId
);
2689 RegQueryValueExA( key
, "ScopeID", NULL
, NULL
, (BYTE
*)info
->ScopeId
, &needed
);
2693 if (!GetIpStatistics( &ip_stats
))
2694 info
->EnableRouting
= (ip_stats
.Forwarding
== MIB_IP_FORWARDING
);
2696 return ERROR_SUCCESS
;
2700 /******************************************************************
2701 * GetNumberOfInterfaces (IPHLPAPI.@)
2703 * Get the number of interfaces.
2706 * pdwNumIf [Out] number of interfaces
2709 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2711 DWORD WINAPI
GetNumberOfInterfaces( DWORD
*count
)
2715 TRACE( "count %p\n", count
);
2716 if (!count
) return ERROR_INVALID_PARAMETER
;
2718 err
= NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, NULL
, 0,
2719 NULL
, 0, NULL
, 0, NULL
, 0, &num
);
2720 *count
= err
? 0 : num
;
2724 /******************************************************************
2725 * GetPerAdapterInfo (IPHLPAPI.@)
2727 * Get information about an adapter corresponding to an interface.
2730 * IfIndex [In] interface info
2731 * pPerAdapterInfo [Out] buffer for per adapter info
2732 * pOutBufLen [In/Out] length of output buffer
2736 * Failure: error code from winerror.h
2738 DWORD WINAPI
GetPerAdapterInfo( ULONG index
, IP_PER_ADAPTER_INFO
*info
, ULONG
*size
)
2740 DWORD needed
= sizeof(*info
), dns_size
;
2743 TRACE( "(index %ld, info %p, size %p)\n", index
, info
, size
);
2745 if (!size
) return ERROR_INVALID_PARAMETER
;
2746 if (ConvertInterfaceIndexToLuid( index
, &luid
)) return ERROR_NO_DATA
;
2748 if (get_dns_server_list( &luid
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2749 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2751 if (!info
|| *size
< needed
)
2754 return ERROR_BUFFER_OVERFLOW
;
2757 memset( info
, 0, needed
);
2758 get_dns_server_list( &luid
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2759 info
->CurrentDnsServer
= &info
->DnsServerList
;
2761 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2762 return ERROR_SUCCESS
;
2766 /******************************************************************
2767 * GetRTTAndHopCount (IPHLPAPI.@)
2769 * Get round-trip time (RTT) and hop count.
2773 * DestIpAddress [In] destination address to get the info for
2774 * HopCount [Out] retrieved hop count
2775 * MaxHops [In] maximum hops to search for the destination
2776 * RTT [Out] RTT in milliseconds
2783 * Stub, returns FALSE.
2785 BOOL WINAPI
GetRTTAndHopCount(IPAddr DestIpAddress
, PULONG HopCount
, ULONG MaxHops
, PULONG RTT
)
2787 FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
2788 DestIpAddress
, HopCount
, MaxHops
, RTT
);
2792 /******************************************************************
2793 * GetTcpStatistics (IPHLPAPI.@)
2795 * Get the TCP statistics for the local computer.
2798 * stats [Out] buffer for TCP statistics
2802 * Failure: error code from winerror.h
2804 DWORD WINAPI
GetTcpStatistics( MIB_TCPSTATS
*stats
)
2806 return GetTcpStatisticsEx( stats
, AF_INET
);
2809 /******************************************************************
2810 * GetTcpStatisticsEx (IPHLPAPI.@)
2812 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2815 * stats [Out] buffer for TCP statistics
2816 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2820 * Failure: error code from winerror.h
2822 DWORD WINAPI
GetTcpStatisticsEx( MIB_TCPSTATS
*stats
, DWORD family
)
2824 struct nsi_tcp_stats_dynamic dyn
;
2825 struct nsi_tcp_stats_static stat
;
2826 USHORT key
= (USHORT
)family
;
2829 if (!stats
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
2830 memset( stats
, 0, sizeof(*stats
) );
2832 err
= NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID
, NSI_TCP_STATS_TABLE
, &key
, sizeof(key
), NULL
, 0,
2833 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2834 if (err
) return err
;
2836 stats
->RtoAlgorithm
= stat
.rto_algo
;
2837 stats
->dwRtoMin
= stat
.rto_min
;
2838 stats
->dwRtoMax
= stat
.rto_max
;
2839 stats
->dwMaxConn
= stat
.max_conns
;
2840 stats
->dwActiveOpens
= dyn
.active_opens
;
2841 stats
->dwPassiveOpens
= dyn
.passive_opens
;
2842 stats
->dwAttemptFails
= dyn
.attempt_fails
;
2843 stats
->dwEstabResets
= dyn
.est_rsts
;
2844 stats
->dwCurrEstab
= dyn
.cur_est
;
2845 stats
->dwInSegs
= (DWORD
)dyn
.in_segs
;
2846 stats
->dwOutSegs
= (DWORD
)dyn
.out_segs
;
2847 stats
->dwRetransSegs
= dyn
.retrans_segs
;
2848 stats
->dwInErrs
= dyn
.in_errs
;
2849 stats
->dwOutRsts
= dyn
.out_rsts
;
2850 stats
->dwNumConns
= dyn
.num_conns
;
2855 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2857 static DWORD
tcp_table_id( ULONG table_class
)
2859 switch (table_class
)
2861 case TCP_TABLE_BASIC_LISTENER
:
2862 case TCP_TABLE_OWNER_PID_LISTENER
:
2863 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2864 return NSI_TCP_LISTEN_TABLE
;
2866 case TCP_TABLE_BASIC_CONNECTIONS
:
2867 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2868 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2869 return NSI_TCP_ESTAB_TABLE
;
2871 case TCP_TABLE_BASIC_ALL
:
2872 case TCP_TABLE_OWNER_PID_ALL
:
2873 case TCP_TABLE_OWNER_MODULE_ALL
:
2875 return NSI_TCP_ALL_TABLE
;
2878 ERR( "unhandled class %lu\n", table_class
);
2883 static DWORD
tcp_table_size( ULONG family
, ULONG table_class
, DWORD row_count
, DWORD
*row_size
)
2885 switch (table_class
)
2887 case TCP_TABLE_BASIC_LISTENER
:
2888 case TCP_TABLE_BASIC_CONNECTIONS
:
2889 case TCP_TABLE_BASIC_ALL
:
2890 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW
) : sizeof(MIB_TCP6ROW
);
2891 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE
, table
[row_count
]) :
2892 FIELD_OFFSET(MIB_TCP6TABLE
, table
[row_count
]);
2894 case TCP_TABLE_OWNER_PID_LISTENER
:
2895 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2896 case TCP_TABLE_OWNER_PID_ALL
:
2897 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW_OWNER_PID
) : sizeof(MIB_TCP6ROW_OWNER_PID
);
2898 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID
, table
[row_count
]) :
2899 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID
, table
[row_count
]);
2901 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2902 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2903 case TCP_TABLE_OWNER_MODULE_ALL
:
2904 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW_OWNER_MODULE
) : sizeof(MIB_TCP6ROW_OWNER_MODULE
);
2905 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE
, table
[row_count
]) :
2906 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE
, table
[row_count
]);
2909 *row_size
= (family
== AF_INET
) ? sizeof(MIB_TCPROW2
) : sizeof(MIB_TCP6ROW2
);
2910 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE2
, table
[row_count
]) :
2911 FIELD_OFFSET(MIB_TCP6TABLE2
, table
[row_count
]);
2914 ERR( "unhandled class %lu\n", table_class
);
2919 static void tcp_row_fill( void *table
, DWORD num
, ULONG family
, ULONG table_class
,
2920 struct nsi_tcp_conn_key
*key
, struct nsi_tcp_conn_dynamic
*dyn
,
2921 struct nsi_tcp_conn_static
*stat
)
2923 if (family
== AF_INET
)
2925 switch (table_class
)
2927 case TCP_TABLE_BASIC_LISTENER
:
2928 case TCP_TABLE_BASIC_CONNECTIONS
:
2929 case TCP_TABLE_BASIC_ALL
:
2931 MIB_TCPROW
*row
= ((MIB_TCPTABLE
*)table
)->table
+ num
;
2932 row
->dwState
= dyn
->state
;
2933 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2934 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2935 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2936 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2939 case TCP_TABLE_OWNER_PID_LISTENER
:
2940 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2941 case TCP_TABLE_OWNER_PID_ALL
:
2943 MIB_TCPROW_OWNER_PID
*row
= ((MIB_TCPTABLE_OWNER_PID
*)table
)->table
+ num
;
2944 row
->dwState
= dyn
->state
;
2945 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2946 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2947 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2948 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2949 row
->dwOwningPid
= stat
->pid
;
2952 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2953 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2954 case TCP_TABLE_OWNER_MODULE_ALL
:
2956 MIB_TCPROW_OWNER_MODULE
*row
= ((MIB_TCPTABLE_OWNER_MODULE
*)table
)->table
+ num
;
2957 row
->dwState
= dyn
->state
;
2958 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2959 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2960 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2961 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2962 row
->dwOwningPid
= stat
->pid
;
2963 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
2964 row
->OwningModuleInfo
[0] = stat
->mod_info
;
2965 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
2970 MIB_TCPROW2
*row
= ((MIB_TCPTABLE2
*)table
)->table
+ num
;
2971 row
->dwState
= dyn
->state
;
2972 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
2973 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2974 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.s_addr
;
2975 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2976 row
->dwOwningPid
= stat
->pid
;
2977 row
->dwOffloadState
= 0; /* FIXME */
2981 ERR( "Unknown class %ld\n", table_class
);
2987 switch (table_class
)
2989 case TCP_TABLE_BASIC_LISTENER
:
2990 case TCP_TABLE_BASIC_CONNECTIONS
:
2991 case TCP_TABLE_BASIC_ALL
:
2993 MIB_TCP6ROW
*row
= ((MIB_TCP6TABLE
*)table
)->table
+ num
;
2994 row
->State
= dyn
->state
;
2995 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
2996 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
2997 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
2998 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
2999 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3000 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3003 case TCP_TABLE_OWNER_PID_LISTENER
:
3004 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
3005 case TCP_TABLE_OWNER_PID_ALL
:
3007 MIB_TCP6ROW_OWNER_PID
*row
= ((MIB_TCP6TABLE_OWNER_PID
*)table
)->table
+ num
;
3008 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3009 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3010 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3011 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3012 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3013 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3014 row
->dwState
= dyn
->state
;
3015 row
->dwOwningPid
= stat
->pid
;
3018 case TCP_TABLE_OWNER_MODULE_LISTENER
:
3019 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
3020 case TCP_TABLE_OWNER_MODULE_ALL
:
3022 MIB_TCP6ROW_OWNER_MODULE
*row
= ((MIB_TCP6TABLE_OWNER_MODULE
*)table
)->table
+ num
;
3023 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3024 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3025 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3026 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3027 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3028 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3029 row
->dwState
= dyn
->state
;
3030 row
->dwOwningPid
= stat
->pid
;
3031 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3032 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3033 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3038 MIB_TCP6ROW2
*row
= ((MIB_TCP6TABLE2
*)table
)->table
+ num
;
3039 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
3040 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3041 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3042 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
3043 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3044 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3045 row
->State
= dyn
->state
;
3046 row
->dwOwningPid
= stat
->pid
;
3047 row
->dwOffloadState
= 0; /* FIXME */
3051 ERR( "Unknown class %ld\n", table_class
);
3055 ERR( "Unknown family %ld\n", family
);
3058 static int tcp_row_cmp( const void *a
, const void *b
)
3060 const MIB_TCPROW
*rowA
= a
, *rowB
= b
;
3063 if ((ret
= DWORD_cmp(RtlUshortByteSwap( rowA
->dwLocalAddr
), RtlUshortByteSwap( rowB
->dwLocalAddr
))) != 0) return ret
;
3064 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3065 if ((ret
= DWORD_cmp(RtlUshortByteSwap( rowA
->dwRemoteAddr
), RtlUshortByteSwap( rowB
->dwRemoteAddr
))) != 0) return ret
;
3066 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3069 static int tcp6_row_basic_cmp( const void *a
, const void *b
)
3071 const MIB_TCP6ROW
*rowA
= a
;
3072 const MIB_TCP6ROW
*rowB
= b
;
3075 if ((ret
= memcmp( &rowA
->LocalAddr
, &rowB
->LocalAddr
, sizeof(rowA
->LocalAddr
) )) != 0) return ret
;
3076 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3077 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3078 if ((ret
= memcmp( &rowA
->RemoteAddr
, &rowB
->RemoteAddr
, sizeof(rowA
->RemoteAddr
) )) != 0) return ret
;
3079 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3080 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3083 static int tcp6_row_owner_cmp( const void *a
, const void *b
)
3085 const MIB_TCP6ROW_OWNER_PID
*rowA
= a
;
3086 const MIB_TCP6ROW_OWNER_PID
*rowB
= b
;
3089 if ((ret
= memcmp( &rowA
->ucLocalAddr
, &rowB
->ucLocalAddr
, sizeof(rowA
->ucLocalAddr
) )) != 0) return ret
;
3090 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3091 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3092 if ((ret
= memcmp( &rowA
->ucRemoteAddr
, &rowB
->ucRemoteAddr
, sizeof(rowA
->ucRemoteAddr
) )) != 0) return ret
;
3093 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3094 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3097 static BOOL
tcp_table_needs_pids( ULONG table_class
)
3099 switch (table_class
)
3101 case TCP_TABLE_BASIC_LISTENER
:
3102 case TCP_TABLE_BASIC_CONNECTIONS
:
3103 case TCP_TABLE_BASIC_ALL
:
3110 /*************************************************************************************
3111 * get_extended_tcp_table
3113 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3114 * corresponding to GetTcp(6)Table2()
3116 static DWORD
get_extended_tcp_table( void *table
, DWORD
*size
, BOOL sort
, ULONG family
, ULONG table_class
)
3118 DWORD err
, count
, needed
, i
, num
= 0, row_size
= 0;
3119 struct nsi_tcp_conn_key
*key
;
3120 struct nsi_tcp_conn_dynamic
*dyn
;
3121 struct nsi_tcp_conn_static
*stat
= NULL
;
3123 if (!size
) return ERROR_INVALID_PARAMETER
;
3125 if (tcp_table_needs_pids( table_class
))
3126 err
= NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID
, tcp_table_id( table_class
), (void **)&key
, sizeof(*key
),
3127 NULL
, 0, (void **)&dyn
, sizeof(*dyn
),
3128 (void **)&stat
, sizeof(*stat
), &count
, 0 );
3129 else /* Don't retrieve the static data if not required as this is expensive to compute */
3130 err
= NsiAllocateAndGetTable( 1, &NPI_MS_TCP_MODULEID
, tcp_table_id( table_class
), (void **)&key
, sizeof(*key
),
3131 NULL
, 0, (void **)&dyn
, sizeof(*dyn
),
3132 NULL
, 0, &count
, 0 );
3134 if (err
) return err
;
3136 for (i
= 0; i
< count
; i
++)
3137 if (key
[i
].local
.si_family
== family
)
3140 needed
= tcp_table_size( family
, table_class
, num
, &row_size
);
3141 if (!table
|| *size
< needed
)
3144 err
= ERROR_INSUFFICIENT_BUFFER
;
3149 *(DWORD
*)table
= num
;
3151 for (i
= 0; i
< count
; i
++)
3153 if (key
[i
].local
.si_family
!= family
) continue;
3154 tcp_row_fill( table
, num
++, family
, table_class
, key
+ i
, dyn
+ i
, stat
+ i
);
3160 int (*fn
)(const void *, const void *);
3163 if (family
== AF_INET
) fn
= tcp_row_cmp
;
3164 else if (row_size
== sizeof(MIB_TCP6ROW
)) fn
= tcp6_row_basic_cmp
;
3165 else fn
= tcp6_row_owner_cmp
;
3167 offset
= tcp_table_size( family
, table_class
, 0, &row_size
);
3168 qsort( (BYTE
*)table
+ offset
, num
, row_size
, fn
);
3171 NsiFreeTable( key
, NULL
, dyn
, stat
);
3175 /******************************************************************
3176 * GetExtendedTcpTable (IPHLPAPI.@)
3178 DWORD WINAPI
GetExtendedTcpTable( void *table
, DWORD
*size
, BOOL sort
, ULONG family
,
3179 TCP_TABLE_CLASS table_class
, ULONG reserved
)
3181 TRACE( "table %p, size %p, sort %d, family %lu, class %u, reserved %lu\n",
3182 table
, size
, sort
, family
, table_class
, reserved
);
3184 if (!ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3185 return get_extended_tcp_table( table
, size
, sort
, family
, table_class
);
3188 /******************************************************************
3189 * GetTcpTable (IPHLPAPI.@)
3191 * Get the table of active TCP connections.
3194 * table [Out] buffer for TCP connections table
3195 * size [In/Out] length of output buffer
3196 * sort [In] whether to order the table
3200 * Failure: error code from winerror.h
3203 * If size is less than required, the function will return
3204 * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
3205 * the required byte size.
3206 * If sort is true, the returned table will be sorted, first by
3207 * local address and port number, then by remote address and port
3210 DWORD WINAPI
GetTcpTable( MIB_TCPTABLE
*table
, DWORD
*size
, BOOL sort
)
3212 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3213 return get_extended_tcp_table( table
, size
, sort
, AF_INET
, TCP_TABLE_BASIC_ALL
);
3216 /******************************************************************
3217 * GetTcp6Table (IPHLPAPI.@)
3219 ULONG WINAPI
GetTcp6Table( MIB_TCP6TABLE
*table
, ULONG
*size
, BOOL sort
)
3221 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3222 return get_extended_tcp_table( table
, size
, sort
, AF_INET6
, TCP_TABLE_BASIC_ALL
);
3225 /******************************************************************
3226 * GetTcpTable2 (IPHLPAPI.@)
3228 ULONG WINAPI
GetTcpTable2( MIB_TCPTABLE2
*table
, ULONG
*size
, BOOL sort
)
3230 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3231 return get_extended_tcp_table( table
, size
, sort
, AF_INET
, TCP_TABLE2
);
3234 /******************************************************************
3235 * GetTcp6Table2 (IPHLPAPI.@)
3237 ULONG WINAPI
GetTcp6Table2( MIB_TCP6TABLE2
*table
, ULONG
*size
, BOOL sort
)
3239 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3240 return get_extended_tcp_table( table
, size
, sort
, AF_INET6
, TCP_TABLE2
);
3243 static DWORD
allocate_tcp_table( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
,
3244 ULONG family
, ULONG table_class
)
3246 DWORD err
, size
= 0x100, attempt
;
3248 for (attempt
= 0; attempt
< 5; attempt
++)
3250 *table
= HeapAlloc( heap
, flags
, size
);
3251 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
3252 err
= get_extended_tcp_table( *table
, &size
, sort
, family
, table_class
);
3254 HeapFree( heap
, flags
, *table
);
3256 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
3261 /******************************************************************
3262 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
3264 DWORD WINAPI
AllocateAndGetTcpTableFromStack( MIB_TCPTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
3266 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
3268 if (!table
) return ERROR_INVALID_PARAMETER
;
3270 return allocate_tcp_table( (void **)table
, sort
, heap
, flags
, AF_INET
, TCP_TABLE_BASIC_ALL
);
3273 /******************************************************************
3274 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
3276 DWORD WINAPI
AllocateAndGetTcpExTableFromStack( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
, DWORD family
)
3278 TRACE( "table %p, sort %d, heap %p, flags 0x%08lx, family %lu\n", table
, sort
, heap
, flags
, family
);
3280 if (!table
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3281 if (family
== AF_INET6
) return ERROR_NOT_SUPPORTED
;
3283 return allocate_tcp_table( table
, sort
, heap
, flags
, family
, TCP_TABLE_OWNER_PID_ALL
);
3286 /******************************************************************
3287 * GetUdpStatistics (IPHLPAPI.@)
3289 * Get the UDP statistics for the local computer.
3292 * stats [Out] buffer for UDP statistics
3294 DWORD WINAPI
GetUdpStatistics( MIB_UDPSTATS
*stats
)
3296 return GetUdpStatisticsEx( stats
, AF_INET
);
3299 /******************************************************************
3300 * GetUdpStatisticsEx (IPHLPAPI.@)
3302 * Get the IPv4 and IPv6 UDP statistics for the local computer.
3305 * stats [Out] buffer for UDP statistics
3306 * family [In] specifies whether IPv4 or IPv6 statistics are returned
3310 * Failure: error code from winerror.h
3312 DWORD WINAPI
GetUdpStatisticsEx( MIB_UDPSTATS
*stats
, DWORD family
)
3314 struct nsi_udp_stats_dynamic dyn
;
3315 USHORT key
= (USHORT
)family
;
3318 if (!stats
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3319 memset( stats
, 0, sizeof(*stats
) );
3321 err
= NsiGetAllParameters( 1, &NPI_MS_UDP_MODULEID
, NSI_UDP_STATS_TABLE
, &key
, sizeof(key
), NULL
, 0,
3322 &dyn
, sizeof(dyn
), NULL
, 0 );
3323 if (err
) return err
;
3325 stats
->dwInDatagrams
= dyn
.in_dgrams
;
3326 stats
->dwNoPorts
= dyn
.no_ports
;
3327 stats
->dwInErrors
= dyn
.in_errs
;
3328 stats
->dwOutDatagrams
= dyn
.out_dgrams
;
3329 stats
->dwNumAddrs
= dyn
.num_addrs
;
3333 /******************************************************************
3334 * GetUdpTable (IPHLPAPI.@)
3336 * Get a table of active UDP connections.
3339 * table [Out] buffer for UDP connections table
3340 * size [In/Out] length of output buffer
3341 * sort [In] whether to order the table
3344 DWORD WINAPI
GetUdpTable( MIB_UDPTABLE
*table
, DWORD
*size
, BOOL sort
)
3346 return GetExtendedUdpTable( table
, size
, sort
, AF_INET
, UDP_TABLE_BASIC
, 0 );
3349 /******************************************************************
3350 * GetUdp6Table (IPHLPAPI.@)
3352 DWORD WINAPI
GetUdp6Table( MIB_UDP6TABLE
*table
, DWORD
*size
, BOOL sort
)
3354 return GetExtendedUdpTable( table
, size
, sort
, AF_INET6
, UDP_TABLE_BASIC
, 0 );
3357 static DWORD
udp_table_size( ULONG family
, ULONG table_class
, DWORD row_count
, DWORD
*row_size
)
3359 switch (table_class
)
3361 case UDP_TABLE_BASIC
:
3362 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW
) : sizeof(MIB_UDP6ROW
);
3363 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE
, table
[row_count
]) :
3364 FIELD_OFFSET(MIB_UDP6TABLE
, table
[row_count
]);
3366 case UDP_TABLE_OWNER_PID
:
3367 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW_OWNER_PID
) : sizeof(MIB_UDP6ROW_OWNER_PID
);
3368 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID
, table
[row_count
]) :
3369 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID
, table
[row_count
]);
3371 case UDP_TABLE_OWNER_MODULE
:
3372 *row_size
= (family
== AF_INET
) ? sizeof(MIB_UDPROW_OWNER_MODULE
) : sizeof(MIB_UDP6ROW_OWNER_MODULE
);
3373 return (family
== AF_INET
) ? FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE
, table
[row_count
]) :
3374 FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE
, table
[row_count
]);
3377 ERR( "unhandled class %lu\n", table_class
);
3382 static void udp_row_fill( void *table
, DWORD num
, ULONG family
, ULONG table_class
,
3383 struct nsi_udp_endpoint_key
*key
,
3384 struct nsi_udp_endpoint_static
*stat
)
3386 if (family
== AF_INET
)
3388 switch (table_class
)
3390 case UDP_TABLE_BASIC
:
3392 MIB_UDPROW
*row
= ((MIB_UDPTABLE
*)table
)->table
+ num
;
3393 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3394 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3397 case UDP_TABLE_OWNER_PID
:
3399 MIB_UDPROW_OWNER_PID
*row
= ((MIB_UDPTABLE_OWNER_PID
*)table
)->table
+ num
;
3400 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3401 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3402 row
->dwOwningPid
= stat
->pid
;
3405 case UDP_TABLE_OWNER_MODULE
:
3407 MIB_UDPROW_OWNER_MODULE
*row
= ((MIB_UDPTABLE_OWNER_MODULE
*)table
)->table
+ num
;
3408 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.s_addr
;
3409 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
3410 row
->dwOwningPid
= stat
->pid
;
3411 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3412 row
->dwFlags
= stat
->flags
;
3413 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3414 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3418 ERR( "Unknown class %ld\n", table_class
);
3424 switch (table_class
)
3426 case UDP_TABLE_BASIC
:
3428 MIB_UDP6ROW
*row
= ((MIB_UDP6TABLE
*)table
)->table
+ num
;
3429 memcpy( &row
->dwLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->dwLocalAddr
) );
3430 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3431 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3434 case UDP_TABLE_OWNER_PID
:
3436 MIB_UDP6ROW_OWNER_PID
*row
= ((MIB_UDP6TABLE_OWNER_PID
*)table
)->table
+ num
;
3437 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3438 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3439 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3440 row
->dwOwningPid
= stat
->pid
;
3443 case UDP_TABLE_OWNER_MODULE
:
3445 MIB_UDP6ROW_OWNER_MODULE
*row
= ((MIB_UDP6TABLE_OWNER_MODULE
*)table
)->table
+ num
;
3446 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3447 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3448 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3449 row
->dwOwningPid
= stat
->pid
;
3450 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3451 row
->dwFlags
= stat
->flags
;
3452 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3453 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3457 ERR( "Unknown class %ld\n", table_class
);
3461 ERR( "Unknown family %ld\n", family
);
3465 static int udp_row_cmp( const void *a
, const void *b
)
3467 const MIB_UDPROW
*rowA
= a
, *rowB
= b
;
3469 return DWORD_cmp(RtlUlongByteSwap( rowA
->dwLocalAddr
), RtlUlongByteSwap( rowB
->dwLocalAddr
)) ||
3470 RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
);
3473 static int udp6_row_cmp( const void *a
, const void *b
)
3475 const MIB_UDP6ROW
*rowA
= a
;
3476 const MIB_UDP6ROW
*rowB
= b
;
3479 if ((ret
= memcmp( &rowA
->dwLocalAddr
, &rowB
->dwLocalAddr
, sizeof(rowA
->dwLocalAddr
) )) != 0) return ret
;
3480 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3481 return RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
);
3484 /******************************************************************
3485 * GetExtendedUdpTable (IPHLPAPI.@)
3487 DWORD WINAPI
GetExtendedUdpTable( void *table
, DWORD
*size
, BOOL sort
, ULONG family
,
3488 UDP_TABLE_CLASS table_class
, ULONG reserved
)
3490 DWORD err
, count
, needed
, i
, num
= 0, row_size
= 0;
3491 struct nsi_udp_endpoint_key
*key
;
3492 struct nsi_udp_endpoint_static
*stat
;
3494 TRACE( "table %p, size %p, sort %d, family %lu, table_class %u, reserved %lu\n",
3495 table
, size
, sort
, family
, table_class
, reserved
);
3497 if (!size
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3499 err
= NsiAllocateAndGetTable( 1, &NPI_MS_UDP_MODULEID
, NSI_UDP_ENDPOINT_TABLE
, (void **)&key
, sizeof(*key
),
3500 NULL
, 0, NULL
, 0, (void **)&stat
, sizeof(*stat
), &count
, 0 );
3501 if (err
) return err
;
3503 for (i
= 0; i
< count
; i
++)
3504 if (key
[i
].local
.si_family
== family
)
3507 needed
= udp_table_size( family
, table_class
, num
, &row_size
);
3508 if (!table
|| *size
< needed
)
3511 err
= ERROR_INSUFFICIENT_BUFFER
;
3516 *(DWORD
*)table
= num
;
3518 for (i
= 0; i
< count
; i
++)
3520 if (key
[i
].local
.si_family
!= family
) continue;
3521 udp_row_fill( table
, num
++, family
, table_class
, key
+ i
, stat
+ i
);
3527 int (*fn
)(const void *, const void *);
3528 DWORD offset
= udp_table_size( family
, table_class
, 0, &row_size
);
3530 if (family
== AF_INET
) fn
= udp_row_cmp
;
3531 else fn
= udp6_row_cmp
;
3533 qsort( (BYTE
*)table
+ offset
, num
, row_size
, fn
);
3536 NsiFreeTable( key
, NULL
, NULL
, stat
);
3540 DWORD WINAPI
AllocateAndGetUdpTableFromStack( MIB_UDPTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
3542 DWORD err
, size
= 0x100, attempt
;
3544 TRACE("table %p, sort %d, heap %p, flags 0x%08lx\n", table
, sort
, heap
, flags
);
3546 if (!table
) return ERROR_INVALID_PARAMETER
;
3548 for (attempt
= 0; attempt
< 5; attempt
++)
3550 *table
= HeapAlloc( heap
, flags
, size
);
3551 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
3552 err
= GetExtendedUdpTable( *table
, &size
, sort
, AF_INET
, UDP_TABLE_BASIC
, 0 );
3554 HeapFree( heap
, flags
, *table
);
3556 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
3561 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW
*row
, USHORT fam
, void *key
, struct nsi_ip_unicast_rw
*rw
,
3562 struct nsi_ip_unicast_dynamic
*dyn
, struct nsi_ip_unicast_static
*stat
)
3564 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
;
3565 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
;
3569 row
->Address
.Ipv4
.sin_family
= fam
;
3570 row
->Address
.Ipv4
.sin_port
= 0;
3571 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
3572 memset( row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
3573 row
->InterfaceLuid
.Value
= key4
->luid
.Value
;
3577 row
->Address
.Ipv6
.sin6_family
= fam
;
3578 row
->Address
.Ipv6
.sin6_port
= 0;
3579 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
3580 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
3581 row
->Address
.Ipv6
.sin6_scope_id
= dyn
->scope_id
;
3582 row
->InterfaceLuid
.Value
= key6
->luid
.Value
;
3585 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
3586 row
->PrefixOrigin
= rw
->prefix_origin
;
3587 row
->SuffixOrigin
= rw
->suffix_origin
;
3588 row
->ValidLifetime
= rw
->valid_lifetime
;
3589 row
->PreferredLifetime
= rw
->preferred_lifetime
;
3590 row
->OnLinkPrefixLength
= rw
->on_link_prefix
;
3591 row
->SkipAsSource
= 0;
3592 row
->DadState
= dyn
->dad_state
;
3593 row
->ScopeId
.Value
= dyn
->scope_id
;
3594 row
->CreationTimeStamp
.QuadPart
= stat
->creation_time
;
3597 DWORD WINAPI
GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW
*row
)
3599 struct nsi_ipv4_unicast_key key4
;
3600 struct nsi_ipv6_unicast_key key6
;
3601 struct nsi_ip_unicast_rw rw
;
3602 struct nsi_ip_unicast_dynamic dyn
;
3603 struct nsi_ip_unicast_static stat
;
3604 const NPI_MODULEID
*mod
;
3605 DWORD err
, key_size
;
3608 TRACE( "%p\n", row
);
3610 if (!row
) return ERROR_INVALID_PARAMETER
;
3611 mod
= ip_module_id( row
->Address
.si_family
);
3612 if (!mod
) return ERROR_INVALID_PARAMETER
;
3614 if (!row
->InterfaceLuid
.Value
)
3616 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
3617 if (err
) return err
;
3620 if (row
->Address
.si_family
== AF_INET
)
3622 key4
.luid
= row
->InterfaceLuid
;
3623 key4
.addr
= row
->Address
.Ipv4
.sin_addr
;
3626 key_size
= sizeof(key4
);
3628 else if (row
->Address
.si_family
== AF_INET6
)
3630 key6
.luid
= row
->InterfaceLuid
;
3631 key6
.addr
= row
->Address
.Ipv6
.sin6_addr
;
3633 key_size
= sizeof(key6
);
3635 else return ERROR_INVALID_PARAMETER
;
3637 err
= NsiGetAllParameters( 1, mod
, NSI_IP_UNICAST_TABLE
, key
, key_size
, &rw
, sizeof(rw
),
3638 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
3639 if (!err
) unicast_row_fill( row
, row
->Address
.si_family
, key
, &rw
, &dyn
, &stat
);
3643 DWORD WINAPI
GetUnicastIpAddressTable(ADDRESS_FAMILY family
, MIB_UNICASTIPADDRESS_TABLE
**table
)
3645 void *key
[2] = { NULL
, NULL
};
3646 struct nsi_ip_unicast_rw
*rw
[2] = { NULL
, NULL
};
3647 struct nsi_ip_unicast_dynamic
*dyn
[2] = { NULL
, NULL
};
3648 struct nsi_ip_unicast_static
*stat
[2] = { NULL
, NULL
};
3649 static const USHORT fam
[2] = { AF_INET
, AF_INET6
};
3650 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_unicast_key
), sizeof(struct nsi_ipv6_unicast_key
) };
3651 DWORD err
, i
, size
, count
[2] = { 0, 0 };
3653 TRACE( "%u, %p\n", family
, table
);
3655 if (!table
|| (family
!= AF_INET
&& family
!= AF_INET6
&& family
!= AF_UNSPEC
))
3656 return ERROR_INVALID_PARAMETER
;
3658 for (i
= 0; i
< 2; i
++)
3660 if (family
!= AF_UNSPEC
&& family
!= fam
[i
]) continue;
3662 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_UNICAST_TABLE
, key
+ i
, key_size
[i
],
3663 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
3664 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
3668 size
= FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE
, Table
[ count
[0] + count
[1] ]);
3669 *table
= heap_alloc( size
);
3672 err
= ERROR_NOT_ENOUGH_MEMORY
;
3676 (*table
)->NumEntries
= count
[0] + count
[1];
3677 for (i
= 0; i
< count
[0]; i
++)
3679 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ i
;
3680 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
[0];
3682 unicast_row_fill( row
, fam
[0], (void *)(key4
+ i
), rw
[0] + i
, dyn
[0] + i
, stat
[0] + i
);
3685 for (i
= 0; i
< count
[1]; i
++)
3687 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ count
[0] + i
;
3688 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
[1];
3690 unicast_row_fill( row
, fam
[1], (void *)(key6
+ i
), rw
[1] + i
, dyn
[1] + i
, stat
[1] + i
);
3694 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
3698 /******************************************************************
3699 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3701 * This is a Win98-only function to get information on "unidirectional"
3702 * adapters. Since this is pretty nonsensical in other contexts, it
3703 * never returns anything.
3706 * pIPIfInfo [Out] buffer for adapter infos
3707 * dwOutBufLen [Out] length of the output buffer
3711 * Failure: error code from winerror.h
3714 * Stub, returns ERROR_NOT_SUPPORTED.
3716 DWORD WINAPI
GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo
, PULONG dwOutBufLen
)
3718 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo
, dwOutBufLen
);
3719 /* a unidirectional adapter?? not bloody likely! */
3720 return ERROR_NOT_SUPPORTED
;
3724 /******************************************************************
3725 * IpReleaseAddress (IPHLPAPI.@)
3727 * Release an IP obtained through DHCP,
3730 * AdapterInfo [In] adapter to release IP address
3734 * Failure: error code from winerror.h
3737 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3738 * this function does nothing.
3741 * Stub, returns ERROR_NOT_SUPPORTED.
3743 DWORD WINAPI
IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3745 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3746 return ERROR_NOT_SUPPORTED
;
3750 /******************************************************************
3751 * IpRenewAddress (IPHLPAPI.@)
3753 * Renew an IP obtained through DHCP.
3756 * AdapterInfo [In] adapter to renew IP address
3760 * Failure: error code from winerror.h
3763 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3764 * this function does nothing.
3767 * Stub, returns ERROR_NOT_SUPPORTED.
3769 DWORD WINAPI
IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3771 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3772 return ERROR_NOT_SUPPORTED
;
3776 /******************************************************************
3777 * NotifyAddrChange (IPHLPAPI.@)
3779 * Notify caller whenever the ip-interface map is changed.
3782 * Handle [Out] handle usable in asynchronous notification
3783 * overlapped [In] overlapped structure that notifies the caller
3787 * Failure: error code from winerror.h
3790 * Stub, returns ERROR_NOT_SUPPORTED.
3792 DWORD WINAPI
NotifyAddrChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3794 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
3795 if (Handle
) *Handle
= INVALID_HANDLE_VALUE
;
3796 if (overlapped
) ((IO_STATUS_BLOCK
*) overlapped
)->Status
= STATUS_PENDING
;
3797 return ERROR_IO_PENDING
;
3801 /******************************************************************
3802 * NotifyIpInterfaceChange (IPHLPAPI.@)
3804 DWORD WINAPI
NotifyIpInterfaceChange(ADDRESS_FAMILY family
, PIPINTERFACE_CHANGE_CALLBACK callback
,
3805 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3807 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3808 family
, callback
, context
, init_notify
, handle
);
3809 if (handle
) *handle
= NULL
;
3813 /******************************************************************
3814 * NotifyRouteChange2 (IPHLPAPI.@)
3816 DWORD WINAPI
NotifyRouteChange2(ADDRESS_FAMILY family
, PIPFORWARD_CHANGE_CALLBACK callback
, VOID
* context
,
3817 BOOLEAN init_notify
, HANDLE
* handle
)
3819 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3820 family
, callback
, context
, init_notify
, handle
);
3821 if (handle
) *handle
= NULL
;
3826 /******************************************************************
3827 * NotifyRouteChange (IPHLPAPI.@)
3829 * Notify caller whenever the ip routing table is changed.
3832 * Handle [Out] handle usable in asynchronous notification
3833 * overlapped [In] overlapped structure that notifies the caller
3837 * Failure: error code from winerror.h
3840 * Stub, returns ERROR_NOT_SUPPORTED.
3842 DWORD WINAPI
NotifyRouteChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3844 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
3845 return ERROR_NOT_SUPPORTED
;
3849 /******************************************************************
3850 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3852 DWORD WINAPI
NotifyUnicastIpAddressChange(ADDRESS_FAMILY family
, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback
,
3853 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3855 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3856 family
, callback
, context
, init_notify
, handle
);
3857 if (handle
) *handle
= NULL
;
3860 callback(context
, NULL
, MibInitialNotification
);
3865 /******************************************************************
3866 * SendARP (IPHLPAPI.@)
3868 * Send an ARP request.
3871 * DestIP [In] attempt to obtain this IP
3872 * SrcIP [In] optional sender IP address
3873 * pMacAddr [Out] buffer for the mac address
3874 * PhyAddrLen [In/Out] length of the output buffer
3878 * Failure: error code from winerror.h
3881 * Stub, returns ERROR_NOT_SUPPORTED.
3883 DWORD WINAPI
SendARP(IPAddr DestIP
, IPAddr SrcIP
, PULONG pMacAddr
, PULONG PhyAddrLen
)
3885 FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
3886 DestIP
, SrcIP
, pMacAddr
, PhyAddrLen
);
3887 return ERROR_NOT_SUPPORTED
;
3891 /******************************************************************
3892 * SetIfEntry (IPHLPAPI.@)
3894 * Set the administrative status of an interface.
3897 * pIfRow [In] dwAdminStatus member specifies the new status.
3901 * Failure: error code from winerror.h
3904 * Stub, returns ERROR_NOT_SUPPORTED.
3906 DWORD WINAPI
SetIfEntry(PMIB_IFROW pIfRow
)
3908 FIXME("(pIfRow %p): stub\n", pIfRow
);
3909 /* this is supposed to set an interface administratively up or down.
3910 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3911 this sort of down is indistinguishable from other sorts of down (e.g. no
3913 return ERROR_NOT_SUPPORTED
;
3917 /******************************************************************
3918 * SetIpForwardEntry (IPHLPAPI.@)
3920 * Modify an existing route.
3923 * pRoute [In] route with the new information
3927 * Failure: error code from winerror.h
3930 * Stub, returns NO_ERROR.
3932 DWORD WINAPI
SetIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
3934 FIXME("(pRoute %p): stub\n", pRoute
);
3935 /* this is to add a route entry, how's it distinguishable from
3936 CreateIpForwardEntry?
3937 could use SIOCADDRT, not sure I want to */
3942 /******************************************************************
3943 * SetIpNetEntry (IPHLPAPI.@)
3945 * Modify an existing ARP entry.
3948 * pArpEntry [In] ARP entry with the new information
3952 * Failure: error code from winerror.h
3955 * Stub, returns NO_ERROR.
3957 DWORD WINAPI
SetIpNetEntry(PMIB_IPNETROW pArpEntry
)
3959 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
3960 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3965 /******************************************************************
3966 * SetIpStatistics (IPHLPAPI.@)
3968 * Toggle IP forwarding and det the default TTL value.
3971 * pIpStats [In] IP statistics with the new information
3975 * Failure: error code from winerror.h
3978 * Stub, returns NO_ERROR.
3980 DWORD WINAPI
SetIpStatistics(PMIB_IPSTATS pIpStats
)
3982 FIXME("(pIpStats %p): stub\n", pIpStats
);
3987 /******************************************************************
3988 * SetIpTTL (IPHLPAPI.@)
3990 * Set the default TTL value.
3993 * nTTL [In] new TTL value
3997 * Failure: error code from winerror.h
4000 * Stub, returns NO_ERROR.
4002 DWORD WINAPI
SetIpTTL(UINT nTTL
)
4004 FIXME("(nTTL %d): stub\n", nTTL
);
4005 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
4006 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
4011 /******************************************************************
4012 * SetTcpEntry (IPHLPAPI.@)
4014 * Set the state of a TCP connection.
4017 * pTcpRow [In] specifies connection with new state
4021 * Failure: error code from winerror.h
4024 * Stub, returns NO_ERROR.
4026 DWORD WINAPI
SetTcpEntry(PMIB_TCPROW pTcpRow
)
4028 FIXME("(pTcpRow %p): stub\n", pTcpRow
);
4032 /******************************************************************
4033 * SetPerTcpConnectionEStats (IPHLPAPI.@)
4035 DWORD WINAPI
SetPerTcpConnectionEStats(PMIB_TCPROW row
, TCP_ESTATS_TYPE state
, PBYTE rw
,
4036 ULONG version
, ULONG size
, ULONG offset
)
4038 FIXME("(row %p, state %d, rw %p, version %lu, size %lu, offset %lu): stub\n",
4039 row
, state
, rw
, version
, size
, offset
);
4040 return ERROR_NOT_SUPPORTED
;
4044 /******************************************************************
4045 * UnenableRouter (IPHLPAPI.@)
4047 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
4048 * if it reaches zero.
4051 * pOverlapped [In/Out] should be the same as in EnableRouter()
4052 * lpdwEnableCount [Out] optional, receives reference count
4056 * Failure: error code from winerror.h
4059 * Stub, returns ERROR_NOT_SUPPORTED.
4061 DWORD WINAPI
UnenableRouter(OVERLAPPED
* pOverlapped
, LPDWORD lpdwEnableCount
)
4063 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped
,
4065 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
4066 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
4068 return ERROR_NOT_SUPPORTED
;
4071 /******************************************************************
4072 * PfCreateInterface (IPHLPAPI.@)
4074 DWORD WINAPI
PfCreateInterface(DWORD dwName
, PFFORWARD_ACTION inAction
, PFFORWARD_ACTION outAction
,
4075 BOOL bUseLog
, BOOL bMustBeUnique
, INTERFACE_HANDLE
*ppInterface
)
4077 FIXME("(%ld %d %d %x %x %p) stub\n", dwName
, inAction
, outAction
, bUseLog
, bMustBeUnique
, ppInterface
);
4078 return ERROR_CALL_NOT_IMPLEMENTED
;
4081 /******************************************************************
4082 * PfUnBindInterface (IPHLPAPI.@)
4084 DWORD WINAPI
PfUnBindInterface(INTERFACE_HANDLE interface
)
4086 FIXME("(%p) stub\n", interface
);
4087 return ERROR_CALL_NOT_IMPLEMENTED
;
4090 /******************************************************************
4091 * PfDeleteInterface(IPHLPAPI.@)
4093 DWORD WINAPI
PfDeleteInterface(INTERFACE_HANDLE interface
)
4095 FIXME("(%p) stub\n", interface
);
4096 return ERROR_CALL_NOT_IMPLEMENTED
;
4099 /******************************************************************
4100 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
4102 DWORD WINAPI
PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface
, PFADDRESSTYPE type
, PBYTE ip
)
4104 FIXME("(%p %d %p) stub\n", interface
, type
, ip
);
4105 return ERROR_CALL_NOT_IMPLEMENTED
;
4108 /******************************************************************
4109 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
4111 DWORD WINAPI
ConvertInterfaceAliasToLuid( const WCHAR
*alias
, NET_LUID
*luid
)
4113 struct nsi_ndis_ifinfo_rw
*data
;
4114 DWORD err
, count
, i
, len
;
4117 TRACE( "(%s %p)\n", debugstr_w(alias
), luid
);
4119 if (!alias
|| !*alias
|| !luid
) return ERROR_INVALID_PARAMETER
;
4121 len
= wcslen( alias
);
4123 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
4124 (void **)&data
, sizeof(*data
), NULL
, 0, NULL
, 0, &count
, 0 );
4125 if (err
) return err
;
4127 err
= ERROR_INVALID_PARAMETER
;
4128 for (i
= 0; i
< count
; i
++)
4130 if (data
[i
].alias
.Length
== len
* 2 && !memcmp( data
[i
].alias
.String
, alias
, len
* 2 ))
4132 luid
->Value
= keys
[i
].Value
;
4133 err
= ERROR_SUCCESS
;
4137 NsiFreeTable( keys
, data
, NULL
, NULL
);
4141 /******************************************************************
4142 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
4144 DWORD WINAPI
ConvertInterfaceGuidToLuid(const GUID
*guid
, NET_LUID
*luid
)
4146 struct nsi_ndis_ifinfo_static
*data
;
4147 DWORD err
, count
, i
;
4150 TRACE( "(%s %p)\n", debugstr_guid(guid
), luid
);
4152 if (!guid
|| !luid
) return ERROR_INVALID_PARAMETER
;
4155 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
4156 NULL
, 0, NULL
, 0, (void **)&data
, sizeof(*data
), &count
, 0 );
4157 if (err
) return err
;
4159 err
= ERROR_INVALID_PARAMETER
;
4160 for (i
= 0; i
< count
; i
++)
4162 if (IsEqualGUID( &data
[i
].if_guid
, guid
))
4164 luid
->Value
= keys
[i
].Value
;
4165 err
= ERROR_SUCCESS
;
4169 NsiFreeTable( keys
, NULL
, NULL
, data
);
4173 /******************************************************************
4174 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
4176 DWORD WINAPI
ConvertInterfaceIndexToLuid(NET_IFINDEX index
, NET_LUID
*luid
)
4180 TRACE( "(%lu %p)\n", index
, luid
);
4182 if (!luid
) return ERROR_INVALID_PARAMETER
;
4184 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_INDEX_LUID_TABLE
, &index
, sizeof(index
),
4185 NSI_PARAM_TYPE_STATIC
, luid
, sizeof(*luid
), 0 );
4186 if (err
) luid
->Value
= 0;
4190 /******************************************************************
4191 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4193 DWORD WINAPI
ConvertInterfaceLuidToAlias( const NET_LUID
*luid
, WCHAR
*alias
, SIZE_T len
)
4196 IF_COUNTED_STRING name
;
4198 TRACE( "(%p %p %Iu)\n", luid
, alias
, len
);
4200 if (!luid
|| !alias
) return ERROR_INVALID_PARAMETER
;
4202 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4203 NSI_PARAM_TYPE_RW
, &name
, sizeof(name
),
4204 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw
, alias
) );
4205 if (err
) return err
;
4207 if (len
<= name
.Length
/ sizeof(WCHAR
)) return ERROR_NOT_ENOUGH_MEMORY
;
4208 memcpy( alias
, name
.String
, name
.Length
);
4209 alias
[name
.Length
/ sizeof(WCHAR
)] = '\0';
4214 /******************************************************************
4215 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4217 DWORD WINAPI
ConvertInterfaceLuidToGuid(const NET_LUID
*luid
, GUID
*guid
)
4221 TRACE( "(%p %p)\n", luid
, guid
);
4223 if (!luid
|| !guid
) return ERROR_INVALID_PARAMETER
;
4225 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4226 NSI_PARAM_TYPE_STATIC
, guid
, sizeof(*guid
),
4227 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_guid
) );
4228 if (err
) memset( guid
, 0, sizeof(*guid
) );
4232 /******************************************************************
4233 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4235 DWORD WINAPI
ConvertInterfaceLuidToIndex(const NET_LUID
*luid
, NET_IFINDEX
*index
)
4239 TRACE( "(%p %p)\n", luid
, index
);
4241 if (!luid
|| !index
) return ERROR_INVALID_PARAMETER
;
4243 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4244 NSI_PARAM_TYPE_STATIC
, index
, sizeof(*index
),
4245 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_index
) );
4246 if (err
) *index
= 0;
4250 /******************************************************************
4251 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4253 DWORD WINAPI
ConvertInterfaceLuidToNameA(const NET_LUID
*luid
, char *name
, SIZE_T len
)
4256 WCHAR nameW
[IF_MAX_STRING_SIZE
+ 1];
4258 TRACE( "(%p %p %Iu)\n", luid
, name
, len
);
4260 if (!luid
) return ERROR_INVALID_PARAMETER
;
4261 if (!name
|| !len
) return ERROR_NOT_ENOUGH_MEMORY
;
4263 err
= ConvertInterfaceLuidToNameW( luid
, nameW
, ARRAY_SIZE(nameW
) );
4264 if (err
) return err
;
4266 if (!WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, name
, len
, NULL
, NULL
))
4267 err
= GetLastError();
4273 const WCHAR
*prefix
;
4276 static const struct name_prefix name_prefixes
[] =
4278 { L
"other", IF_TYPE_OTHER
},
4279 { L
"ethernet", IF_TYPE_ETHERNET_CSMACD
},
4280 { L
"tokenring", IF_TYPE_ISO88025_TOKENRING
},
4281 { L
"ppp", IF_TYPE_PPP
},
4282 { L
"loopback", IF_TYPE_SOFTWARE_LOOPBACK
},
4283 { L
"atm", IF_TYPE_ATM
},
4284 { L
"wireless", IF_TYPE_IEEE80211
},
4285 { L
"tunnel", IF_TYPE_TUNNEL
},
4286 { L
"ieee1394", IF_TYPE_IEEE1394
}
4289 /******************************************************************
4290 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4292 DWORD WINAPI
ConvertInterfaceLuidToNameW(const NET_LUID
*luid
, WCHAR
*name
, SIZE_T len
)
4295 const WCHAR
*prefix
= NULL
;
4296 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4298 TRACE( "(%p %p %Iu)\n", luid
, name
, len
);
4300 if (!luid
|| !name
) return ERROR_INVALID_PARAMETER
;
4302 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4304 if (luid
->Info
.IfType
== name_prefixes
[i
].type
)
4306 prefix
= name_prefixes
[i
].prefix
;
4311 if (prefix
) needed
= swprintf( buf
, len
, L
"%s_%d", prefix
, luid
->Info
.NetLuidIndex
);
4312 else needed
= swprintf( buf
, len
, L
"iftype%d_%d", luid
->Info
.IfType
, luid
->Info
.NetLuidIndex
);
4314 if (needed
>= len
) return ERROR_NOT_ENOUGH_MEMORY
;
4315 memcpy( name
, buf
, (needed
+ 1) * sizeof(WCHAR
) );
4316 return ERROR_SUCCESS
;
4319 /******************************************************************
4320 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4322 DWORD WINAPI
ConvertInterfaceNameToLuidA(const char *name
, NET_LUID
*luid
)
4324 WCHAR nameW
[IF_MAX_STRING_SIZE
];
4326 TRACE( "(%s %p)\n", debugstr_a(name
), luid
);
4328 if (!name
) return ERROR_INVALID_NAME
;
4329 if (!MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, ARRAY_SIZE(nameW
) ))
4330 return GetLastError();
4332 return ConvertInterfaceNameToLuidW( nameW
, luid
);
4335 /******************************************************************
4336 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4338 DWORD WINAPI
ConvertInterfaceNameToLuidW(const WCHAR
*name
, NET_LUID
*luid
)
4341 DWORD type
= ~0u, i
;
4342 int iftype_len
= wcslen( L
"iftype" );
4343 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4345 TRACE( "(%s %p)\n", debugstr_w(name
), luid
);
4347 if (!luid
) return ERROR_INVALID_PARAMETER
;
4348 memset( luid
, 0, sizeof(*luid
) );
4350 if (!name
|| !(sep
= wcschr( name
, '_' )) || sep
>= name
+ ARRAY_SIZE(buf
)) return ERROR_INVALID_NAME
;
4351 memcpy( buf
, name
, (sep
- name
) * sizeof(WCHAR
) );
4352 buf
[sep
- name
] = '\0';
4354 if (sep
- name
> iftype_len
&& !memcmp( buf
, L
"iftype", iftype_len
* sizeof(WCHAR
) ))
4356 type
= wcstol( buf
+ iftype_len
, NULL
, 10 );
4360 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4362 if (!wcscmp( buf
, name_prefixes
[i
].prefix
))
4364 type
= name_prefixes
[i
].type
;
4369 if (type
== ~0u) return ERROR_INVALID_NAME
;
4371 luid
->Info
.NetLuidIndex
= wcstol( sep
+ 1, NULL
, 10 );
4372 luid
->Info
.IfType
= type
;
4373 return ERROR_SUCCESS
;
4376 /******************************************************************
4377 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4379 DWORD WINAPI
ConvertLengthToIpv4Mask(ULONG mask_len
, ULONG
*mask
)
4383 *mask
= INADDR_NONE
;
4384 return ERROR_INVALID_PARAMETER
;
4390 *mask
= htonl(~0u << (32 - mask_len
));
4395 /******************************************************************
4396 * if_nametoindex (IPHLPAPI.@)
4398 IF_INDEX WINAPI
IPHLP_if_nametoindex(const char *name
)
4404 TRACE( "(%s)\n", name
);
4406 err
= ConvertInterfaceNameToLuidA( name
, &luid
);
4409 err
= ConvertInterfaceLuidToIndex( &luid
, &index
);
4414 /******************************************************************
4415 * if_indextoname (IPHLPAPI.@)
4417 char *WINAPI
IPHLP_if_indextoname( NET_IFINDEX index
, char *name
)
4422 TRACE( "(%lu, %p)\n", index
, name
);
4424 err
= ConvertInterfaceIndexToLuid( index
, &luid
);
4425 if (err
) return NULL
;
4427 err
= ConvertInterfaceLuidToNameA( &luid
, name
, IF_MAX_STRING_SIZE
);
4428 if (err
) return NULL
;
4432 /******************************************************************
4433 * GetIpInterfaceTable (IPHLPAPI.@)
4435 DWORD WINAPI
GetIpInterfaceTable(ADDRESS_FAMILY family
, PMIB_IPINTERFACE_TABLE
*table
)
4437 FIXME("(%u %p): stub\n", family
, table
);
4438 return ERROR_NOT_SUPPORTED
;
4441 /******************************************************************
4442 * GetBestRoute2 (IPHLPAPI.@)
4444 DWORD WINAPI
GetBestRoute2(NET_LUID
*luid
, NET_IFINDEX index
,
4445 const SOCKADDR_INET
*source
, const SOCKADDR_INET
*destination
,
4446 ULONG options
, PMIB_IPFORWARD_ROW2 bestroute
,
4447 SOCKADDR_INET
*bestaddress
)
4452 FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid
, index
, source
,
4453 destination
, options
, bestroute
, bestaddress
);
4455 if (!destination
|| !bestroute
|| !bestaddress
)
4456 return ERROR_INVALID_PARAMETER
;
4458 return ERROR_NOT_SUPPORTED
;
4461 /******************************************************************
4462 * ParseNetworkString (IPHLPAPI.@)
4464 DWORD WINAPI
ParseNetworkString(const WCHAR
*str
, DWORD type
,
4465 NET_ADDRESS_INFO
*info
, USHORT
*port
, BYTE
*prefix_len
)
4468 IN6_ADDR temp_addr6
;
4470 USHORT temp_port
= 0;
4473 TRACE("(%s, %ld, %p, %p, %p)\n", debugstr_w(str
), type
, info
, port
, prefix_len
);
4476 return ERROR_INVALID_PARAMETER
;
4478 if (type
& NET_STRING_IPV4_ADDRESS
)
4480 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4481 if (SUCCEEDED(status
) && !temp_port
)
4485 info
->Format
= NET_ADDRESS_IPV4
;
4486 info
->Ipv4Address
.sin_addr
= temp_addr4
;
4487 info
->Ipv4Address
.sin_port
= 0;
4489 if (port
) *port
= 0;
4490 if (prefix_len
) *prefix_len
= 255;
4491 return ERROR_SUCCESS
;
4494 if (type
& NET_STRING_IPV4_SERVICE
)
4496 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4497 if (SUCCEEDED(status
) && temp_port
)
4501 info
->Format
= NET_ADDRESS_IPV4
;
4502 info
->Ipv4Address
.sin_addr
= temp_addr4
;
4503 info
->Ipv4Address
.sin_port
= temp_port
;
4505 if (port
) *port
= ntohs(temp_port
);
4506 if (prefix_len
) *prefix_len
= 255;
4507 return ERROR_SUCCESS
;
4510 if (type
& NET_STRING_IPV6_ADDRESS
)
4512 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4513 if (SUCCEEDED(status
) && !temp_port
)
4517 info
->Format
= NET_ADDRESS_IPV6
;
4518 info
->Ipv6Address
.sin6_addr
= temp_addr6
;
4519 info
->Ipv6Address
.sin6_scope_id
= temp_scope
;
4520 info
->Ipv6Address
.sin6_port
= 0;
4522 if (port
) *port
= 0;
4523 if (prefix_len
) *prefix_len
= 255;
4524 return ERROR_SUCCESS
;
4527 if (type
& NET_STRING_IPV6_SERVICE
)
4529 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4530 if (SUCCEEDED(status
) && temp_port
)
4534 info
->Format
= NET_ADDRESS_IPV6
;
4535 info
->Ipv6Address
.sin6_addr
= temp_addr6
;
4536 info
->Ipv6Address
.sin6_scope_id
= temp_scope
;
4537 info
->Ipv6Address
.sin6_port
= temp_port
;
4539 if (port
) *port
= ntohs(temp_port
);
4540 if (prefix_len
) *prefix_len
= 255;
4541 return ERROR_SUCCESS
;
4545 if (info
) info
->Format
= NET_ADDRESS_FORMAT_UNSPECIFIED
;
4547 if (type
& ~(NET_STRING_IPV4_ADDRESS
|NET_STRING_IPV4_SERVICE
|NET_STRING_IPV6_ADDRESS
|NET_STRING_IPV6_SERVICE
))
4549 FIXME("Unimplemented type 0x%lx\n", type
);
4550 return ERROR_NOT_SUPPORTED
;
4553 return ERROR_INVALID_PARAMETER
;
4556 struct icmp_handle_data
4561 /***********************************************************************
4562 * IcmpCloseHandle (IPHLPAPI.@)
4564 BOOL WINAPI
IcmpCloseHandle( HANDLE handle
)
4566 struct icmp_handle_data
*data
= (struct icmp_handle_data
*)handle
;
4568 CloseHandle( data
->nsi_device
);
4573 /***********************************************************************
4574 * IcmpCreateFile (IPHLPAPI.@)
4576 HANDLE WINAPI
IcmpCreateFile( void )
4578 struct icmp_handle_data
*data
= heap_alloc( sizeof(*data
) );
4582 SetLastError( IP_NO_RESOURCES
);
4583 return INVALID_HANDLE_VALUE
;
4586 data
->nsi_device
= CreateFileW( L
"\\\\.\\Nsi", 0, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
,
4587 FILE_FLAG_OVERLAPPED
, NULL
);
4588 if (data
->nsi_device
== INVALID_HANDLE_VALUE
)
4591 return INVALID_HANDLE_VALUE
;
4594 return (HANDLE
)data
;
4597 /******************************************************************
4598 * IcmpParseReplies (IPHLPAPI.@)
4600 DWORD WINAPI
IcmpParseReplies( void *reply
, DWORD reply_size
)
4602 ICMP_ECHO_REPLY
*icmp_reply
= reply
;
4603 DWORD num_pkts
= icmp_reply
->Reserved
;
4605 icmp_reply
->Reserved
= 0;
4606 if (!num_pkts
) SetLastError( icmp_reply
->Status
);
4610 /***********************************************************************
4611 * IcmpSendEcho (IPHLPAPI.@)
4613 DWORD WINAPI
IcmpSendEcho( HANDLE handle
, IPAddr dst
, void *request
, WORD request_size
,
4614 IP_OPTION_INFORMATION
*opts
, void *reply
, DWORD reply_size
,
4617 return IcmpSendEcho2Ex( handle
, NULL
, NULL
, NULL
, INADDR_ANY
, dst
, request
, request_size
,
4618 opts
, reply
, reply_size
, timeout
);
4621 /***********************************************************************
4622 * IcmpSendEcho2 (IPHLPAPI.@)
4624 DWORD WINAPI
IcmpSendEcho2( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4625 IPAddr dst
, void *request
, WORD request_size
, IP_OPTION_INFORMATION
*opts
,
4626 void *reply
, DWORD reply_size
, DWORD timeout
)
4628 return IcmpSendEcho2Ex( handle
, event
, apc_routine
, apc_ctxt
, INADDR_ANY
, dst
, request
, request_size
,
4629 opts
, reply
, reply_size
, timeout
);
4632 struct icmp_apc_ctxt
4635 PIO_APC_ROUTINE apc_routine
;
4636 IO_STATUS_BLOCK iosb
;
4639 void WINAPI
icmp_apc_routine( void *context
, IO_STATUS_BLOCK
*iosb
, ULONG reserved
)
4641 struct icmp_apc_ctxt
*ctxt
= context
;
4643 ctxt
->apc_routine( ctxt
->apc_ctxt
, iosb
, reserved
);
4647 /***********************************************************************
4648 * IcmpSendEcho2Ex (IPHLPAPI.@)
4650 DWORD WINAPI
IcmpSendEcho2Ex( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4651 IPAddr src
, IPAddr dst
, void *request
, WORD request_size
, IP_OPTION_INFORMATION
*opts
,
4652 void *reply
, DWORD reply_size
, DWORD timeout
)
4654 struct icmp_handle_data
*data
= (struct icmp_handle_data
*)handle
;
4655 struct icmp_apc_ctxt
*ctxt
= heap_alloc( sizeof(*ctxt
) );
4656 IO_STATUS_BLOCK
*iosb
= &ctxt
->iosb
;
4657 DWORD opt_size
, in_size
, ret
= 0;
4658 struct nsiproxy_icmp_echo
*in
;
4659 HANDLE request_event
;
4662 if (handle
== INVALID_HANDLE_VALUE
|| !reply
)
4665 SetLastError( ERROR_INVALID_PARAMETER
);
4669 ctxt
->apc_routine
= apc_routine
;
4670 ctxt
->apc_ctxt
= apc_ctxt
;
4672 opt_size
= opts
? (opts
->OptionsSize
+ 3) & ~3 : 0;
4673 in_size
= FIELD_OFFSET(struct nsiproxy_icmp_echo
, data
[opt_size
+ request_size
]);
4674 in
= heap_alloc_zero( in_size
);
4679 SetLastError( IP_NO_RESOURCES
);
4683 in
->user_reply_ptr
= (ULONG_PTR
)reply
;
4684 in
->bits
= sizeof(void*) * 8;
4685 in
->src
.Ipv4
.sin_family
= AF_INET
;
4686 in
->src
.Ipv4
.sin_addr
.s_addr
= src
;
4687 in
->dst
.Ipv4
.sin_family
= AF_INET
;
4688 in
->dst
.Ipv4
.sin_addr
.s_addr
= dst
;
4691 in
->ttl
= opts
->Ttl
;
4692 in
->tos
= opts
->Tos
;
4693 in
->flags
= opts
->Flags
;
4694 memcpy( in
->data
, opts
->OptionsData
, opts
->OptionsSize
);
4695 in
->opt_size
= opts
->OptionsSize
;
4697 in
->req_size
= request_size
;
4698 in
->timeout
= timeout
;
4699 memcpy( in
->data
+ opt_size
, request
, request_size
);
4701 request_event
= event
? event
: (apc_routine
? NULL
: CreateEventW( NULL
, 0, 0, NULL
));
4703 status
= NtDeviceIoControlFile( data
->nsi_device
, request_event
, apc_routine
? icmp_apc_routine
: NULL
,
4704 apc_routine
? ctxt
: apc_ctxt
, iosb
, IOCTL_NSIPROXY_WINE_ICMP_ECHO
,
4705 in
, in_size
, reply
, reply_size
);
4707 if (status
== STATUS_PENDING
)
4709 if (!event
&& !apc_routine
&& !WaitForSingleObject( request_event
, INFINITE
))
4710 status
= iosb
->Status
;
4714 ret
= IcmpParseReplies( reply
, reply_size
);
4716 if (!event
&& request_event
) CloseHandle( request_event
);
4717 if (!apc_routine
|| status
!= STATUS_PENDING
) heap_free( ctxt
);
4720 if (status
) SetLastError( RtlNtStatusToDosError( status
) );
4724 /***********************************************************************
4725 * Icmp6CreateFile (IPHLPAPI.@)
4727 HANDLE WINAPI
Icmp6CreateFile( void )
4730 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4731 return INVALID_HANDLE_VALUE
;
4734 /***********************************************************************
4735 * Icmp6SendEcho2 (IPHLPAPI.@)
4737 DWORD WINAPI
Icmp6SendEcho2( HANDLE handle
, HANDLE event
, PIO_APC_ROUTINE apc_routine
, void *apc_ctxt
,
4738 struct sockaddr_in6
*src
, struct sockaddr_in6
*dst
, void *request
, WORD request_size
,
4739 IP_OPTION_INFORMATION
*opts
, void *reply
, DWORD reply_size
, DWORD timeout
)
4741 FIXME( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld): stub\n", handle
, event
,
4742 apc_routine
, apc_ctxt
, src
, dst
, request
, request_size
, opts
, reply
, reply_size
, timeout
);
4743 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);