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