2 * iphlpapi dll implementation
4 * Copyright (C) 2003,2006 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <sys/types.h>
27 #ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
51 #include "tcpestats.h"
52 #include "ip2string.h"
56 #include "wine/debug.h"
57 #include "wine/unicode.h"
58 #include "wine/heap.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
63 #define IF_NAMESIZE 16
67 #define INADDR_NONE ~0UL
70 #define CHARS_IN_GUID 39
72 DWORD WINAPI
AllocateAndGetIfTableFromStack( MIB_IFTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
);
73 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
);
75 static const NPI_MODULEID
*ip_module_id( USHORT family
)
77 if (family
== WS_AF_INET
) return &NPI_MS_IPV4_MODULEID
;
78 if (family
== WS_AF_INET6
) return &NPI_MS_IPV6_MODULEID
;
82 DWORD WINAPI
ConvertGuidToStringA( const GUID
*guid
, char *str
, DWORD len
)
84 if (len
< CHARS_IN_GUID
) return ERROR_INSUFFICIENT_BUFFER
;
85 sprintf( str
, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
86 guid
->Data1
, guid
->Data2
, guid
->Data3
, guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2],
87 guid
->Data4
[3], guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
91 DWORD WINAPI
ConvertGuidToStringW( const GUID
*guid
, WCHAR
*str
, DWORD len
)
93 static const WCHAR fmt
[] = { '{','%','0','8','X','-','%','0','4','X','-','%','0','4','X','-',
94 '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X',
95 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','}',0 };
97 if (len
< CHARS_IN_GUID
) return ERROR_INSUFFICIENT_BUFFER
;
99 guid
->Data1
, guid
->Data2
, guid
->Data3
, guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2],
100 guid
->Data4
[3], guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
101 return ERROR_SUCCESS
;
104 DWORD WINAPI
ConvertStringToGuidW( const WCHAR
*str
, GUID
*guid
)
108 RtlInitUnicodeString( &ustr
, str
);
109 return RtlNtStatusToDosError( RtlGUIDFromString( &ustr
, guid
) );
112 static void if_counted_string_copy( WCHAR
*dst
, unsigned int len
, IF_COUNTED_STRING
*src
)
114 unsigned int copy
= src
->Length
;
116 if (copy
>= len
* sizeof(WCHAR
)) copy
= 0;
117 memcpy( dst
, src
->String
, copy
);
118 memset( (char *)dst
+ copy
, 0, len
* sizeof(WCHAR
) - copy
);
121 /******************************************************************
122 * AddIPAddress (IPHLPAPI.@)
124 * Add an IP address to an adapter.
127 * Address [In] IP address to add to the adapter
128 * IpMask [In] subnet mask for the IP address
129 * IfIndex [In] adapter index to add the address
130 * NTEContext [Out] Net Table Entry (NTE) context for the IP address
131 * NTEInstance [Out] NTE instance for the IP address
135 * Failure: error code from winerror.h
138 * Stub. Currently returns ERROR_NOT_SUPPORTED.
140 DWORD WINAPI
AddIPAddress(IPAddr Address
, IPMask IpMask
, DWORD IfIndex
, PULONG NTEContext
, PULONG NTEInstance
)
143 return ERROR_NOT_SUPPORTED
;
146 /******************************************************************
147 * CancelIPChangeNotify (IPHLPAPI.@)
149 * Cancel a previous notification created by NotifyAddrChange or
153 * overlapped [In] overlapped structure that notifies the caller
160 * Stub, returns FALSE.
162 BOOL WINAPI
CancelIPChangeNotify(LPOVERLAPPED overlapped
)
164 FIXME("(overlapped %p): stub\n", overlapped
);
169 /******************************************************************
170 * CancelMibChangeNotify2 (IPHLPAPI.@)
172 DWORD WINAPI
CancelMibChangeNotify2(HANDLE handle
)
174 FIXME("(handle %p): stub\n", handle
);
179 /******************************************************************
180 * CreateIpForwardEntry (IPHLPAPI.@)
182 * Create a route in the local computer's IP table.
185 * pRoute [In] new route information
189 * Failure: error code from winerror.h
192 * Stub, always returns NO_ERROR.
194 DWORD WINAPI
CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
196 FIXME("(pRoute %p): stub\n", pRoute
);
197 /* could use SIOCADDRT, not sure I want to */
202 /******************************************************************
203 * CreateIpNetEntry (IPHLPAPI.@)
205 * Create entry in the ARP table.
208 * pArpEntry [In] new ARP entry
212 * Failure: error code from winerror.h
215 * Stub, always returns NO_ERROR.
217 DWORD WINAPI
CreateIpNetEntry(PMIB_IPNETROW pArpEntry
)
219 FIXME("(pArpEntry %p)\n", pArpEntry
);
220 /* could use SIOCSARP on systems that support it, not sure I want to */
225 /******************************************************************
226 * CreateProxyArpEntry (IPHLPAPI.@)
228 * Create a Proxy ARP (PARP) entry for an IP address.
231 * dwAddress [In] IP address for which this computer acts as a proxy.
232 * dwMask [In] subnet mask for dwAddress
233 * dwIfIndex [In] interface index
237 * Failure: error code from winerror.h
240 * Stub, returns ERROR_NOT_SUPPORTED.
242 DWORD WINAPI
CreateProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
244 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
245 dwAddress
, dwMask
, dwIfIndex
);
246 return ERROR_NOT_SUPPORTED
;
249 static char *debugstr_ipv6(const struct WS_sockaddr_in6
*sin
, char *buf
)
251 const IN6_ADDR
*addr
= &sin
->sin6_addr
;
254 BOOL in_zero
= FALSE
;
256 for (i
= 0; i
< 7; i
++)
258 if (!addr
->u
.Word
[i
])
270 p
+= sprintf(p
, "%x:", ntohs(addr
->u
.Word
[i
]));
274 sprintf(p
, "%x", ntohs(addr
->u
.Word
[7]));
278 static BOOL
map_address_6to4( const SOCKADDR_IN6
*addr6
, SOCKADDR_IN
*addr4
)
282 if (addr6
->sin6_family
!= WS_AF_INET6
) return FALSE
;
284 for (i
= 0; i
< 5; i
++)
285 if (addr6
->sin6_addr
.u
.Word
[i
]) return FALSE
;
287 if (addr6
->sin6_addr
.u
.Word
[5] != 0xffff) return FALSE
;
289 addr4
->sin_family
= WS_AF_INET
;
290 addr4
->sin_port
= addr6
->sin6_port
;
291 addr4
->sin_addr
.S_un
.S_addr
= addr6
->sin6_addr
.u
.Word
[6] << 16 | addr6
->sin6_addr
.u
.Word
[7];
292 memset( &addr4
->sin_zero
, 0, sizeof(addr4
->sin_zero
) );
297 static BOOL
find_src_address( MIB_IPADDRTABLE
*table
, const SOCKADDR_IN
*dst
, SOCKADDR_IN6
*src
)
299 MIB_IPFORWARDROW row
;
302 if (GetBestRoute( dst
->sin_addr
.S_un
.S_addr
, 0, &row
)) return FALSE
;
304 for (i
= 0; i
< table
->dwNumEntries
; i
++)
306 /* take the first address */
307 if (table
->table
[i
].dwIndex
== row
.dwForwardIfIndex
)
309 src
->sin6_family
= WS_AF_INET6
;
311 src
->sin6_flowinfo
= 0;
312 for (j
= 0; j
< 5; j
++) src
->sin6_addr
.u
.Word
[j
] = 0;
313 src
->sin6_addr
.u
.Word
[5] = 0xffff;
314 src
->sin6_addr
.u
.Word
[6] = table
->table
[i
].dwAddr
& 0xffff;
315 src
->sin6_addr
.u
.Word
[7] = table
->table
[i
].dwAddr
>> 16;
323 /******************************************************************
324 * CreateSortedAddressPairs (IPHLPAPI.@)
326 DWORD WINAPI
CreateSortedAddressPairs( const PSOCKADDR_IN6 src_list
, DWORD src_count
,
327 const PSOCKADDR_IN6 dst_list
, DWORD dst_count
,
328 DWORD options
, PSOCKADDR_IN6_PAIR
*pair_list
,
332 SOCKADDR_IN6_PAIR
*pairs
;
335 MIB_IPADDRTABLE
*table
;
337 FIXME( "(src_list %p src_count %u dst_list %p dst_count %u options %x pair_list %p pair_count %p): stub\n",
338 src_list
, src_count
, dst_list
, dst_count
, options
, pair_list
, pair_count
);
340 if (src_list
|| src_count
|| !dst_list
|| !pair_list
|| !pair_count
|| dst_count
> 500)
341 return ERROR_INVALID_PARAMETER
;
343 for (i
= 0; i
< dst_count
; i
++)
345 if (!map_address_6to4( &dst_list
[i
], &addr4
))
347 FIXME("only mapped IPv4 addresses are supported\n");
348 return ERROR_NOT_SUPPORTED
;
352 size
= dst_count
* sizeof(*pairs
);
353 size
+= dst_count
* sizeof(SOCKADDR_IN6
) * 2; /* source address + destination address */
354 if (!(pairs
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_NOT_ENOUGH_MEMORY
;
355 ptr
= (SOCKADDR_IN6
*)&pairs
[dst_count
];
357 if ((ret
= AllocateAndGetIpAddrTableFromStack( &table
, FALSE
, GetProcessHeap(), 0 )))
359 HeapFree( GetProcessHeap(), 0, pairs
);
363 for (i
= 0; i
< dst_count
; i
++)
365 pairs
[i
].SourceAddress
= ptr
++;
366 if (!map_address_6to4( &dst_list
[i
], &addr4
) ||
367 !find_src_address( table
, &addr4
, pairs
[i
].SourceAddress
))
370 FIXME( "source address for %s not found\n", debugstr_ipv6(&dst_list
[i
], buf
) );
371 memset( pairs
[i
].SourceAddress
, 0, sizeof(*pairs
[i
].SourceAddress
) );
372 pairs
[i
].SourceAddress
->sin6_family
= WS_AF_INET6
;
375 pairs
[i
].DestinationAddress
= ptr
++;
376 memcpy( pairs
[i
].DestinationAddress
, &dst_list
[i
], sizeof(*pairs
[i
].DestinationAddress
) );
379 *pair_count
= dst_count
;
381 HeapFree( GetProcessHeap(), 0, table
);
386 /******************************************************************
387 * DeleteIPAddress (IPHLPAPI.@)
389 * Delete an IP address added with AddIPAddress().
392 * NTEContext [In] NTE context from AddIPAddress();
396 * Failure: error code from winerror.h
399 * Stub, returns ERROR_NOT_SUPPORTED.
401 DWORD WINAPI
DeleteIPAddress(ULONG NTEContext
)
403 FIXME("(NTEContext %d): stub\n", NTEContext
);
404 return ERROR_NOT_SUPPORTED
;
408 /******************************************************************
409 * DeleteIpForwardEntry (IPHLPAPI.@)
414 * pRoute [In] route to delete
418 * Failure: error code from winerror.h
421 * Stub, returns NO_ERROR.
423 DWORD WINAPI
DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
425 FIXME("(pRoute %p): stub\n", pRoute
);
426 /* could use SIOCDELRT, not sure I want to */
431 /******************************************************************
432 * DeleteIpNetEntry (IPHLPAPI.@)
434 * Delete an ARP entry.
437 * pArpEntry [In] ARP entry to delete
441 * Failure: error code from winerror.h
444 * Stub, returns NO_ERROR.
446 DWORD WINAPI
DeleteIpNetEntry(PMIB_IPNETROW pArpEntry
)
448 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
449 /* could use SIOCDARP on systems that support it, not sure I want to */
454 /******************************************************************
455 * DeleteProxyArpEntry (IPHLPAPI.@)
457 * Delete a Proxy ARP entry.
460 * dwAddress [In] IP address for which this computer acts as a proxy.
461 * dwMask [In] subnet mask for dwAddress
462 * dwIfIndex [In] interface index
466 * Failure: error code from winerror.h
469 * Stub, returns ERROR_NOT_SUPPORTED.
471 DWORD WINAPI
DeleteProxyArpEntry(DWORD dwAddress
, DWORD dwMask
, DWORD dwIfIndex
)
473 FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
474 dwAddress
, dwMask
, dwIfIndex
);
475 return ERROR_NOT_SUPPORTED
;
479 /******************************************************************
480 * EnableRouter (IPHLPAPI.@)
482 * Turn on ip forwarding.
486 * pOverlapped [In/Out] hEvent member should contain a valid handle.
489 * Success: ERROR_IO_PENDING
490 * Failure: error code from winerror.h
493 * Stub, returns ERROR_NOT_SUPPORTED.
495 DWORD WINAPI
EnableRouter(HANDLE
* pHandle
, OVERLAPPED
* pOverlapped
)
497 FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle
, pOverlapped
);
498 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
499 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
501 return ERROR_NOT_SUPPORTED
;
505 /******************************************************************
506 * FlushIpNetTable (IPHLPAPI.@)
508 * Delete all ARP entries of an interface
511 * dwIfIndex [In] interface index
515 * Failure: error code from winerror.h
518 * Stub, returns ERROR_NOT_SUPPORTED.
520 DWORD WINAPI
FlushIpNetTable(DWORD dwIfIndex
)
522 FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex
);
523 /* this flushes the arp cache of the given index */
524 return ERROR_NOT_SUPPORTED
;
527 /******************************************************************
528 * FreeMibTable (IPHLPAPI.@)
530 * Free buffer allocated by network functions
533 * ptr [In] pointer to the buffer to free
536 void WINAPI
FreeMibTable(void *ptr
)
538 TRACE("(%p)\n", ptr
);
539 HeapFree(GetProcessHeap(), 0, ptr
);
542 /******************************************************************
543 * GetAdapterIndex (IPHLPAPI.@)
545 * Get interface index from its name.
548 * adapter_name [In] unicode string with the adapter name
549 * index [Out] returns found interface index
553 * Failure: error code from winerror.h
555 DWORD WINAPI
GetAdapterIndex( WCHAR
*adapter_name
, ULONG
*index
)
557 MIB_IFTABLE
*if_table
;
560 TRACE( "name %s, index %p\n", debugstr_w( adapter_name
), index
);
562 err
= AllocateAndGetIfTableFromStack( &if_table
, 0, GetProcessHeap(), 0 );
565 err
= ERROR_INVALID_PARAMETER
;
566 for (i
= 0; i
< if_table
->dwNumEntries
; i
++)
568 if (!strcmpW( adapter_name
, if_table
->table
[i
].wszName
))
570 *index
= if_table
->table
[i
].dwIndex
;
575 heap_free( if_table
);
579 static DWORD
get_wins_servers( SOCKADDR_INET
**servers
)
583 DWORD size
, i
, count
= 0;
584 static const char *values
[] = { "WinsServer", "BackupWinsServer" };
585 IN_ADDR addrs
[ARRAY_SIZE(values
)];
588 /* @@ Wine registry key: HKCU\Software\Wine\Network */
589 if (RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Network", &key
)) return 0;
591 for (i
= 0; i
< ARRAY_SIZE(values
); i
++)
594 if (!RegQueryValueExA( key
, values
[i
], NULL
, NULL
, (LPBYTE
)buf
, &size
))
595 if (!RtlIpv4StringToAddressA( buf
, TRUE
, NULL
, addrs
+ count
) &&
596 addrs
[count
].WS_s_addr
!= INADDR_NONE
&& addrs
[count
].WS_s_addr
!= INADDR_ANY
)
603 *servers
= heap_alloc_zero( count
* sizeof(**servers
) );
604 if (!*servers
) return 0;
605 for (i
= 0; i
< count
; i
++)
607 (*servers
)[i
].Ipv4
.sin_family
= WS_AF_INET
;
608 (*servers
)[i
].Ipv4
.sin_addr
= addrs
[i
];
614 static void ip_addr_string_init( IP_ADDR_STRING
*s
, const IN_ADDR
*addr
, const IN_ADDR
*mask
, DWORD ctxt
)
618 if (addr
) RtlIpv4AddressToStringA( addr
, s
->IpAddress
.String
);
619 else s
->IpAddress
.String
[0] = '\0';
620 if (mask
) RtlIpv4AddressToStringA( mask
, s
->IpMask
.String
);
621 else s
->IpMask
.String
[0] = '\0';
625 /******************************************************************
626 * GetAdaptersInfo (IPHLPAPI.@)
628 * Get information about adapters.
631 * info [Out] buffer for adapter infos
632 * size [In] length of output buffer
634 DWORD WINAPI
GetAdaptersInfo( IP_ADAPTER_INFO
*info
, ULONG
*size
)
636 DWORD err
, if_count
, if_num
= 0, uni_count
, fwd_count
, needed
, wins_server_count
;
637 DWORD len
, i
, uni
, fwd
;
638 NET_LUID
*if_keys
= NULL
;
639 struct nsi_ndis_ifinfo_rw
*if_rw
= NULL
;
640 struct nsi_ndis_ifinfo_dynamic
*if_dyn
= NULL
;
641 struct nsi_ndis_ifinfo_static
*if_stat
= NULL
;
642 struct nsi_ipv4_unicast_key
*uni_keys
= NULL
;
643 struct nsi_ip_unicast_rw
*uni_rw
= NULL
;
644 struct nsi_ipv4_forward_key
*fwd_keys
= NULL
;
645 SOCKADDR_INET
*wins_servers
= NULL
;
646 IP_ADDR_STRING
*extra_ip_addrs
, *cursor
;
649 TRACE( "info %p, size %p\n", info
, size
);
650 if (!size
) return ERROR_INVALID_PARAMETER
;
652 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
653 (void **)&if_keys
, sizeof(*if_keys
), (void **)&if_rw
, sizeof(*if_rw
),
654 (void **)&if_dyn
, sizeof(*if_dyn
), (void **)&if_stat
, sizeof(*if_stat
), &if_count
, 0 );
656 for (i
= 0; i
< if_count
; i
++)
658 if (if_stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
668 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
,
669 (void **)&uni_keys
, sizeof(*uni_keys
), (void **)&uni_rw
, sizeof(*uni_rw
),
670 NULL
, 0, NULL
, 0, &uni_count
, 0 );
673 /* Slightly overestimate the needed size by assuming that all
674 unicast addresses require a separate IP_ADDR_STRING. */
676 needed
= if_num
* sizeof(*info
) + uni_count
* sizeof(IP_ADDR_STRING
);
677 if (!info
|| *size
< needed
)
680 err
= ERROR_BUFFER_OVERFLOW
;
684 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_FORWARD_TABLE
,
685 (void **)&fwd_keys
, sizeof(*fwd_keys
), NULL
, 0,
686 NULL
, 0, NULL
, 0, &fwd_count
, 0 );
689 wins_server_count
= get_wins_servers( &wins_servers
);
691 extra_ip_addrs
= (IP_ADDR_STRING
*)(info
+ if_num
);
692 for (i
= 0; i
< if_count
; i
++)
694 if (if_stat
[i
].type
== IF_TYPE_SOFTWARE_LOOPBACK
) continue;
696 info
->Next
= info
+ 1;
697 info
->ComboIndex
= 0;
698 ConvertGuidToStringA( &if_stat
[i
].if_guid
, info
->AdapterName
, sizeof(info
->AdapterName
) );
699 len
= WideCharToMultiByte( CP_ACP
, 0, if_stat
[i
].descr
.String
, if_stat
[i
].descr
.Length
/ sizeof(WCHAR
),
700 info
->Description
, sizeof(info
->Description
) - 1, NULL
, NULL
);
701 info
->Description
[len
] = '\0';
702 info
->AddressLength
= if_rw
[i
].phys_addr
.Length
;
703 if (info
->AddressLength
> sizeof(info
->Address
)) info
->AddressLength
= 0;
704 memcpy( info
->Address
, if_rw
[i
].phys_addr
.Address
, info
->AddressLength
);
705 memset( info
->Address
+ info
->AddressLength
, 0, sizeof(info
->Address
) - info
->AddressLength
);
706 info
->Index
= if_stat
[i
].if_index
;
707 info
->Type
= if_stat
[i
].type
;
708 info
->DhcpEnabled
= TRUE
; /* FIXME */
709 info
->CurrentIpAddress
= NULL
;
712 for (uni
= 0; uni
< uni_count
; uni
++)
714 if (uni_keys
[uni
].luid
.Value
!= if_keys
[i
].Value
) continue;
715 if (!cursor
) cursor
= &info
->IpAddressList
;
718 cursor
->Next
= extra_ip_addrs
++;
719 cursor
= cursor
->Next
;
721 ConvertLengthToIpv4Mask( uni_rw
[uni
].on_link_prefix
, &mask
.WS_s_addr
);
722 ip_addr_string_init( cursor
, &uni_keys
[uni
].addr
, &mask
, 0 );
726 mask
.WS_s_addr
= INADDR_ANY
;
727 ip_addr_string_init( &info
->IpAddressList
, &mask
, &mask
, 0 );
730 gw
.WS_s_addr
= INADDR_ANY
;
731 mask
.WS_s_addr
= INADDR_NONE
;
732 for (fwd
= 0; fwd
< fwd_count
; fwd
++)
733 { /* find the first router on this interface */
734 if (fwd_keys
[fwd
].luid
.Value
== if_keys
[i
].Value
&&
735 fwd_keys
[fwd
].next_hop
.WS_s_addr
!= INADDR_ANY
&&
736 !fwd_keys
[fwd
].prefix_len
)
738 gw
= fwd_keys
[fwd
].next_hop
;
742 ip_addr_string_init( &info
->GatewayList
, &gw
, &mask
, 0 );
744 ip_addr_string_init( &info
->DhcpServer
, NULL
, NULL
, 0 );
746 info
->HaveWins
= !!wins_server_count
;
747 ip_addr_string_init( &info
->PrimaryWinsServer
, NULL
, NULL
, 0 );
748 ip_addr_string_init( &info
->SecondaryWinsServer
, NULL
, NULL
, 0 );
751 mask
.WS_s_addr
= INADDR_NONE
;
752 ip_addr_string_init( &info
->PrimaryWinsServer
, &wins_servers
[0].Ipv4
.sin_addr
, &mask
, 0 );
753 if (wins_server_count
> 1)
754 ip_addr_string_init( &info
->SecondaryWinsServer
, &wins_servers
[1].Ipv4
.sin_addr
, &mask
, 0 );
757 info
->LeaseObtained
= 0;
758 info
->LeaseExpires
= 0;
762 info
[-1].Next
= NULL
;
765 heap_free( wins_servers
);
766 NsiFreeTable( fwd_keys
, NULL
, NULL
, NULL
);
767 NsiFreeTable( uni_keys
, uni_rw
, NULL
, NULL
);
768 NsiFreeTable( if_keys
, if_rw
, if_dyn
, if_stat
);
772 static void address_entry_free( void *ptr
, ULONG offset
, void *ctxt
)
777 static void address_entry_size( void *ptr
, ULONG offset
, void *ctxt
)
779 IP_ADAPTER_DNS_SERVER_ADDRESS
*src_addr
= ptr
; /* all list types are super-sets of this type */
780 ULONG
*total
= (ULONG
*)ctxt
, align
= sizeof(ULONGLONG
) - 1;
782 *total
= (*total
+ src_addr
->u
.s
.Length
+ src_addr
->Address
.iSockaddrLength
+ align
) & ~align
;
785 struct address_entry_copy_params
787 IP_ADAPTER_ADDRESSES
*src
, *dst
;
793 static void address_entry_copy( void *ptr
, ULONG offset
, void *ctxt
)
795 struct address_entry_copy_params
*params
= ctxt
;
796 IP_ADAPTER_DNS_SERVER_ADDRESS
*src_addr
= ptr
; /* all list types are super-sets of this type */
797 IP_ADAPTER_DNS_SERVER_ADDRESS
*dst_addr
= (IP_ADAPTER_DNS_SERVER_ADDRESS
*)params
->ptr
;
798 ULONG align
= sizeof(ULONGLONG
) - 1;
800 memcpy( dst_addr
, src_addr
, src_addr
->u
.s
.Length
);
801 params
->ptr
+= src_addr
->u
.s
.Length
;
802 dst_addr
->Address
.lpSockaddr
= (SOCKADDR
*)params
->ptr
;
803 memcpy( dst_addr
->Address
.lpSockaddr
, src_addr
->Address
.lpSockaddr
, src_addr
->Address
.iSockaddrLength
);
804 params
->ptr
+= (src_addr
->Address
.iSockaddrLength
+ align
) & ~align
;
806 if (params
->cur_offset
!= offset
) /* new list */
808 params
->next
= (BYTE
*)params
->dst
+ offset
;
809 params
->cur_offset
= offset
;
811 *(IP_ADAPTER_DNS_SERVER_ADDRESS
**)params
->next
= dst_addr
;
812 params
->next
= &dst_addr
->Next
;
815 static void address_lists_iterate( IP_ADAPTER_ADDRESSES
*aa
, void (*fn
)(void *entry
, ULONG offset
, void *ctxt
), void *ctxt
)
817 IP_ADAPTER_UNICAST_ADDRESS
*uni
;
818 IP_ADAPTER_DNS_SERVER_ADDRESS
*dns
;
819 IP_ADAPTER_GATEWAY_ADDRESS
*gw
;
820 IP_ADAPTER_PREFIX
*prefix
;
823 for (uni
= aa
->FirstUnicastAddress
; uni
; uni
= next
)
826 fn( uni
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstUnicastAddress
), ctxt
);
829 for (dns
= aa
->FirstDnsServerAddress
; dns
; dns
= next
)
832 fn( dns
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstDnsServerAddress
), ctxt
);
835 for (gw
= aa
->FirstGatewayAddress
; gw
; gw
= next
)
838 fn( gw
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstGatewayAddress
), ctxt
);
841 for (prefix
= aa
->FirstPrefix
; prefix
; prefix
= next
)
844 fn( prefix
, FIELD_OFFSET( IP_ADAPTER_ADDRESSES
, FirstPrefix
), ctxt
);
848 void adapters_addresses_free( IP_ADAPTER_ADDRESSES
*info
)
850 IP_ADAPTER_ADDRESSES
*aa
;
852 for (aa
= info
; aa
; aa
= aa
->Next
)
854 address_lists_iterate( aa
, address_entry_free
, NULL
);
856 heap_free( aa
->DnsSuffix
);
861 ULONG
adapters_addresses_size( IP_ADAPTER_ADDRESSES
*info
)
863 IP_ADAPTER_ADDRESSES
*aa
;
864 ULONG size
= 0, align
= sizeof(ULONGLONG
) - 1;
866 for (aa
= info
; aa
; aa
= aa
->Next
)
868 size
+= sizeof(*aa
) + ((strlen( aa
->AdapterName
) + 1 + 1) & ~1);
869 size
+= (strlenW( aa
->Description
) + 1 + strlenW( aa
->DnsSuffix
) + 1) * sizeof(WCHAR
);
870 if (aa
->FriendlyName
) size
+= (strlenW(aa
->FriendlyName
) + 1) * sizeof(WCHAR
);
871 size
= (size
+ align
) & ~align
;
872 address_lists_iterate( aa
, address_entry_size
, &size
);
877 void adapters_addresses_copy( IP_ADAPTER_ADDRESSES
*dst
, IP_ADAPTER_ADDRESSES
*src
)
880 DWORD len
, align
= sizeof(ULONGLONG
) - 1;
881 struct address_entry_copy_params params
;
885 ptr
= (char *)(dst
+ 1);
887 dst
->AdapterName
= ptr
;
888 len
= strlen( src
->AdapterName
) + 1;
889 memcpy( dst
->AdapterName
, src
->AdapterName
, len
);
890 ptr
+= (len
+ 1) & ~1;
891 dst
->Description
= (WCHAR
*)ptr
;
892 len
= (strlenW( src
->Description
) + 1) * sizeof(WCHAR
);
893 memcpy( dst
->Description
, src
->Description
, len
);
895 dst
->DnsSuffix
= (WCHAR
*)ptr
;
896 len
= (strlenW( src
->DnsSuffix
) + 1) * sizeof(WCHAR
);
897 memcpy( dst
->DnsSuffix
, src
->DnsSuffix
, len
);
899 if (src
->FriendlyName
)
901 dst
->FriendlyName
= (WCHAR
*)ptr
;
902 len
= (strlenW( src
->FriendlyName
) + 1) * sizeof(WCHAR
);
903 memcpy( dst
->FriendlyName
, src
->FriendlyName
, len
);
906 ptr
= (char *)(((UINT_PTR
)ptr
+ align
) & ~align
);
912 params
.cur_offset
= ~0u;
913 address_lists_iterate( src
, address_entry_copy
, ¶ms
);
918 dst
->Next
= (IP_ADAPTER_ADDRESSES
*)ptr
;
925 static BOOL
sockaddr_is_loopback( SOCKADDR
*sock
)
927 if (sock
->sa_family
== WS_AF_INET
)
929 SOCKADDR_IN
*sin
= (SOCKADDR_IN
*)sock
;
930 return (sin
->sin_addr
.WS_s_addr
& 0xff) == 127;
932 else if (sock
->sa_family
== WS_AF_INET6
)
934 SOCKADDR_IN6
*sin6
= (SOCKADDR_IN6
*)sock
;
935 return WS_IN6_IS_ADDR_LOOPBACK( &sin6
->sin6_addr
);
940 static BOOL
sockaddr_is_linklocal( SOCKADDR
*sock
)
942 if (sock
->sa_family
== WS_AF_INET6
)
944 SOCKADDR_IN6
*sin6
= (SOCKADDR_IN6
*)sock
;
945 return WS_IN6_IS_ADDR_LINKLOCAL( &sin6
->sin6_addr
);
950 static BOOL
unicast_is_dns_eligible( IP_ADAPTER_UNICAST_ADDRESS
*uni
)
952 return !sockaddr_is_loopback( uni
->Address
.lpSockaddr
) &&
953 !sockaddr_is_linklocal( uni
->Address
.lpSockaddr
);
956 static DWORD
unicast_addresses_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
958 struct nsi_ipv4_unicast_key
*key4
;
959 struct nsi_ipv6_unicast_key
*key6
;
960 struct nsi_ip_unicast_rw
*rw
;
961 struct nsi_ip_unicast_dynamic
*dyn
;
962 struct nsi_ip_unicast_static
*stat
;
963 IP_ADAPTER_UNICAST_ADDRESS
*addr
, **next
;
964 DWORD err
, count
, i
, key_size
= (family
== WS_AF_INET
) ? sizeof(*key4
) : sizeof(*key6
);
965 DWORD sockaddr_size
= (family
== WS_AF_INET
) ? sizeof(SOCKADDR_IN
) : sizeof(SOCKADDR_IN6
);
969 err
= NsiAllocateAndGetTable( 1, ip_module_id( family
), NSI_IP_UNICAST_TABLE
, &key
, key_size
,
970 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
971 (void **)&stat
, sizeof(*stat
), &count
, 0 );
977 for (next
= &aa
->FirstUnicastAddress
; *next
; next
= &(*next
)->Next
)
980 for (i
= 0; i
< count
; i
++)
982 key4
= (struct nsi_ipv4_unicast_key
*)key
+ i
;
983 key6
= (struct nsi_ipv6_unicast_key
*)key
+ i
;
984 luid
= (family
== WS_AF_INET
) ? &key4
->luid
: &key6
->luid
;
985 if (luid
->Value
!= aa
->Luid
.Value
) continue;
986 addr
= heap_alloc_zero( sizeof(*addr
) + sockaddr_size
);
989 err
= ERROR_NOT_ENOUGH_MEMORY
;
992 addr
->u
.s
.Length
= sizeof(*addr
);
993 addr
->Address
.lpSockaddr
= (SOCKADDR
*)(addr
+ 1);
994 addr
->Address
.iSockaddrLength
= sockaddr_size
;
995 addr
->Address
.lpSockaddr
->sa_family
= family
;
996 if (family
== WS_AF_INET
)
998 SOCKADDR_IN
*in
= (SOCKADDR_IN
*)addr
->Address
.lpSockaddr
;
999 in
->sin_addr
= key4
->addr
;
1003 SOCKADDR_IN6
*in6
= (SOCKADDR_IN6
*)addr
->Address
.lpSockaddr
;
1004 in6
->sin6_addr
= key6
->addr
;
1005 in6
->sin6_scope_id
= dyn
[i
].scope_id
;
1007 addr
->PrefixOrigin
= rw
[i
].prefix_origin
;
1008 addr
->SuffixOrigin
= rw
[i
].suffix_origin
;
1009 addr
->DadState
= dyn
[i
].dad_state
;
1010 addr
->ValidLifetime
= rw
[i
].valid_lifetime
;
1011 addr
->PreferredLifetime
= rw
[i
].preferred_lifetime
;
1012 addr
->LeaseLifetime
= rw
[i
].valid_lifetime
; /* FIXME */
1013 addr
->OnLinkPrefixLength
= rw
[i
].on_link_prefix
;
1014 if (unicast_is_dns_eligible( addr
)) addr
->u
.s
.Flags
|= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE
;
1023 NsiFreeTable( key
, rw
, dyn
, stat
);
1027 static DWORD
gateway_and_prefix_addresses_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1029 struct nsi_ipv4_forward_key
*key4
;
1030 struct nsi_ipv6_forward_key
*key6
;
1031 IP_ADAPTER_GATEWAY_ADDRESS
*gw
, **gw_next
;
1032 IP_ADAPTER_PREFIX
*prefix
, **prefix_next
;
1033 DWORD err
, count
, i
, prefix_len
, key_size
= (family
== WS_AF_INET
) ? sizeof(*key4
) : sizeof(*key6
);
1034 DWORD sockaddr_size
= (family
== WS_AF_INET
) ? sizeof(SOCKADDR_IN
) : sizeof(SOCKADDR_IN6
);
1035 SOCKADDR_INET sockaddr
;
1039 err
= NsiAllocateAndGetTable( 1, ip_module_id( family
), NSI_IP_FORWARD_TABLE
, &key
, key_size
,
1040 NULL
, 0, NULL
, 0, NULL
, 0, &count
, 0 );
1041 if (err
) return err
;
1045 for (gw_next
= &aa
->FirstGatewayAddress
; *gw_next
; gw_next
= &(*gw_next
)->Next
)
1047 for (prefix_next
= &aa
->FirstPrefix
; *prefix_next
; prefix_next
= &(*prefix_next
)->Next
)
1050 for (i
= 0; i
< count
; i
++)
1052 key4
= (struct nsi_ipv4_forward_key
*)key
+ i
;
1053 key6
= (struct nsi_ipv6_forward_key
*)key
+ i
;
1054 luid
= (family
== WS_AF_INET
) ? &key4
->luid
: &key6
->luid
;
1055 if (luid
->Value
!= aa
->Luid
.Value
) continue;
1057 if (flags
& GAA_FLAG_INCLUDE_ALL_GATEWAYS
)
1059 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1060 if (family
== WS_AF_INET
)
1062 if (key4
->next_hop
.WS_s_addr
!= 0)
1064 sockaddr
.si_family
= family
;
1065 sockaddr
.Ipv4
.sin_addr
= key4
->next_hop
;
1070 static const IN6_ADDR zero
;
1071 if (memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1073 sockaddr
.si_family
= family
;
1074 sockaddr
.Ipv6
.sin6_addr
= key6
->next_hop
;
1078 if (sockaddr
.si_family
)
1080 gw
= heap_alloc_zero( sizeof(*gw
) + sockaddr_size
);
1083 err
= ERROR_NOT_ENOUGH_MEMORY
;
1086 gw
->u
.s
.Length
= sizeof(*gw
);
1087 gw
->Address
.lpSockaddr
= (SOCKADDR
*)(gw
+ 1);
1088 gw
->Address
.iSockaddrLength
= sockaddr_size
;
1089 memcpy( gw
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1091 gw_next
= &gw
->Next
;
1095 if (flags
& GAA_FLAG_INCLUDE_PREFIX
)
1097 memset( &sockaddr
, 0, sizeof(sockaddr
) );
1098 if (family
== WS_AF_INET
)
1100 if (!key4
->next_hop
.WS_s_addr
)
1102 sockaddr
.si_family
= family
;
1103 sockaddr
.Ipv4
.sin_addr
= key4
->prefix
;
1104 prefix_len
= key4
->prefix_len
;
1109 static const IN6_ADDR zero
;
1110 if (!memcmp( &key6
->next_hop
, &zero
, sizeof(zero
) ))
1112 sockaddr
.si_family
= family
;
1113 sockaddr
.Ipv6
.sin6_addr
= key6
->prefix
;
1114 prefix_len
= key6
->prefix_len
;
1118 if (sockaddr
.si_family
)
1120 prefix
= heap_alloc_zero( sizeof(*prefix
) + sockaddr_size
);
1123 err
= ERROR_NOT_ENOUGH_MEMORY
;
1126 prefix
->u
.s
.Length
= sizeof(*prefix
);
1127 prefix
->Address
.lpSockaddr
= (SOCKADDR
*)(prefix
+ 1);
1128 prefix
->Address
.iSockaddrLength
= sockaddr_size
;
1129 memcpy( prefix
->Address
.lpSockaddr
, &sockaddr
, sockaddr_size
);
1130 prefix
->PrefixLength
= prefix_len
;
1131 *prefix_next
= prefix
;
1132 prefix_next
= &prefix
->Next
;
1140 NsiFreeTable( key
, NULL
, NULL
, NULL
);
1144 static DWORD
call_families( DWORD (*fn
)( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
),
1145 IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1149 if (family
!= WS_AF_INET
)
1151 err
= fn( aa
, WS_AF_INET6
, flags
);
1152 if (err
) return err
;
1155 if (family
!= WS_AF_INET6
)
1157 err
= fn( aa
, WS_AF_INET
, flags
);
1158 if (err
) return err
;
1163 static DWORD
dns_servers_query_code( ULONG family
)
1165 if (family
== WS_AF_INET
) return DnsConfigDnsServersIpv4
;
1166 if (family
== WS_AF_INET6
) return DnsConfigDnsServersIpv6
;
1167 return DnsConfigDnsServersUnspec
;
1170 static DWORD
dns_info_alloc( IP_ADAPTER_ADDRESSES
*aa
, ULONG family
, ULONG flags
)
1172 char buf
[FIELD_OFFSET(DNS_ADDR_ARRAY
, AddrArray
[3])];
1173 IP_ADAPTER_DNS_SERVER_ADDRESS
*dns
, **next
;
1174 DWORD query
= dns_servers_query_code( family
);
1175 DWORD err
, i
, size
, attempt
, sockaddr_len
;
1176 WCHAR name
[MAX_ADAPTER_NAME_LENGTH
+ 1];
1177 DNS_ADDR_ARRAY
*servers
;
1178 DNS_TXT_DATAW
*search
;
1182 MultiByteToWideChar( CP_ACP
, 0, aa
->AdapterName
, -1, name
, ARRAY_SIZE(name
) );
1183 if (!(flags
& GAA_FLAG_SKIP_DNS_SERVER
))
1185 servers
= (DNS_ADDR_ARRAY
*)buf
;
1186 for (attempt
= 0; attempt
< 5; attempt
++)
1188 err
= DnsQueryConfig( query
, 0, name
, NULL
, servers
, &size
);
1189 if (err
!= ERROR_MORE_DATA
) break;
1190 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1191 servers
= heap_alloc( size
);
1194 err
= ERROR_NOT_ENOUGH_MEMORY
;
1200 next
= &aa
->FirstDnsServerAddress
;
1201 for (i
= 0; i
< servers
->AddrCount
; i
++)
1203 sockaddr_len
= servers
->AddrArray
[i
].Data
.DnsAddrUserDword
[0];
1204 if (sockaddr_len
> sizeof(servers
->AddrArray
[i
].MaxSa
))
1205 sockaddr_len
= sizeof(servers
->AddrArray
[i
].MaxSa
);
1206 dns
= heap_alloc_zero( sizeof(*dns
) + sockaddr_len
);
1209 err
= ERROR_NOT_ENOUGH_MEMORY
;
1212 dns
->u
.s
.Length
= sizeof(*dns
);
1213 dns
->Address
.lpSockaddr
= (SOCKADDR
*)(dns
+ 1);
1214 dns
->Address
.iSockaddrLength
= sockaddr_len
;
1215 memcpy( dns
->Address
.lpSockaddr
, servers
->AddrArray
[i
].MaxSa
, sockaddr_len
);
1220 if (servers
!= (DNS_ADDR_ARRAY
*)buf
) heap_free( servers
);
1224 aa
->DnsSuffix
= heap_alloc( MAX_DNS_SUFFIX_STRING_LENGTH
* sizeof(WCHAR
) );
1227 err
= ERROR_NOT_ENOUGH_MEMORY
;
1230 aa
->DnsSuffix
[0] = '\0';
1232 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, NULL
, &size
) &&
1233 (search
= heap_alloc( size
)))
1235 if (!DnsQueryConfig( DnsConfigSearchList
, 0, name
, NULL
, search
, &size
) &&
1236 search
->dwStringCount
&& strlenW( search
->pStringArray
[0] ) < MAX_DNS_SUFFIX_STRING_LENGTH
)
1238 strcpyW( aa
->DnsSuffix
, search
->pStringArray
[0] );
1240 heap_free( search
);
1250 static DWORD
adapters_addresses_alloc( ULONG family
, ULONG flags
, IP_ADAPTER_ADDRESSES
**info
)
1252 IP_ADAPTER_ADDRESSES
*aa
;
1254 struct nsi_ndis_ifinfo_rw
*rw
;
1255 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1256 struct nsi_ndis_ifinfo_static
*stat
;
1257 DWORD err
, i
, count
, needed
;
1261 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&luids
, sizeof(*luids
),
1262 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1263 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1264 if (err
) return err
;
1266 needed
= count
* (sizeof(*aa
) + ((CHARS_IN_GUID
+ 1) & ~1) + sizeof(stat
->descr
.String
));
1267 if (!(flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
)) needed
+= count
* sizeof(rw
->alias
.String
);
1269 aa
= heap_alloc_zero( needed
);
1272 err
= ERROR_NOT_ENOUGH_MEMORY
;
1276 str_ptr
= (char *)(aa
+ count
);
1277 for (i
= 0; i
< count
; i
++)
1279 aa
[i
].u
.s
.Length
= sizeof(*aa
);
1280 aa
[i
].u
.s
.IfIndex
= stat
[i
].if_index
;
1281 if (i
< count
- 1) aa
[i
].Next
= aa
+ i
+ 1;
1282 ConvertInterfaceLuidToGuid( luids
+ i
, &guid
);
1283 ConvertGuidToStringA( &guid
, str_ptr
, CHARS_IN_GUID
);
1284 aa
[i
].AdapterName
= str_ptr
;
1285 str_ptr
+= (CHARS_IN_GUID
+ 1) & ~1;
1286 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(stat
[i
].descr
.String
), &stat
[i
].descr
);
1287 aa
[i
].Description
= (WCHAR
*)str_ptr
;
1288 str_ptr
+= sizeof(stat
[i
].descr
.String
);
1289 if (!(flags
& GAA_FLAG_SKIP_FRIENDLY_NAME
))
1291 if_counted_string_copy( (WCHAR
*)str_ptr
, ARRAY_SIZE(rw
[i
].alias
.String
), &rw
[i
].alias
);
1292 aa
[i
].FriendlyName
= (WCHAR
*)str_ptr
;
1293 str_ptr
+= sizeof(rw
[i
].alias
.String
);
1295 aa
[i
].PhysicalAddressLength
= rw
->phys_addr
.Length
;
1296 if (aa
[i
].PhysicalAddressLength
> sizeof(aa
[i
].PhysicalAddress
)) aa
[i
].PhysicalAddressLength
= 0;
1297 memcpy( aa
[i
].PhysicalAddress
, rw
->phys_addr
.Address
, aa
[i
].PhysicalAddressLength
);
1298 aa
[i
].Mtu
= dyn
[i
].mtu
;
1299 aa
[i
].IfType
= stat
[i
].type
;
1300 aa
[i
].OperStatus
= dyn
[i
].oper_status
;
1301 aa
[i
].TransmitLinkSpeed
= dyn
[i
].xmit_speed
;
1302 aa
[i
].ReceiveLinkSpeed
= dyn
[i
].rcv_speed
;
1303 aa
[i
].Luid
= luids
[i
];
1304 aa
[i
].NetworkGuid
= rw
[i
].network_guid
;
1305 aa
[i
].ConnectionType
= stat
[i
].conn_type
;
1308 if (!(flags
& GAA_FLAG_SKIP_UNICAST
))
1310 err
= call_families( unicast_addresses_alloc
, aa
, family
, flags
);
1314 if (flags
& (GAA_FLAG_INCLUDE_ALL_GATEWAYS
| GAA_FLAG_INCLUDE_PREFIX
))
1316 err
= call_families( gateway_and_prefix_addresses_alloc
, aa
, family
, flags
);
1320 err
= dns_info_alloc( aa
, family
, flags
);
1324 NsiFreeTable( luids
, rw
, dyn
, stat
);
1325 if (!err
) *info
= aa
;
1326 else adapters_addresses_free( aa
);
1330 ULONG WINAPI DECLSPEC_HOTPATCH
GetAdaptersAddresses( ULONG family
, ULONG flags
, void *reserved
,
1331 IP_ADAPTER_ADDRESSES
*aa
, ULONG
*size
)
1333 IP_ADAPTER_ADDRESSES
*info
;
1336 TRACE( "(%d, %08x, %p, %p, %p)\n", family
, flags
, reserved
, aa
, size
);
1338 if (!size
) return ERROR_INVALID_PARAMETER
;
1340 err
= adapters_addresses_alloc( family
, flags
, &info
);
1341 if (err
) return err
;
1343 needed
= adapters_addresses_size( info
);
1344 if (!aa
|| *size
< needed
)
1347 err
= ERROR_BUFFER_OVERFLOW
;
1350 adapters_addresses_copy( aa
, info
);
1352 adapters_addresses_free( info
);
1356 /******************************************************************
1357 * GetBestInterface (IPHLPAPI.@)
1359 * Get the interface, with the best route for the given IP address.
1362 * dwDestAddr [In] IP address to search the interface for
1363 * pdwBestIfIndex [Out] found best interface
1367 * Failure: error code from winerror.h
1369 DWORD WINAPI
GetBestInterface(IPAddr dwDestAddr
, PDWORD pdwBestIfIndex
)
1371 struct WS_sockaddr_in sa_in
;
1372 memset(&sa_in
, 0, sizeof(sa_in
));
1373 sa_in
.sin_family
= WS_AF_INET
;
1374 sa_in
.sin_addr
.S_un
.S_addr
= dwDestAddr
;
1375 return GetBestInterfaceEx((struct WS_sockaddr
*)&sa_in
, pdwBestIfIndex
);
1378 /******************************************************************
1379 * GetBestInterfaceEx (IPHLPAPI.@)
1381 * Get the interface, with the best route for the given IP address.
1384 * dwDestAddr [In] IP address to search the interface for
1385 * pdwBestIfIndex [Out] found best interface
1389 * Failure: error code from winerror.h
1391 DWORD WINAPI
GetBestInterfaceEx(struct WS_sockaddr
*pDestAddr
, PDWORD pdwBestIfIndex
)
1395 TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr
, pdwBestIfIndex
);
1396 if (!pDestAddr
|| !pdwBestIfIndex
)
1397 ret
= ERROR_INVALID_PARAMETER
;
1399 MIB_IPFORWARDROW ipRow
;
1401 if (pDestAddr
->sa_family
== WS_AF_INET
) {
1402 ret
= GetBestRoute(((struct WS_sockaddr_in
*)pDestAddr
)->sin_addr
.S_un
.S_addr
, 0, &ipRow
);
1403 if (ret
== ERROR_SUCCESS
)
1404 *pdwBestIfIndex
= ipRow
.dwForwardIfIndex
;
1406 FIXME("address family %d not supported\n", pDestAddr
->sa_family
);
1407 ret
= ERROR_NOT_SUPPORTED
;
1410 TRACE("returning %d\n", ret
);
1415 /******************************************************************
1416 * GetBestRoute (IPHLPAPI.@)
1418 * Get the best route for the given IP address.
1421 * dwDestAddr [In] IP address to search the best route for
1422 * dwSourceAddr [In] optional source IP address
1423 * pBestRoute [Out] found best route
1427 * Failure: error code from winerror.h
1429 DWORD WINAPI
GetBestRoute(DWORD dwDestAddr
, DWORD dwSourceAddr
, PMIB_IPFORWARDROW pBestRoute
)
1431 PMIB_IPFORWARDTABLE table
;
1434 TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr
,
1435 dwSourceAddr
, pBestRoute
);
1437 return ERROR_INVALID_PARAMETER
;
1439 ret
= AllocateAndGetIpForwardTableFromStack(&table
, FALSE
, GetProcessHeap(), 0);
1441 DWORD ndx
, matchedBits
, matchedNdx
= table
->dwNumEntries
;
1443 for (ndx
= 0, matchedBits
= 0; ndx
< table
->dwNumEntries
; ndx
++) {
1444 if (table
->table
[ndx
].u1
.ForwardType
!= MIB_IPROUTE_TYPE_INVALID
&&
1445 (dwDestAddr
& table
->table
[ndx
].dwForwardMask
) ==
1446 (table
->table
[ndx
].dwForwardDest
& table
->table
[ndx
].dwForwardMask
)) {
1447 DWORD numShifts
, mask
;
1449 for (numShifts
= 0, mask
= table
->table
[ndx
].dwForwardMask
;
1450 mask
&& mask
& 1; mask
>>= 1, numShifts
++)
1452 if (numShifts
> matchedBits
) {
1453 matchedBits
= numShifts
;
1456 else if (!matchedBits
) {
1461 if (matchedNdx
< table
->dwNumEntries
) {
1462 memcpy(pBestRoute
, &table
->table
[matchedNdx
], sizeof(MIB_IPFORWARDROW
));
1463 ret
= ERROR_SUCCESS
;
1466 /* No route matches, which can happen if there's no default route. */
1467 ret
= ERROR_HOST_UNREACHABLE
;
1469 HeapFree(GetProcessHeap(), 0, table
);
1471 TRACE("returning %d\n", ret
);
1476 /******************************************************************
1477 * GetFriendlyIfIndex (IPHLPAPI.@)
1479 * Get a "friendly" version of IfIndex, which is one that doesn't
1480 * have the top byte set. Doesn't validate whether IfIndex is a valid
1484 * IfIndex [In] interface index to get the friendly one for
1487 * A friendly version of IfIndex.
1489 DWORD WINAPI
GetFriendlyIfIndex(DWORD IfIndex
)
1491 /* windows doesn't validate these, either, just makes sure the top byte is
1492 cleared. I assume my ifenum module never gives an index with the top
1494 TRACE("returning %d\n", IfIndex
);
1498 static void icmp_stats_ex_to_icmp_stats( MIBICMPSTATS_EX
*stats_ex
, MIBICMPSTATS
*stats
)
1500 stats
->dwMsgs
= stats_ex
->dwMsgs
;
1501 stats
->dwErrors
= stats_ex
->dwErrors
;
1502 stats
->dwDestUnreachs
= stats_ex
->rgdwTypeCount
[ICMP4_DST_UNREACH
];
1503 stats
->dwTimeExcds
= stats_ex
->rgdwTypeCount
[ICMP4_TIME_EXCEEDED
];
1504 stats
->dwParmProbs
= stats_ex
->rgdwTypeCount
[ICMP4_PARAM_PROB
];
1505 stats
->dwSrcQuenchs
= stats_ex
->rgdwTypeCount
[ICMP4_SOURCE_QUENCH
];
1506 stats
->dwRedirects
= stats_ex
->rgdwTypeCount
[ICMP4_REDIRECT
];
1507 stats
->dwEchos
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REQUEST
];
1508 stats
->dwEchoReps
= stats_ex
->rgdwTypeCount
[ICMP4_ECHO_REPLY
];
1509 stats
->dwTimestamps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
];
1510 stats
->dwTimestampReps
= stats_ex
->rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
];
1511 stats
->dwAddrMasks
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REQUEST
];
1512 stats
->dwAddrMaskReps
= stats_ex
->rgdwTypeCount
[ICMP4_MASK_REPLY
];
1515 /******************************************************************
1516 * GetIcmpStatistics (IPHLPAPI.@)
1518 * Get the ICMP statistics for the local computer.
1521 * stats [Out] buffer for ICMP statistics
1525 * Failure: error code from winerror.h
1527 DWORD WINAPI
GetIcmpStatistics( MIB_ICMP
*stats
)
1529 MIB_ICMP_EX stats_ex
;
1530 DWORD err
= GetIcmpStatisticsEx( &stats_ex
, WS_AF_INET
);
1532 if (err
) return err
;
1534 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpInStats
, &stats
->stats
.icmpInStats
);
1535 icmp_stats_ex_to_icmp_stats( &stats_ex
.icmpOutStats
, &stats
->stats
.icmpOutStats
);
1539 /******************************************************************
1540 * GetIcmpStatisticsEx (IPHLPAPI.@)
1542 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
1545 * stats [Out] buffer for ICMP statistics
1546 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1550 * Failure: error code from winerror.h
1552 DWORD WINAPI
GetIcmpStatisticsEx( MIB_ICMP_EX
*stats
, DWORD family
)
1554 const NPI_MODULEID
*mod
= ip_module_id( family
);
1555 struct nsi_ip_icmpstats_dynamic dyn
;
1558 if (!stats
|| !mod
) return ERROR_INVALID_PARAMETER
;
1559 memset( stats
, 0, sizeof(*stats
) );
1561 err
= NsiGetAllParameters( 1, mod
, NSI_IP_ICMPSTATS_TABLE
, NULL
, 0, NULL
, 0,
1562 &dyn
, sizeof(dyn
), NULL
, 0 );
1563 if (err
) return err
;
1565 stats
->icmpInStats
.dwMsgs
= dyn
.in_msgs
;
1566 stats
->icmpInStats
.dwErrors
= dyn
.in_errors
;
1567 memcpy( stats
->icmpInStats
.rgdwTypeCount
, dyn
.in_type_counts
, sizeof( dyn
.in_type_counts
) );
1568 stats
->icmpOutStats
.dwMsgs
= dyn
.out_msgs
;
1569 stats
->icmpOutStats
.dwErrors
= dyn
.out_errors
;
1570 memcpy( stats
->icmpOutStats
.rgdwTypeCount
, dyn
.out_type_counts
, sizeof( dyn
.out_type_counts
) );
1572 return ERROR_SUCCESS
;
1575 static void if_row_fill( MIB_IFROW
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1576 struct nsi_ndis_ifinfo_static
*stat
)
1578 static const WCHAR name_prefix
[] = {'\\','D','E','V','I','C','E','\\','T','C','P','I','P','_',0};
1580 memcpy( row
->wszName
, name_prefix
, sizeof(name_prefix
) );
1581 ConvertGuidToStringW( &stat
->if_guid
, row
->wszName
+ ARRAY_SIZE(name_prefix
) - 1, CHARS_IN_GUID
);
1582 row
->dwIndex
= stat
->if_index
;
1583 row
->dwType
= stat
->type
;
1584 row
->dwMtu
= dyn
->mtu
;
1585 row
->dwSpeed
= dyn
->rcv_speed
;
1586 row
->dwPhysAddrLen
= rw
->phys_addr
.Length
;
1587 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
1588 memcpy( row
->bPhysAddr
, rw
->phys_addr
.Address
, row
->dwPhysAddrLen
);
1589 row
->dwAdminStatus
= rw
->admin_status
;
1590 row
->dwOperStatus
= (dyn
->oper_status
== IfOperStatusUp
) ? MIB_IF_OPER_STATUS_OPERATIONAL
: MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
1591 row
->dwLastChange
= 0;
1592 row
->dwInOctets
= dyn
->in_octets
;
1593 row
->dwInUcastPkts
= dyn
->in_ucast_pkts
;
1594 row
->dwInNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1595 row
->dwInDiscards
= dyn
->in_discards
;
1596 row
->dwInErrors
= dyn
->in_errors
;
1597 row
->dwInUnknownProtos
= 0;
1598 row
->dwOutOctets
= dyn
->out_octets
;
1599 row
->dwOutUcastPkts
= dyn
->out_ucast_pkts
;
1600 row
->dwOutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1601 row
->dwOutDiscards
= dyn
->out_discards
;
1602 row
->dwOutErrors
= dyn
->out_errors
;
1604 row
->dwDescrLen
= WideCharToMultiByte( CP_ACP
, 0, stat
->descr
.String
, stat
->descr
.Length
/ sizeof(WCHAR
),
1605 (char *)row
->bDescr
, sizeof(row
->bDescr
) - 1, NULL
, NULL
);
1606 row
->bDescr
[row
->dwDescrLen
] = '\0';
1609 /******************************************************************
1610 * GetIfEntry (IPHLPAPI.@)
1612 * Get information about an interface.
1615 * pIfRow [In/Out] In: dwIndex of MIB_IFROW selects the interface.
1616 * Out: interface information
1620 * Failure: error code from winerror.h
1622 DWORD WINAPI
GetIfEntry( MIB_IFROW
*row
)
1624 struct nsi_ndis_ifinfo_rw rw
;
1625 struct nsi_ndis_ifinfo_dynamic dyn
;
1626 struct nsi_ndis_ifinfo_static stat
;
1630 TRACE( "row %p\n", row
);
1631 if (!row
) return ERROR_INVALID_PARAMETER
;
1633 err
= ConvertInterfaceIndexToLuid( row
->dwIndex
, &luid
);
1634 if (err
) return err
;
1636 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1637 &luid
, sizeof(luid
), &rw
, sizeof(rw
),
1638 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1639 if (!err
) if_row_fill( row
, &rw
, &dyn
, &stat
);
1643 static int ifrow_cmp( const void *a
, const void *b
)
1645 return ((const MIB_IFROW
*)a
)->dwIndex
- ((const MIB_IFROW
*)b
)->dwIndex
;
1648 /******************************************************************
1649 * GetIfTable (IPHLPAPI.@)
1651 * Get a table of local interfaces.
1654 * table [Out] buffer for local interfaces table
1655 * size [In/Out] length of output buffer
1656 * sort [In] whether to sort the table
1660 * Failure: error code from winerror.h
1663 * If size is less than required, the function will return
1664 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1666 * If sort is true, the returned table will be sorted by interface index.
1668 DWORD WINAPI
GetIfTable( MIB_IFTABLE
*table
, ULONG
*size
, BOOL sort
)
1670 DWORD i
, count
, needed
, err
;
1672 struct nsi_ndis_ifinfo_rw
*rw
;
1673 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1674 struct nsi_ndis_ifinfo_static
*stat
;
1676 if (!size
) return ERROR_INVALID_PARAMETER
;
1678 /* While this could be implemented on top of GetIfTable2(), it would require
1679 an additional copy of the data */
1680 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1681 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1682 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1683 if (err
) return err
;
1685 needed
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1687 if (!table
|| *size
< needed
)
1690 err
= ERROR_INSUFFICIENT_BUFFER
;
1694 table
->dwNumEntries
= count
;
1695 for (i
= 0; i
< count
; i
++)
1697 MIB_IFROW
*row
= table
->table
+ i
;
1699 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1702 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1705 NsiFreeTable( keys
, rw
, dyn
, stat
);
1709 /******************************************************************
1710 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
1712 * Get table of local interfaces.
1713 * Like GetIfTable(), but allocate the returned table from heap.
1716 * table [Out] pointer into which the MIB_IFTABLE is
1717 * allocated and returned.
1718 * sort [In] whether to sort the table
1719 * heap [In] heap from which the table is allocated
1720 * flags [In] flags to HeapAlloc
1723 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
1724 * GetIfTable() returns otherwise.
1726 DWORD WINAPI
AllocateAndGetIfTableFromStack( MIB_IFTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
1728 DWORD i
, count
, size
, err
;
1730 struct nsi_ndis_ifinfo_rw
*rw
;
1731 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1732 struct nsi_ndis_ifinfo_static
*stat
;
1734 if (!table
) return ERROR_INVALID_PARAMETER
;
1736 /* While this could be implemented on top of GetIfTable(), it would require
1737 an additional call to retrieve the size */
1738 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1739 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1740 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1741 if (err
) return err
;
1743 size
= FIELD_OFFSET( MIB_IFTABLE
, table
[count
] );
1744 *table
= HeapAlloc( heap
, flags
, size
);
1747 err
= ERROR_NOT_ENOUGH_MEMORY
;
1751 (*table
)->dwNumEntries
= count
;
1752 for (i
= 0; i
< count
; i
++)
1754 MIB_IFROW
*row
= (*table
)->table
+ i
;
1756 if_row_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1758 if (sort
) qsort( (*table
)->table
, count
, sizeof(MIB_IFROW
), ifrow_cmp
);
1761 NsiFreeTable( keys
, rw
, dyn
, stat
);
1765 static void if_row2_fill( MIB_IF_ROW2
*row
, struct nsi_ndis_ifinfo_rw
*rw
, struct nsi_ndis_ifinfo_dynamic
*dyn
,
1766 struct nsi_ndis_ifinfo_static
*stat
)
1768 row
->InterfaceIndex
= stat
->if_index
;
1769 row
->InterfaceGuid
= stat
->if_guid
;
1770 if_counted_string_copy( row
->Alias
, ARRAY_SIZE(row
->Alias
), &rw
->alias
);
1771 if_counted_string_copy( row
->Description
, ARRAY_SIZE(row
->Description
), &stat
->descr
);
1772 row
->PhysicalAddressLength
= rw
->phys_addr
.Length
;
1773 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
)) row
->PhysicalAddressLength
= 0;
1774 memcpy( row
->PhysicalAddress
, rw
->phys_addr
.Address
, row
->PhysicalAddressLength
);
1775 memcpy( row
->PermanentPhysicalAddress
, stat
->perm_phys_addr
.Address
, row
->PhysicalAddressLength
);
1776 row
->Mtu
= dyn
->mtu
;
1777 row
->Type
= stat
->type
;
1778 row
->TunnelType
= TUNNEL_TYPE_NONE
; /* fixme */
1779 row
->MediaType
= stat
->media_type
;
1780 row
->PhysicalMediumType
= stat
->phys_medium_type
;
1781 row
->AccessType
= stat
->access_type
;
1782 row
->DirectionType
= NET_IF_DIRECTION_SENDRECEIVE
; /* fixme */
1783 row
->InterfaceAndOperStatusFlags
.HardwareInterface
= stat
->flags
.hw
;
1784 row
->InterfaceAndOperStatusFlags
.FilterInterface
= stat
->flags
.filter
;
1785 row
->InterfaceAndOperStatusFlags
.ConnectorPresent
= !!stat
->conn_present
;
1786 row
->InterfaceAndOperStatusFlags
.NotAuthenticated
= 0; /* fixme */
1787 row
->InterfaceAndOperStatusFlags
.NotMediaConnected
= dyn
->flags
.not_media_conn
;
1788 row
->InterfaceAndOperStatusFlags
.Paused
= 0; /* fixme */
1789 row
->InterfaceAndOperStatusFlags
.LowPower
= 0; /* fixme */
1790 row
->InterfaceAndOperStatusFlags
.EndPointInterface
= 0; /* fixme */
1791 row
->OperStatus
= dyn
->oper_status
;
1792 row
->AdminStatus
= rw
->admin_status
;
1793 row
->MediaConnectState
= dyn
->media_conn_state
;
1794 row
->NetworkGuid
= rw
->network_guid
;
1795 row
->ConnectionType
= stat
->conn_type
;
1796 row
->TransmitLinkSpeed
= dyn
->xmit_speed
;
1797 row
->ReceiveLinkSpeed
= dyn
->rcv_speed
;
1798 row
->InOctets
= dyn
->in_octets
;
1799 row
->InUcastPkts
= dyn
->in_ucast_pkts
;
1800 row
->InNUcastPkts
= dyn
->in_bcast_pkts
+ dyn
->in_mcast_pkts
;
1801 row
->InDiscards
= dyn
->in_discards
;
1802 row
->InErrors
= dyn
->in_errors
;
1803 row
->InUnknownProtos
= 0; /* fixme */
1804 row
->InUcastOctets
= dyn
->in_ucast_octs
;
1805 row
->InMulticastOctets
= dyn
->in_mcast_octs
;
1806 row
->InBroadcastOctets
= dyn
->in_bcast_octs
;
1807 row
->OutOctets
= dyn
->out_octets
;
1808 row
->OutUcastPkts
= dyn
->out_ucast_pkts
;
1809 row
->OutNUcastPkts
= dyn
->out_bcast_pkts
+ dyn
->out_mcast_pkts
;
1810 row
->OutDiscards
= dyn
->out_discards
;
1811 row
->OutErrors
= dyn
->out_errors
;
1812 row
->OutUcastOctets
= dyn
->out_ucast_octs
;
1813 row
->OutMulticastOctets
= dyn
->out_mcast_octs
;
1814 row
->OutBroadcastOctets
= dyn
->out_bcast_octs
;
1815 row
->OutQLen
= 0; /* fixme */
1818 /******************************************************************
1819 * GetIfEntry2Ex (IPHLPAPI.@)
1821 DWORD WINAPI
GetIfEntry2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_ROW2
*row
)
1824 struct nsi_ndis_ifinfo_rw rw
;
1825 struct nsi_ndis_ifinfo_dynamic dyn
;
1826 struct nsi_ndis_ifinfo_static stat
;
1828 TRACE( "(%d, %p)\n", level
, row
);
1830 if (level
!= MibIfTableNormal
) FIXME( "level %u not fully supported\n", level
);
1831 if (!row
) return ERROR_INVALID_PARAMETER
;
1833 if (!row
->InterfaceLuid
.Value
)
1835 if (!row
->InterfaceIndex
) return ERROR_INVALID_PARAMETER
;
1836 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
1837 if (err
) return err
;
1840 err
= NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
,
1841 &row
->InterfaceLuid
, sizeof(row
->InterfaceLuid
),
1842 &rw
, sizeof(rw
), &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
1843 if (!err
) if_row2_fill( row
, &rw
, &dyn
, &stat
);
1847 /******************************************************************
1848 * GetIfEntry2 (IPHLPAPI.@)
1850 DWORD WINAPI
GetIfEntry2( MIB_IF_ROW2
*row
)
1852 return GetIfEntry2Ex( MibIfTableNormal
, row
);
1855 /******************************************************************
1856 * GetIfTable2Ex (IPHLPAPI.@)
1858 DWORD WINAPI
GetIfTable2Ex( MIB_IF_TABLE_LEVEL level
, MIB_IF_TABLE2
**table
)
1860 DWORD i
, count
, size
, err
;
1862 struct nsi_ndis_ifinfo_rw
*rw
;
1863 struct nsi_ndis_ifinfo_dynamic
*dyn
;
1864 struct nsi_ndis_ifinfo_static
*stat
;
1866 TRACE( "level %u, table %p\n", level
, table
);
1868 if (!table
|| level
> MibIfTableNormalWithoutStatistics
)
1869 return ERROR_INVALID_PARAMETER
;
1871 if (level
!= MibIfTableNormal
)
1872 FIXME("level %u not fully supported\n", level
);
1874 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
1875 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
1876 (void **)&stat
, sizeof(*stat
), &count
, 0 );
1877 if (err
) return err
;
1879 size
= FIELD_OFFSET( MIB_IF_TABLE2
, Table
[count
] );
1881 if (!(*table
= heap_alloc_zero( size
)))
1883 err
= ERROR_OUTOFMEMORY
;
1887 (*table
)->NumEntries
= count
;
1888 for (i
= 0; i
< count
; i
++)
1890 MIB_IF_ROW2
*row
= (*table
)->Table
+ i
;
1892 row
->InterfaceLuid
.Value
= keys
[i
].Value
;
1893 if_row2_fill( row
, rw
+ i
, dyn
+ i
, stat
+ i
);
1896 NsiFreeTable( keys
, rw
, dyn
, stat
);
1900 /******************************************************************
1901 * GetIfTable2 (IPHLPAPI.@)
1903 DWORD WINAPI
GetIfTable2( MIB_IF_TABLE2
**table
)
1905 TRACE( "table %p\n", table
);
1906 return GetIfTable2Ex( MibIfTableNormal
, table
);
1909 /******************************************************************
1910 * GetInterfaceInfo (IPHLPAPI.@)
1912 * Get a list of network interface adapters.
1915 * pIfTable [Out] buffer for interface adapters
1916 * dwOutBufLen [Out] if buffer is too small, returns required size
1920 * Failure: error code from winerror.h
1923 * MSDN states this should return non-loopback interfaces only.
1925 DWORD WINAPI
GetInterfaceInfo( IP_INTERFACE_INFO
*table
, ULONG
*size
)
1927 MIB_IFTABLE
*if_table
;
1928 DWORD err
, needed
, i
;
1930 TRACE("table %p, size %p\n", table
, size
);
1931 if (!size
) return ERROR_INVALID_PARAMETER
;
1933 err
= AllocateAndGetIfTableFromStack( &if_table
, 0, GetProcessHeap(), 0 );
1934 if (err
) return err
;
1936 needed
= FIELD_OFFSET(IP_INTERFACE_INFO
, Adapter
[if_table
->dwNumEntries
]);
1937 if (!table
|| *size
< needed
)
1940 heap_free( if_table
);
1941 return ERROR_INSUFFICIENT_BUFFER
;
1944 table
->NumAdapters
= if_table
->dwNumEntries
;
1945 for (i
= 0; i
< if_table
->dwNumEntries
; i
++)
1947 table
->Adapter
[i
].Index
= if_table
->table
[i
].dwIndex
;
1948 strcpyW( table
->Adapter
[i
].Name
, if_table
->table
[i
].wszName
);
1950 heap_free( if_table
);
1951 return ERROR_SUCCESS
;
1954 static int ipaddrrow_cmp( const void *a
, const void *b
)
1956 return ((const MIB_IPADDRROW
*)a
)->dwAddr
- ((const MIB_IPADDRROW
*)b
)->dwAddr
;
1959 /******************************************************************
1960 * GetIpAddrTable (IPHLPAPI.@)
1962 * Get interface-to-IP address mapping table.
1965 * table [Out] buffer for mapping table
1966 * size [In/Out] length of output buffer
1967 * sort [In] whether to sort the table
1971 * Failure: error code from winerror.h
1974 DWORD WINAPI
GetIpAddrTable( MIB_IPADDRTABLE
*table
, ULONG
*size
, BOOL sort
)
1976 DWORD err
, count
, needed
, i
, loopback
, row_num
= 0;
1977 struct nsi_ipv4_unicast_key
*keys
;
1978 struct nsi_ip_unicast_rw
*rw
;
1980 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
1981 if (!size
) return ERROR_INVALID_PARAMETER
;
1983 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&keys
, sizeof(*keys
),
1984 (void **)&rw
, sizeof(*rw
), NULL
, 0, NULL
, 0, &count
, 0 );
1985 if (err
) return err
;
1987 needed
= FIELD_OFFSET( MIB_IPADDRTABLE
, table
[count
] );
1989 if (!table
|| *size
< needed
)
1992 err
= ERROR_INSUFFICIENT_BUFFER
;
1996 table
->dwNumEntries
= count
;
1998 for (loopback
= 0; loopback
< 2; loopback
++) /* Move the loopback addresses to the end */
2000 for (i
= 0; i
< count
; i
++)
2002 MIB_IPADDRROW
*row
= table
->table
+ row_num
;
2004 if (!!loopback
!= (keys
[i
].luid
.Info
.IfType
== MIB_IF_TYPE_LOOPBACK
)) continue;
2006 row
->dwAddr
= keys
[i
].addr
.WS_s_addr
;
2007 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
2008 ConvertLengthToIpv4Mask( rw
[i
].on_link_prefix
, &row
->dwMask
);
2009 row
->dwBCastAddr
= 1;
2010 row
->dwReasmSize
= 0xffff;
2012 row
->wType
= MIB_IPADDR_PRIMARY
;
2017 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPADDRROW
), ipaddrrow_cmp
);
2019 NsiFreeTable( keys
, rw
, NULL
, NULL
);
2025 /******************************************************************
2026 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
2028 * Get interface-to-IP address mapping table.
2029 * Like GetIpAddrTable(), but allocate the returned table from heap.
2032 * table [Out] pointer into which the MIB_IPADDRTABLE is
2033 * allocated and returned.
2034 * sort [In] whether to sort the table
2035 * heap [In] heap from which the table is allocated
2036 * flags [In] flags to HeapAlloc
2039 DWORD WINAPI
AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2041 DWORD err
, size
= FIELD_OFFSET(MIB_IPADDRTABLE
, table
[2]), attempt
;
2043 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table
, sort
, heap
, flags
);
2045 for (attempt
= 0; attempt
< 5; attempt
++)
2047 *table
= HeapAlloc( heap
, flags
, size
);
2048 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2050 err
= GetIpAddrTable( *table
, &size
, sort
);
2052 HeapFree( heap
, flags
, *table
);
2053 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2059 static int ipforward_row_cmp( const void *a
, const void *b
)
2061 const MIB_IPFORWARDROW
*rowA
= a
;
2062 const MIB_IPFORWARDROW
*rowB
= b
;
2065 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
2066 if ((ret
= rowA
->u2
.dwForwardProto
- rowB
->u2
.dwForwardProto
) != 0) return ret
;
2067 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
2068 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
2071 /******************************************************************
2072 * GetIpForwardTable (IPHLPAPI.@)
2074 * Get the route table.
2077 * table [Out] buffer for route table
2078 * size [In/Out] length of output buffer
2079 * sort [In] whether to sort the table
2083 * Failure: error code from winerror.h
2085 DWORD WINAPI
GetIpForwardTable( MIB_IPFORWARDTABLE
*table
, ULONG
*size
, BOOL sort
)
2087 DWORD err
, count
, uni_count
, needed
, i
, addr
;
2088 struct nsi_ipv4_forward_key
*keys
;
2089 struct nsi_ip_forward_rw
*rw
;
2090 struct nsi_ipv4_forward_dynamic
*dyn
;
2091 struct nsi_ip_forward_static
*stat
;
2092 struct nsi_ipv4_unicast_key
*uni_keys
= NULL
;
2094 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2095 if (!size
) return ERROR_INVALID_PARAMETER
;
2097 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_FORWARD_TABLE
, (void **)&keys
, sizeof(*keys
),
2098 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2099 (void **)&stat
, sizeof(*stat
), &count
, 0 );
2100 if (err
) return err
;
2102 needed
= FIELD_OFFSET( MIB_IPFORWARDTABLE
, table
[count
] );
2104 if (!table
|| *size
< needed
)
2107 err
= ERROR_INSUFFICIENT_BUFFER
;
2111 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_UNICAST_TABLE
, (void **)&uni_keys
, sizeof(*uni_keys
),
2112 NULL
, 0, NULL
, 0, NULL
, 0, &uni_count
, 0 );
2115 table
->dwNumEntries
= count
;
2116 for (i
= 0; i
< count
; i
++)
2118 MIB_IPFORWARDROW
*row
= table
->table
+ i
;
2120 row
->dwForwardDest
= keys
[i
].prefix
.WS_s_addr
;
2121 ConvertLengthToIpv4Mask( keys
[i
].prefix_len
, &row
->dwForwardMask
);
2122 row
->dwForwardPolicy
= 0;
2123 row
->dwForwardNextHop
= keys
[i
].next_hop
.WS_s_addr
;
2124 row
->u1
.dwForwardType
= row
->dwForwardNextHop
? MIB_IPROUTE_TYPE_INDIRECT
: MIB_IPROUTE_TYPE_DIRECT
;
2125 if (!row
->dwForwardNextHop
) /* find the interface's addr */
2127 for (addr
= 0; addr
< uni_count
; addr
++)
2129 if (uni_keys
[addr
].luid
.Value
== keys
[i
].luid
.Value
)
2131 row
->dwForwardNextHop
= uni_keys
[addr
].addr
.WS_s_addr
;
2136 row
->dwForwardIfIndex
= stat
[i
].if_index
;
2137 row
->u2
.dwForwardProto
= rw
[i
].protocol
;
2138 row
->dwForwardAge
= dyn
[i
].age
;
2139 row
->dwForwardNextHopAS
= 0;
2140 row
->dwForwardMetric1
= rw
[i
].metric
; /* FIXME: add interface metric */
2141 row
->dwForwardMetric2
= 0;
2142 row
->dwForwardMetric3
= 0;
2143 row
->dwForwardMetric4
= 0;
2144 row
->dwForwardMetric5
= 0;
2147 if (sort
) qsort( table
->table
, count
, sizeof(MIB_IPFORWARDROW
), ipforward_row_cmp
);
2149 NsiFreeTable( uni_keys
, NULL
, NULL
, NULL
);
2150 NsiFreeTable( keys
, rw
, dyn
, stat
);
2155 /******************************************************************
2156 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
2158 * Get the route table.
2159 * Like GetIpForwardTable(), but allocate the returned table from heap.
2162 * table [Out] pointer into which the MIB_IPFORWARDTABLE is
2163 * allocated and returned.
2164 * sort [In] whether to sort the table
2165 * heap [In] heap from which the table is allocated
2166 * flags [In] flags to HeapAlloc
2169 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
2170 * on failure, NO_ERROR on success.
2172 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2174 DWORD err
, size
= FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[2]), attempt
;
2176 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table
, sort
, heap
, flags
);
2178 for (attempt
= 0; attempt
< 5; attempt
++)
2180 *table
= HeapAlloc( heap
, flags
, size
);
2181 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2183 err
= GetIpForwardTable( *table
, &size
, sort
);
2185 HeapFree( heap
, flags
, *table
);
2186 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2192 static void forward_row2_fill( MIB_IPFORWARD_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_forward_rw
*rw
,
2193 void *dyn
, struct nsi_ip_forward_static
*stat
)
2195 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
;
2196 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
;
2197 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
;
2198 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
;
2200 if (fam
== WS_AF_INET
)
2202 row
->InterfaceLuid
= key4
->luid
;
2203 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_family
= fam
;
2204 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_port
= 0;
2205 row
->DestinationPrefix
.Prefix
.Ipv4
.sin_addr
= key4
->prefix
;
2206 memset( &row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
, 0, sizeof(row
->DestinationPrefix
.Prefix
.Ipv4
.sin_zero
) );
2207 row
->DestinationPrefix
.PrefixLength
= key4
->prefix_len
;
2208 row
->NextHop
.Ipv4
.sin_family
= fam
;
2209 row
->NextHop
.Ipv4
.sin_port
= 0;
2210 row
->NextHop
.Ipv4
.sin_addr
= key4
->next_hop
;
2211 memset( &row
->NextHop
.Ipv4
.sin_zero
, 0, sizeof(row
->NextHop
.Ipv4
.sin_zero
) );
2213 row
->Age
= dyn4
->age
;
2217 row
->InterfaceLuid
= key6
->luid
;
2219 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_family
= fam
;
2220 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_port
= 0;
2221 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_flowinfo
= 0;
2222 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_addr
= key6
->prefix
;
2223 row
->DestinationPrefix
.Prefix
.Ipv6
.sin6_scope_id
= 0;
2224 row
->DestinationPrefix
.PrefixLength
= key6
->prefix_len
;
2225 row
->NextHop
.Ipv6
.sin6_family
= fam
;
2226 row
->NextHop
.Ipv6
.sin6_port
= 0;
2227 row
->NextHop
.Ipv6
.sin6_flowinfo
= 0;
2228 row
->NextHop
.Ipv6
.sin6_addr
= key6
->next_hop
;
2229 row
->NextHop
.Ipv6
.sin6_scope_id
= 0;
2231 row
->Age
= dyn6
->age
;
2234 row
->InterfaceIndex
= stat
->if_index
;
2236 row
->SitePrefixLength
= rw
->site_prefix_len
;
2237 row
->ValidLifetime
= rw
->valid_lifetime
;
2238 row
->PreferredLifetime
= rw
->preferred_lifetime
;
2239 row
->Metric
= rw
->metric
;
2240 row
->Protocol
= rw
->protocol
;
2241 row
->Loopback
= rw
->loopback
;
2242 row
->AutoconfigureAddress
= rw
->autoconf
;
2243 row
->Publish
= rw
->publish
;
2244 row
->Immortal
= rw
->immortal
;
2246 row
->Origin
= stat
->origin
;
2249 /******************************************************************
2250 * GetIpForwardTable2 (IPHLPAPI.@)
2252 DWORD WINAPI
GetIpForwardTable2( ADDRESS_FAMILY family
, MIB_IPFORWARD_TABLE2
**table
)
2254 void *key
[2] = { NULL
, NULL
};
2255 struct nsi_ip_forward_rw
*rw
[2] = { NULL
, NULL
};
2256 void *dyn
[2] = { NULL
, NULL
};
2257 struct nsi_ip_forward_static
*stat
[2] = { NULL
, NULL
};
2258 static const USHORT fam
[2] = { WS_AF_INET
, WS_AF_INET6
};
2259 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_forward_key
), sizeof(struct nsi_ipv6_forward_key
) };
2260 static const DWORD dyn_size
[2] = { sizeof(struct nsi_ipv4_forward_dynamic
), sizeof(struct nsi_ipv6_forward_dynamic
) };
2261 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2263 TRACE( "%u, %p\n", family
, table
);
2265 if (!table
|| (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
&& family
!= WS_AF_UNSPEC
))
2266 return ERROR_INVALID_PARAMETER
;
2268 for (i
= 0; i
< 2; i
++)
2270 if (family
!= WS_AF_UNSPEC
&& family
!= fam
[i
]) continue;
2272 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_FORWARD_TABLE
, key
+ i
, key_size
[i
],
2273 (void **)rw
+ i
, sizeof(**rw
), dyn
+ i
, dyn_size
[i
],
2274 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
2275 if (err
) count
[i
] = 0;
2278 size
= FIELD_OFFSET(MIB_IPFORWARD_TABLE2
, Table
[ count
[0] + count
[1] ]);
2279 *table
= heap_alloc( size
);
2282 err
= ERROR_NOT_ENOUGH_MEMORY
;
2286 (*table
)->NumEntries
= count
[0] + count
[1];
2287 for (i
= 0; i
< count
[0]; i
++)
2289 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ i
;
2290 struct nsi_ipv4_forward_key
*key4
= (struct nsi_ipv4_forward_key
*)key
[0];
2291 struct nsi_ipv4_forward_dynamic
*dyn4
= (struct nsi_ipv4_forward_dynamic
*)dyn
[0];
2293 forward_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn4
+ i
, stat
[0] + i
);
2296 for (i
= 0; i
< count
[1]; i
++)
2298 MIB_IPFORWARD_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2299 struct nsi_ipv6_forward_key
*key6
= (struct nsi_ipv6_forward_key
*)key
[1];
2300 struct nsi_ipv6_forward_dynamic
*dyn6
= (struct nsi_ipv6_forward_dynamic
*)dyn
[1];
2302 forward_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn6
+ i
, stat
[1] + i
);
2306 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
2310 static int ipnetrow_cmp( const void *a
, const void *b
)
2312 const MIB_IPNETROW
*row_a
= a
;
2313 const MIB_IPNETROW
*row_b
= b
;
2315 return RtlUlongByteSwap( row_a
->dwAddr
) - RtlUlongByteSwap( row_b
->dwAddr
);
2318 /******************************************************************
2319 * GetIpNetTable (IPHLPAPI.@)
2321 * Get the IP-to-physical address mapping table.
2324 * table [Out] buffer for mapping table
2325 * size [In/Out] length of output buffer
2326 * sort [In] whether to sort the table
2330 * Failure: error code from winerror.h
2333 DWORD WINAPI
GetIpNetTable( MIB_IPNETTABLE
*table
, ULONG
*size
, BOOL sort
)
2335 DWORD err
, count
, needed
, i
;
2336 struct nsi_ipv4_neighbour_key
*keys
;
2337 struct nsi_ip_neighbour_rw
*rw
;
2338 struct nsi_ip_neighbour_dynamic
*dyn
;
2340 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
2342 if (!size
) return ERROR_INVALID_PARAMETER
;
2344 err
= NsiAllocateAndGetTable( 1, &NPI_MS_IPV4_MODULEID
, NSI_IP_NEIGHBOUR_TABLE
, (void **)&keys
, sizeof(*keys
),
2345 (void **)&rw
, sizeof(*rw
), (void **)&dyn
, sizeof(*dyn
),
2346 NULL
, 0, &count
, 0 );
2347 if (err
) return err
;
2349 needed
= FIELD_OFFSET( MIB_IPNETTABLE
, table
[count
] );
2351 if (!table
|| *size
< needed
)
2354 err
= ERROR_INSUFFICIENT_BUFFER
;
2358 table
->dwNumEntries
= count
;
2359 for (i
= 0; i
< count
; i
++)
2361 MIB_IPNETROW
*row
= table
->table
+ i
;
2363 ConvertInterfaceLuidToIndex( &keys
[i
].luid
, &row
->dwIndex
);
2364 row
->dwPhysAddrLen
= dyn
[i
].phys_addr_len
;
2365 if (row
->dwPhysAddrLen
> sizeof(row
->bPhysAddr
)) row
->dwPhysAddrLen
= 0;
2366 memcpy( row
->bPhysAddr
, rw
[i
].phys_addr
, row
->dwPhysAddrLen
);
2367 memset( row
->bPhysAddr
+ row
->dwPhysAddrLen
, 0,
2368 sizeof(row
->bPhysAddr
) - row
->dwPhysAddrLen
);
2369 row
->dwAddr
= keys
[i
].addr
.WS_s_addr
;
2372 case NlnsUnreachable
:
2373 case NlnsIncomplete
:
2374 row
->u
.Type
= MIB_IPNET_TYPE_INVALID
;
2380 row
->u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
2383 row
->u
.Type
= MIB_IPNET_TYPE_STATIC
;
2386 row
->u
.Type
= MIB_IPNET_TYPE_OTHER
;
2390 if (sort
) qsort( table
->table
, table
->dwNumEntries
, sizeof(*table
->table
), ipnetrow_cmp
);
2393 NsiFreeTable( keys
, rw
, dyn
, NULL
);
2397 /******************************************************************
2398 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
2400 DWORD WINAPI
AllocateAndGetIpNetTableFromStack( MIB_IPNETTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
2402 DWORD err
, size
= FIELD_OFFSET(MIB_IPNETTABLE
, table
[2]), attempt
;
2404 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table
, sort
, heap
, flags
);
2406 for (attempt
= 0; attempt
< 5; attempt
++)
2408 *table
= HeapAlloc( heap
, flags
, size
);
2409 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
2411 err
= GetIpNetTable( *table
, &size
, sort
);
2413 HeapFree( heap
, flags
, *table
);
2414 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
2420 static void ipnet_row2_fill( MIB_IPNET_ROW2
*row
, USHORT fam
, void *key
, struct nsi_ip_neighbour_rw
*rw
,
2421 struct nsi_ip_neighbour_dynamic
*dyn
)
2423 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
;
2424 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
;
2426 if (fam
== WS_AF_INET
)
2428 row
->Address
.Ipv4
.sin_family
= fam
;
2429 row
->Address
.Ipv4
.sin_port
= 0;
2430 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
2431 memset( &row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
2432 row
->InterfaceLuid
= key4
->luid
;
2436 row
->Address
.Ipv6
.sin6_family
= fam
;
2437 row
->Address
.Ipv6
.sin6_port
= 0;
2438 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
2439 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
2440 row
->Address
.Ipv6
.sin6_scope_id
= 0;
2441 row
->InterfaceLuid
= key6
->luid
;
2444 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
2446 row
->PhysicalAddressLength
= dyn
->phys_addr_len
;
2447 if (row
->PhysicalAddressLength
> sizeof(row
->PhysicalAddress
))
2448 row
->PhysicalAddressLength
= 0;
2449 memcpy( row
->PhysicalAddress
, rw
->phys_addr
, row
->PhysicalAddressLength
);
2450 memset( row
->PhysicalAddress
+ row
->PhysicalAddressLength
, 0,
2451 sizeof(row
->PhysicalAddress
) - row
->PhysicalAddressLength
);
2452 row
->State
= dyn
->state
;
2454 row
->u
.s
.IsRouter
= dyn
->flags
.is_router
;
2455 row
->u
.s
.IsUnreachable
= dyn
->flags
.is_unreachable
;
2456 row
->ReachabilityTime
.LastReachable
= dyn
->time
;
2459 /******************************************************************
2460 * GetIpNetTable2 (IPHLPAPI.@)
2462 DWORD WINAPI
GetIpNetTable2( ADDRESS_FAMILY family
, MIB_IPNET_TABLE2
**table
)
2464 void *key
[2] = { NULL
, NULL
};
2465 struct nsi_ip_neighbour_rw
*rw
[2] = { NULL
, NULL
};
2466 struct nsi_ip_neighbour_dynamic
*dyn
[2] = { NULL
, NULL
};
2467 static const USHORT fam
[2] = { WS_AF_INET
, WS_AF_INET6
};
2468 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_neighbour_key
), sizeof(struct nsi_ipv6_neighbour_key
) };
2469 DWORD err
= ERROR_SUCCESS
, i
, size
, count
[2] = { 0, 0 };
2471 TRACE( "%u, %p\n", family
, table
);
2473 if (!table
|| (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
&& family
!= WS_AF_UNSPEC
))
2474 return ERROR_INVALID_PARAMETER
;
2476 for (i
= 0; i
< 2; i
++)
2478 if (family
!= WS_AF_UNSPEC
&& family
!= fam
[i
]) continue;
2480 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_NEIGHBOUR_TABLE
, key
+ i
, key_size
[i
],
2481 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
2482 NULL
, 0, count
+ i
, 0 );
2483 if (err
) count
[i
] = 0;
2486 size
= FIELD_OFFSET(MIB_IPNET_TABLE2
, Table
[ count
[0] + count
[1] ]);
2487 *table
= heap_alloc( size
);
2490 err
= ERROR_NOT_ENOUGH_MEMORY
;
2494 (*table
)->NumEntries
= count
[0] + count
[1];
2495 for (i
= 0; i
< count
[0]; i
++)
2497 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ i
;
2498 struct nsi_ipv4_neighbour_key
*key4
= (struct nsi_ipv4_neighbour_key
*)key
[0];
2500 ipnet_row2_fill( row
, fam
[0], key4
+ i
, rw
[0] + i
, dyn
[0] + i
);
2503 for (i
= 0; i
< count
[1]; i
++)
2505 MIB_IPNET_ROW2
*row
= (*table
)->Table
+ count
[0] + i
;
2506 struct nsi_ipv6_neighbour_key
*key6
= (struct nsi_ipv6_neighbour_key
*)key
[1];
2508 ipnet_row2_fill( row
, fam
[1], key6
+ i
, rw
[1] + i
, dyn
[1] + i
);
2512 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], NULL
);
2516 /******************************************************************
2517 * GetIpStatistics (IPHLPAPI.@)
2519 * Get the IP statistics for the local computer.
2522 * stats [Out] buffer for IP statistics
2526 * Failure: error code from winerror.h
2528 DWORD WINAPI
GetIpStatistics( MIB_IPSTATS
*stats
)
2530 return GetIpStatisticsEx( stats
, WS_AF_INET
);
2533 /******************************************************************
2534 * GetIpStatisticsEx (IPHLPAPI.@)
2536 * Get the IPv4 and IPv6 statistics for the local computer.
2539 * stats [Out] buffer for IP statistics
2540 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2544 * Failure: error code from winerror.h
2546 DWORD WINAPI
GetIpStatisticsEx( MIB_IPSTATS
*stats
, DWORD family
)
2548 struct nsi_ip_ipstats_dynamic dyn
;
2549 struct nsi_ip_ipstats_static stat
;
2550 struct nsi_ip_cmpt_rw cmpt_rw
;
2551 struct nsi_ip_cmpt_dynamic cmpt_dyn
;
2552 const NPI_MODULEID
*mod
;
2553 DWORD err
, cmpt
= 1;
2555 TRACE( "%p %d\n", stats
, family
);
2557 if (!stats
) return ERROR_INVALID_PARAMETER
;
2558 mod
= ip_module_id( family
);
2559 if (!mod
) return ERROR_INVALID_PARAMETER
;
2561 memset( stats
, 0, sizeof(*stats
) );
2563 err
= NsiGetAllParameters( 1, mod
, NSI_IP_IPSTATS_TABLE
, NULL
, 0, NULL
, 0,
2564 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2565 if (err
) return err
;
2567 err
= NsiGetAllParameters( 1, mod
, NSI_IP_COMPARTMENT_TABLE
, &cmpt
, sizeof(cmpt
), &cmpt_rw
, sizeof(cmpt_rw
),
2568 &cmpt_dyn
, sizeof(cmpt_dyn
), NULL
, 0 );
2569 if (err
) return err
;
2571 stats
->u
.Forwarding
= cmpt_rw
.not_forwarding
+ 1;
2572 stats
->dwDefaultTTL
= cmpt_rw
.default_ttl
;
2573 stats
->dwInReceives
= dyn
.in_recv
;
2574 stats
->dwInHdrErrors
= dyn
.in_hdr_errs
;
2575 stats
->dwInAddrErrors
= dyn
.in_addr_errs
;
2576 stats
->dwForwDatagrams
= dyn
.fwd_dgrams
;
2577 stats
->dwInUnknownProtos
= dyn
.in_unk_protos
;
2578 stats
->dwInDiscards
= dyn
.in_discards
;
2579 stats
->dwInDelivers
= dyn
.in_delivers
;
2580 stats
->dwOutRequests
= dyn
.out_reqs
;
2581 stats
->dwRoutingDiscards
= dyn
.routing_discards
;
2582 stats
->dwOutDiscards
= dyn
.out_discards
;
2583 stats
->dwOutNoRoutes
= dyn
.out_no_routes
;
2584 stats
->dwReasmTimeout
= stat
.reasm_timeout
;
2585 stats
->dwReasmReqds
= dyn
.reasm_reqds
;
2586 stats
->dwReasmOks
= dyn
.reasm_oks
;
2587 stats
->dwReasmFails
= dyn
.reasm_fails
;
2588 stats
->dwFragOks
= dyn
.frag_oks
;
2589 stats
->dwFragFails
= dyn
.frag_fails
;
2590 stats
->dwFragCreates
= dyn
.frag_creates
;
2591 stats
->dwNumIf
= cmpt_dyn
.num_ifs
;
2592 stats
->dwNumAddr
= cmpt_dyn
.num_addrs
;
2593 stats
->dwNumRoutes
= cmpt_dyn
.num_routes
;
2598 /* Gets the DNS server list into the list beginning at list. Assumes that
2599 * a single server address may be placed at list if *len is at least
2600 * sizeof(IP_ADDR_STRING) long. Otherwise, list->Next is set to firstDynamic,
2601 * and assumes that all remaining DNS servers are contiguously located
2602 * beginning at second. On input, *len is assumed to be the total number
2603 * of bytes available for all DNS servers, and is ignored if list is NULL.
2604 * On return, *len is set to the total number of bytes required for all DNS
2606 * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
2607 * ERROR_SUCCESS otherwise.
2609 static DWORD
get_dns_server_list( const NET_LUID
*luid
, IP_ADDR_STRING
*list
, IP_ADDR_STRING
*second
, DWORD
*len
)
2611 char buf
[FIELD_OFFSET(IP4_ARRAY
, AddrArray
[3])];
2612 IP4_ARRAY
*servers
= (IP4_ARRAY
*)buf
;
2613 DWORD needed
, num
, err
, i
, array_len
= sizeof(buf
);
2614 IP_ADDR_STRING
*ptr
;
2616 if (luid
&& luid
->Info
.IfType
== MIB_IF_TYPE_LOOPBACK
) return ERROR_NO_DATA
;
2620 err
= DnsQueryConfig( DnsConfigDnsServerList
, 0, NULL
, NULL
, servers
, &array_len
);
2621 num
= (array_len
- FIELD_OFFSET(IP4_ARRAY
, AddrArray
[0])) / sizeof(IP4_ADDRESS
);
2622 needed
= num
* sizeof(IP_ADDR_STRING
);
2623 if (!list
|| *len
< needed
)
2626 err
= ERROR_BUFFER_OVERFLOW
;
2631 if ((char *)servers
!= buf
) heap_free( servers
);
2632 servers
= heap_alloc( array_len
);
2635 err
= ERROR_NOT_ENOUGH_MEMORY
;
2642 for (i
= 0, ptr
= list
; i
< num
; i
++, ptr
= ptr
->Next
)
2644 RtlIpv4AddressToStringA( (IN_ADDR
*)&servers
->AddrArray
[i
], ptr
->IpAddress
.String
);
2645 if (i
== num
- 1) ptr
->Next
= NULL
;
2646 else if (i
== 0) ptr
->Next
= second
;
2647 else ptr
->Next
= ptr
+ 1;
2651 if ((char *)servers
!= buf
) heap_free( servers
);
2655 /******************************************************************
2656 * GetNetworkParams (IPHLPAPI.@)
2658 * Get the network parameters for the local computer.
2661 * info [Out] buffer for network parameters
2662 * size [In/Out] length of output buffer
2666 * Failure: error code from winerror.h
2669 * If size is less than required, the function will return
2670 * ERROR_INSUFFICIENT_BUFFER, and size will be set to the required byte
2673 DWORD WINAPI
GetNetworkParams( FIXED_INFO
*info
, ULONG
*size
)
2675 DWORD needed
= sizeof(*info
), dns_size
, err
;
2676 MIB_IPSTATS ip_stats
;
2679 TRACE( "info %p, size %p\n", info
, size
);
2680 if (!size
) return ERROR_INVALID_PARAMETER
;
2682 if (get_dns_server_list( NULL
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2683 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2684 if (!info
|| *size
< needed
)
2687 return ERROR_BUFFER_OVERFLOW
;
2691 memset( info
, 0, needed
);
2692 needed
= sizeof(info
->HostName
);
2693 GetComputerNameExA( ComputerNameDnsHostname
, info
->HostName
, &needed
);
2694 needed
= sizeof(info
->DomainName
);
2695 GetComputerNameExA( ComputerNameDnsDomain
, info
->DomainName
, &needed
);
2696 get_dns_server_list( NULL
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2697 info
->CurrentDnsServer
= &info
->DnsServerList
;
2698 info
->NodeType
= HYBRID_NODETYPE
;
2699 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
2700 0, KEY_READ
, &key
);
2702 err
= RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters",
2703 0, KEY_READ
, &key
);
2706 needed
= sizeof(info
->ScopeId
);
2707 RegQueryValueExA( key
, "ScopeID", NULL
, NULL
, (BYTE
*)info
->ScopeId
, &needed
);
2711 if (!GetIpStatistics( &ip_stats
))
2712 info
->EnableRouting
= (ip_stats
.u
.Forwarding
== MIB_IP_FORWARDING
);
2714 return ERROR_SUCCESS
;
2718 /******************************************************************
2719 * GetNumberOfInterfaces (IPHLPAPI.@)
2721 * Get the number of interfaces.
2724 * pdwNumIf [Out] number of interfaces
2727 * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
2729 DWORD WINAPI
GetNumberOfInterfaces( DWORD
*count
)
2733 TRACE( "count %p\n", count
);
2734 if (!count
) return ERROR_INVALID_PARAMETER
;
2736 err
= NsiEnumerateObjectsAllParameters( 1, 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, NULL
, 0,
2737 NULL
, 0, NULL
, 0, NULL
, 0, &num
);
2738 *count
= err
? 0 : num
;
2742 /******************************************************************
2743 * GetPerAdapterInfo (IPHLPAPI.@)
2745 * Get information about an adapter corresponding to an interface.
2748 * IfIndex [In] interface info
2749 * pPerAdapterInfo [Out] buffer for per adapter info
2750 * pOutBufLen [In/Out] length of output buffer
2754 * Failure: error code from winerror.h
2756 DWORD WINAPI
GetPerAdapterInfo( ULONG index
, IP_PER_ADAPTER_INFO
*info
, ULONG
*size
)
2758 DWORD needed
= sizeof(*info
), dns_size
;
2761 TRACE( "(index %d, info %p, size %p)\n", index
, info
, size
);
2763 if (!size
) return ERROR_INVALID_PARAMETER
;
2764 if (ConvertInterfaceIndexToLuid( index
, &luid
)) return ERROR_NO_DATA
;
2766 if (get_dns_server_list( &luid
, NULL
, NULL
, &dns_size
) == ERROR_BUFFER_OVERFLOW
)
2767 needed
+= dns_size
- sizeof(IP_ADDR_STRING
);
2769 if (!info
|| *size
< needed
)
2772 return ERROR_BUFFER_OVERFLOW
;
2775 memset( info
, 0, needed
);
2776 get_dns_server_list( &luid
, &info
->DnsServerList
, (IP_ADDR_STRING
*)(info
+ 1), &dns_size
);
2777 info
->CurrentDnsServer
= &info
->DnsServerList
;
2779 /* FIXME Autoconfig: get unicast addresses and compare to 169.254.x.x */
2780 return ERROR_SUCCESS
;
2784 /******************************************************************
2785 * GetRTTAndHopCount (IPHLPAPI.@)
2787 * Get round-trip time (RTT) and hop count.
2791 * DestIpAddress [In] destination address to get the info for
2792 * HopCount [Out] retrieved hop count
2793 * MaxHops [In] maximum hops to search for the destination
2794 * RTT [Out] RTT in milliseconds
2801 * Stub, returns FALSE.
2803 BOOL WINAPI
GetRTTAndHopCount(IPAddr DestIpAddress
, PULONG HopCount
, ULONG MaxHops
, PULONG RTT
)
2805 FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
2806 DestIpAddress
, HopCount
, MaxHops
, RTT
);
2810 /******************************************************************
2811 * GetTcpStatistics (IPHLPAPI.@)
2813 * Get the TCP statistics for the local computer.
2816 * stats [Out] buffer for TCP statistics
2820 * Failure: error code from winerror.h
2822 DWORD WINAPI
GetTcpStatistics( MIB_TCPSTATS
*stats
)
2824 return GetTcpStatisticsEx( stats
, WS_AF_INET
);
2827 /******************************************************************
2828 * GetTcpStatisticsEx (IPHLPAPI.@)
2830 * Get the IPv4 and IPv6 TCP statistics for the local computer.
2833 * stats [Out] buffer for TCP statistics
2834 * family [In] specifies whether IPv4 or IPv6 statistics are returned
2838 * Failure: error code from winerror.h
2840 DWORD WINAPI
GetTcpStatisticsEx( MIB_TCPSTATS
*stats
, DWORD family
)
2842 struct nsi_tcp_stats_dynamic dyn
;
2843 struct nsi_tcp_stats_static stat
;
2844 USHORT key
= (USHORT
)family
;
2847 if (!stats
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
2848 memset( stats
, 0, sizeof(*stats
) );
2850 err
= NsiGetAllParameters( 1, &NPI_MS_TCP_MODULEID
, NSI_TCP_STATS_TABLE
, &key
, sizeof(key
), NULL
, 0,
2851 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
2852 if (err
) return err
;
2854 stats
->u
.RtoAlgorithm
= stat
.rto_algo
;
2855 stats
->dwRtoMin
= stat
.rto_min
;
2856 stats
->dwRtoMax
= stat
.rto_max
;
2857 stats
->dwMaxConn
= stat
.max_conns
;
2858 stats
->dwActiveOpens
= dyn
.active_opens
;
2859 stats
->dwPassiveOpens
= dyn
.passive_opens
;
2860 stats
->dwAttemptFails
= dyn
.attempt_fails
;
2861 stats
->dwEstabResets
= dyn
.est_rsts
;
2862 stats
->dwCurrEstab
= dyn
.cur_est
;
2863 stats
->dwInSegs
= (DWORD
)dyn
.in_segs
;
2864 stats
->dwOutSegs
= (DWORD
)dyn
.out_segs
;
2865 stats
->dwRetransSegs
= dyn
.retrans_segs
;
2866 stats
->dwInErrs
= dyn
.in_errs
;
2867 stats
->dwOutRsts
= dyn
.out_rsts
;
2868 stats
->dwNumConns
= dyn
.num_conns
;
2873 #define TCP_TABLE2 ~0u /* Internal tcp table for GetTcp(6)Table2() */
2875 static DWORD
tcp_table_id( ULONG table_class
)
2877 switch (table_class
)
2879 case TCP_TABLE_BASIC_LISTENER
:
2880 case TCP_TABLE_OWNER_PID_LISTENER
:
2881 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2882 return NSI_TCP_LISTEN_TABLE
;
2884 case TCP_TABLE_BASIC_CONNECTIONS
:
2885 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2886 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2887 return NSI_TCP_ESTAB_TABLE
;
2889 case TCP_TABLE_BASIC_ALL
:
2890 case TCP_TABLE_OWNER_PID_ALL
:
2891 case TCP_TABLE_OWNER_MODULE_ALL
:
2893 return NSI_TCP_ALL_TABLE
;
2896 ERR( "unhandled class %u\n", table_class
);
2901 static DWORD
tcp_table_size( ULONG family
, ULONG table_class
, DWORD row_count
, DWORD
*row_size
)
2903 switch (table_class
)
2905 case TCP_TABLE_BASIC_LISTENER
:
2906 case TCP_TABLE_BASIC_CONNECTIONS
:
2907 case TCP_TABLE_BASIC_ALL
:
2908 *row_size
= (family
== WS_AF_INET
) ? sizeof(MIB_TCPROW
) : sizeof(MIB_TCP6ROW
);
2909 return (family
== WS_AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE
, table
[row_count
]) :
2910 FIELD_OFFSET(MIB_TCP6TABLE
, table
[row_count
]);
2912 case TCP_TABLE_OWNER_PID_LISTENER
:
2913 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2914 case TCP_TABLE_OWNER_PID_ALL
:
2915 *row_size
= (family
== WS_AF_INET
) ? sizeof(MIB_TCPROW_OWNER_PID
) : sizeof(MIB_TCP6ROW_OWNER_PID
);
2916 return (family
== WS_AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID
, table
[row_count
]) :
2917 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID
, table
[row_count
]);
2919 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2920 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2921 case TCP_TABLE_OWNER_MODULE_ALL
:
2922 *row_size
= (family
== WS_AF_INET
) ? sizeof(MIB_TCPROW_OWNER_MODULE
) : sizeof(MIB_TCP6ROW_OWNER_MODULE
);
2923 return (family
== WS_AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE
, table
[row_count
]) :
2924 FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE
, table
[row_count
]);
2927 *row_size
= (family
== WS_AF_INET
) ? sizeof(MIB_TCPROW2
) : sizeof(MIB_TCP6ROW2
);
2928 return (family
== WS_AF_INET
) ? FIELD_OFFSET(MIB_TCPTABLE2
, table
[row_count
]) :
2929 FIELD_OFFSET(MIB_TCP6TABLE2
, table
[row_count
]);
2932 ERR( "unhandled class %u\n", table_class
);
2937 static void tcp_row_fill( void *table
, DWORD num
, ULONG family
, ULONG table_class
,
2938 struct nsi_tcp_conn_key
*key
, struct nsi_tcp_conn_dynamic
*dyn
,
2939 struct nsi_tcp_conn_static
*stat
)
2941 if (family
== WS_AF_INET
)
2943 switch (table_class
)
2945 case TCP_TABLE_BASIC_LISTENER
:
2946 case TCP_TABLE_BASIC_CONNECTIONS
:
2947 case TCP_TABLE_BASIC_ALL
:
2949 MIB_TCPROW
*row
= ((MIB_TCPTABLE
*)table
)->table
+ num
;
2950 row
->u
.dwState
= dyn
->state
;
2951 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.WS_s_addr
;
2952 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2953 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.WS_s_addr
;
2954 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2957 case TCP_TABLE_OWNER_PID_LISTENER
:
2958 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2959 case TCP_TABLE_OWNER_PID_ALL
:
2961 MIB_TCPROW_OWNER_PID
*row
= ((MIB_TCPTABLE_OWNER_PID
*)table
)->table
+ num
;
2962 row
->dwState
= dyn
->state
;
2963 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.WS_s_addr
;
2964 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2965 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.WS_s_addr
;
2966 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2967 row
->dwOwningPid
= stat
->pid
;
2970 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2971 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2972 case TCP_TABLE_OWNER_MODULE_ALL
:
2974 MIB_TCPROW_OWNER_MODULE
*row
= ((MIB_TCPTABLE_OWNER_MODULE
*)table
)->table
+ num
;
2975 row
->dwState
= dyn
->state
;
2976 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.WS_s_addr
;
2977 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2978 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.WS_s_addr
;
2979 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2980 row
->dwOwningPid
= stat
->pid
;
2981 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
2982 row
->OwningModuleInfo
[0] = stat
->mod_info
;
2983 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
2988 MIB_TCPROW2
*row
= ((MIB_TCPTABLE2
*)table
)->table
+ num
;
2989 row
->dwState
= dyn
->state
;
2990 row
->dwLocalAddr
= key
->local
.Ipv4
.sin_addr
.WS_s_addr
;
2991 row
->dwLocalPort
= key
->local
.Ipv4
.sin_port
;
2992 row
->dwRemoteAddr
= key
->remote
.Ipv4
.sin_addr
.WS_s_addr
;
2993 row
->dwRemotePort
= key
->remote
.Ipv4
.sin_port
;
2994 row
->dwOwningPid
= stat
->pid
;
2995 row
->dwOffloadState
= 0; /* FIXME */
2999 ERR( "Unknown class %d\n", table_class
);
3005 switch (table_class
)
3007 case TCP_TABLE_BASIC_LISTENER
:
3008 case TCP_TABLE_BASIC_CONNECTIONS
:
3009 case TCP_TABLE_BASIC_ALL
:
3011 MIB_TCP6ROW
*row
= ((MIB_TCP6TABLE
*)table
)->table
+ num
;
3012 row
->State
= dyn
->state
;
3013 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
3014 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3015 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3016 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
3017 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3018 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3021 case TCP_TABLE_OWNER_PID_LISTENER
:
3022 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
3023 case TCP_TABLE_OWNER_PID_ALL
:
3025 MIB_TCP6ROW_OWNER_PID
*row
= ((MIB_TCP6TABLE_OWNER_PID
*)table
)->table
+ num
;
3026 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3027 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3028 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3029 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3030 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3031 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3032 row
->dwState
= dyn
->state
;
3033 row
->dwOwningPid
= stat
->pid
;
3036 case TCP_TABLE_OWNER_MODULE_LISTENER
:
3037 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
3038 case TCP_TABLE_OWNER_MODULE_ALL
:
3040 MIB_TCP6ROW_OWNER_MODULE
*row
= ((MIB_TCP6TABLE_OWNER_MODULE
*)table
)->table
+ num
;
3041 memcpy( &row
->ucLocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->ucLocalAddr
) );
3042 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3043 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3044 memcpy( &row
->ucRemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->ucRemoteAddr
) );
3045 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3046 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3047 row
->dwState
= dyn
->state
;
3048 row
->dwOwningPid
= stat
->pid
;
3049 row
->liCreateTimestamp
.QuadPart
= stat
->create_time
;
3050 row
->OwningModuleInfo
[0] = stat
->mod_info
;
3051 memset( row
->OwningModuleInfo
+ 1, 0, sizeof(row
->OwningModuleInfo
) - sizeof(row
->OwningModuleInfo
[0]) );
3056 MIB_TCP6ROW2
*row
= ((MIB_TCP6TABLE2
*)table
)->table
+ num
;
3057 memcpy( &row
->LocalAddr
, &key
->local
.Ipv6
.sin6_addr
, sizeof(row
->LocalAddr
) );
3058 row
->dwLocalScopeId
= key
->local
.Ipv6
.sin6_scope_id
;
3059 row
->dwLocalPort
= key
->local
.Ipv6
.sin6_port
;
3060 memcpy( &row
->RemoteAddr
, &key
->remote
.Ipv6
.sin6_addr
, sizeof(row
->RemoteAddr
) );
3061 row
->dwRemoteScopeId
= key
->remote
.Ipv6
.sin6_scope_id
;
3062 row
->dwRemotePort
= key
->remote
.Ipv6
.sin6_port
;
3063 row
->State
= dyn
->state
;
3064 row
->dwOwningPid
= stat
->pid
;
3065 row
->dwOffloadState
= 0; /* FIXME */
3069 ERR( "Unknown class %d\n", table_class
);
3073 ERR( "Unknown family %d\n", family
);
3076 static int tcp_row_cmp( const void *a
, const void *b
)
3078 const MIB_TCPROW
*rowA
= a
;
3079 const MIB_TCPROW
*rowB
= b
;
3082 if ((ret
= RtlUlongByteSwap( rowA
->dwLocalAddr
) - RtlUlongByteSwap( rowB
->dwLocalAddr
)) != 0) return ret
;
3083 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3084 if ((ret
= RtlUlongByteSwap( rowA
->dwRemoteAddr
) - RtlUlongByteSwap( rowB
->dwRemoteAddr
)) != 0) return ret
;
3085 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3088 static int tcp6_row_basic_cmp( const void *a
, const void *b
)
3090 const MIB_TCP6ROW
*rowA
= a
;
3091 const MIB_TCP6ROW
*rowB
= b
;
3094 if ((ret
= memcmp( &rowA
->LocalAddr
, &rowB
->LocalAddr
, sizeof(rowA
->LocalAddr
) )) != 0) return ret
;
3095 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3096 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3097 if ((ret
= memcmp( &rowA
->RemoteAddr
, &rowB
->RemoteAddr
, sizeof(rowA
->RemoteAddr
) )) != 0) return ret
;
3098 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3099 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3102 static int tcp6_row_owner_cmp( const void *a
, const void *b
)
3104 const MIB_TCP6ROW_OWNER_PID
*rowA
= a
;
3105 const MIB_TCP6ROW_OWNER_PID
*rowB
= b
;
3108 if ((ret
= memcmp( &rowA
->ucLocalAddr
, &rowB
->ucLocalAddr
, sizeof(rowA
->ucLocalAddr
) )) != 0) return ret
;
3109 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
3110 if ((ret
= RtlUshortByteSwap( rowA
->dwLocalPort
) - RtlUshortByteSwap( rowB
->dwLocalPort
)) != 0) return ret
;
3111 if ((ret
= memcmp( &rowA
->ucRemoteAddr
, &rowB
->ucRemoteAddr
, sizeof(rowA
->ucRemoteAddr
) )) != 0) return ret
;
3112 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
3113 return RtlUshortByteSwap( rowA
->dwRemotePort
) - RtlUshortByteSwap( rowB
->dwRemotePort
);
3116 /*************************************************************************************
3117 * get_extended_tcp_table
3119 * Implementation of GetExtendedTcpTable() which additionally handles TCP_TABLE2
3120 * corresponding to GetTcp(6)Table2()
3122 DWORD
get_extended_tcp_table( void *table
, DWORD
*size
, BOOL sort
, ULONG family
, ULONG table_class
)
3124 DWORD err
, count
, needed
, i
, num
= 0, row_size
= 0;
3125 struct nsi_tcp_conn_key
*key
;
3126 struct nsi_tcp_conn_dynamic
*dyn
;
3127 struct nsi_tcp_conn_static
*stat
;
3129 if (!size
) return ERROR_INVALID_PARAMETER
;
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 (void **)&stat
, sizeof(*stat
), &count
, 0 );
3134 if (err
) return err
;
3136 for (i
= 0; i
< count
; i
++)
3137 if (key
[i
].local
.si_family
== family
)
3140 needed
= tcp_table_size( family
, table_class
, num
, &row_size
);
3141 if (!table
|| *size
< needed
)
3144 err
= ERROR_INSUFFICIENT_BUFFER
;
3149 *(DWORD
*)table
= num
;
3151 for (i
= 0; i
< count
; i
++)
3153 if (key
[i
].local
.si_family
!= family
) continue;
3154 tcp_row_fill( table
, num
++, family
, table_class
, key
+ i
, dyn
+ i
, stat
+ i
);
3160 int (*fn
)(const void *, const void *);
3163 if (family
== WS_AF_INET
) fn
= tcp_row_cmp
;
3164 else if (row_size
== sizeof(MIB_TCP6ROW
)) fn
= tcp6_row_basic_cmp
;
3165 else fn
= tcp6_row_owner_cmp
;
3167 offset
= tcp_table_size( family
, table_class
, 0, &row_size
);
3168 qsort( (BYTE
*)table
+ offset
, num
, row_size
, fn
);
3171 NsiFreeTable( key
, NULL
, dyn
, stat
);
3175 /******************************************************************
3176 * GetExtendedTcpTable (IPHLPAPI.@)
3178 DWORD WINAPI
GetExtendedTcpTable( void *table
, DWORD
*size
, BOOL sort
, ULONG family
,
3179 TCP_TABLE_CLASS table_class
, ULONG reserved
)
3181 TRACE( "table %p, size %p, sort %d, family %u, class %u, reserved %u\n",
3182 table
, size
, sort
, family
, table_class
, reserved
);
3184 if (!ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3185 return get_extended_tcp_table( table
, size
, sort
, family
, table_class
);
3188 /******************************************************************
3189 * GetTcpTable (IPHLPAPI.@)
3191 * Get the table of active TCP connections.
3194 * table [Out] buffer for TCP connections table
3195 * size [In/Out] length of output buffer
3196 * sort [In] whether to order the table
3200 * Failure: error code from winerror.h
3203 * If size is less than required, the function will return
3204 * ERROR_INSUFFICIENT_BUFFER, and *size will be set to
3205 * the required byte size.
3206 * If sort is true, the returned table will be sorted, first by
3207 * local address and port number, then by remote address and port
3210 DWORD WINAPI
GetTcpTable( MIB_TCPTABLE
*table
, DWORD
*size
, BOOL sort
)
3212 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3213 return get_extended_tcp_table( table
, size
, sort
, WS_AF_INET
, TCP_TABLE_BASIC_ALL
);
3216 /******************************************************************
3217 * GetTcp6Table (IPHLPAPI.@)
3219 ULONG WINAPI
GetTcp6Table( MIB_TCP6TABLE
*table
, ULONG
*size
, BOOL sort
)
3221 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3222 return get_extended_tcp_table( table
, size
, sort
, WS_AF_INET6
, TCP_TABLE_BASIC_ALL
);
3225 /******************************************************************
3226 * GetTcpTable2 (IPHLPAPI.@)
3228 ULONG WINAPI
GetTcpTable2( MIB_TCPTABLE2
*table
, ULONG
*size
, BOOL sort
)
3230 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3231 return get_extended_tcp_table( table
, size
, sort
, WS_AF_INET
, TCP_TABLE2
);
3234 /******************************************************************
3235 * GetTcp6Table2 (IPHLPAPI.@)
3237 ULONG WINAPI
GetTcp6Table2( MIB_TCP6TABLE2
*table
, ULONG
*size
, BOOL sort
)
3239 TRACE( "table %p, size %p, sort %d\n", table
, size
, sort
);
3240 return get_extended_tcp_table( table
, size
, sort
, WS_AF_INET6
, TCP_TABLE2
);
3243 static DWORD
allocate_tcp_table( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
,
3244 ULONG family
, ULONG table_class
)
3246 DWORD err
, size
= 0x100, attempt
;
3248 for (attempt
= 0; attempt
< 5; attempt
++)
3250 *table
= HeapAlloc( heap
, flags
, size
);
3251 if (!*table
) return ERROR_NOT_ENOUGH_MEMORY
;
3252 err
= get_extended_tcp_table( *table
, &size
, sort
, family
, table_class
);
3254 HeapFree( heap
, flags
, *table
);
3256 if (err
!= ERROR_INSUFFICIENT_BUFFER
) break;
3261 /******************************************************************
3262 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
3264 DWORD WINAPI
AllocateAndGetTcpTableFromStack( MIB_TCPTABLE
**table
, BOOL sort
, HANDLE heap
, DWORD flags
)
3266 TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table
, sort
, heap
, flags
);
3268 if (!table
) return ERROR_INVALID_PARAMETER
;
3270 return allocate_tcp_table( (void **)table
, sort
, heap
, flags
, WS_AF_INET
, TCP_TABLE_BASIC_ALL
);
3273 /******************************************************************
3274 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
3276 DWORD WINAPI
AllocateAndGetTcpExTableFromStack( void **table
, BOOL sort
, HANDLE heap
, DWORD flags
, DWORD family
)
3278 TRACE( "table %p, sort %d, heap %p, flags 0x%08x, family %u\n", table
, sort
, heap
, flags
, family
);
3280 if (!table
|| !ip_module_id( family
)) return ERROR_INVALID_PARAMETER
;
3281 if (family
== WS_AF_INET6
) return ERROR_NOT_SUPPORTED
;
3283 return allocate_tcp_table( table
, sort
, heap
, flags
, family
, TCP_TABLE_OWNER_PID_ALL
);
3286 /******************************************************************
3287 * GetUdpTable (IPHLPAPI.@)
3289 * Get a table of active UDP connections.
3292 * pUdpTable [Out] buffer for UDP connections table
3293 * pdwSize [In/Out] length of output buffer
3294 * bOrder [In] whether to order the table
3298 * Failure: error code from winerror.h
3301 * If pdwSize is less than required, the function will return
3302 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
3303 * required byte size.
3304 * If bOrder is true, the returned table will be sorted, first by
3305 * local address, then by local port number.
3307 DWORD WINAPI
GetUdpTable(PMIB_UDPTABLE pUdpTable
, PDWORD pdwSize
, BOOL bOrder
)
3309 return GetExtendedUdpTable(pUdpTable
, pdwSize
, bOrder
, WS_AF_INET
, UDP_TABLE_BASIC
, 0);
3312 /******************************************************************
3313 * GetUdp6Table (IPHLPAPI.@)
3315 DWORD WINAPI
GetUdp6Table(PMIB_UDP6TABLE pUdpTable
, PDWORD pdwSize
, BOOL bOrder
)
3317 return GetExtendedUdpTable(pUdpTable
, pdwSize
, bOrder
, WS_AF_INET6
, UDP_TABLE_BASIC
, 0);
3320 /******************************************************************
3321 * GetExtendedUdpTable (IPHLPAPI.@)
3323 DWORD WINAPI
GetExtendedUdpTable(PVOID pUdpTable
, PDWORD pdwSize
, BOOL bOrder
,
3324 ULONG ulAf
, UDP_TABLE_CLASS TableClass
, ULONG Reserved
)
3329 TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
3330 pUdpTable
, pdwSize
, bOrder
, ulAf
, TableClass
, Reserved
);
3332 if (!pdwSize
) return ERROR_INVALID_PARAMETER
;
3334 if (TableClass
== UDP_TABLE_OWNER_MODULE
)
3335 FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
3340 ret
= build_udp_table(TableClass
, &table
, bOrder
, GetProcessHeap(), 0, &size
);
3344 ret
= build_udp6_table(TableClass
, &table
, bOrder
, GetProcessHeap(), 0, &size
);
3348 FIXME("ulAf = %u not supported\n", ulAf
);
3349 ret
= ERROR_NOT_SUPPORTED
;
3355 if (!pUdpTable
|| *pdwSize
< size
)
3358 ret
= ERROR_INSUFFICIENT_BUFFER
;
3363 memcpy(pUdpTable
, table
, size
);
3365 HeapFree(GetProcessHeap(), 0, table
);
3369 static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW
*row
, USHORT fam
, void *key
, struct nsi_ip_unicast_rw
*rw
,
3370 struct nsi_ip_unicast_dynamic
*dyn
, struct nsi_ip_unicast_static
*stat
)
3372 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
;
3373 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
;
3375 if (fam
== WS_AF_INET
)
3377 row
->Address
.Ipv4
.sin_family
= fam
;
3378 row
->Address
.Ipv4
.sin_port
= 0;
3379 row
->Address
.Ipv4
.sin_addr
= key4
->addr
;
3380 memset( row
->Address
.Ipv4
.sin_zero
, 0, sizeof(row
->Address
.Ipv4
.sin_zero
) );
3381 row
->InterfaceLuid
.Value
= key4
->luid
.Value
;
3385 row
->Address
.Ipv6
.sin6_family
= fam
;
3386 row
->Address
.Ipv6
.sin6_port
= 0;
3387 row
->Address
.Ipv6
.sin6_flowinfo
= 0;
3388 row
->Address
.Ipv6
.sin6_addr
= key6
->addr
;
3389 row
->Address
.Ipv6
.sin6_scope_id
= dyn
->scope_id
;
3390 row
->InterfaceLuid
.Value
= key6
->luid
.Value
;
3393 ConvertInterfaceLuidToIndex( &row
->InterfaceLuid
, &row
->InterfaceIndex
);
3394 row
->PrefixOrigin
= rw
->prefix_origin
;
3395 row
->SuffixOrigin
= rw
->suffix_origin
;
3396 row
->ValidLifetime
= rw
->valid_lifetime
;
3397 row
->PreferredLifetime
= rw
->preferred_lifetime
;
3398 row
->OnLinkPrefixLength
= rw
->on_link_prefix
;
3399 row
->SkipAsSource
= 0;
3400 row
->DadState
= dyn
->dad_state
;
3401 row
->ScopeId
.u
.Value
= dyn
->scope_id
;
3402 row
->CreationTimeStamp
.QuadPart
= stat
->creation_time
;
3405 DWORD WINAPI
GetUnicastIpAddressEntry(MIB_UNICASTIPADDRESS_ROW
*row
)
3407 struct nsi_ipv4_unicast_key key4
;
3408 struct nsi_ipv6_unicast_key key6
;
3409 struct nsi_ip_unicast_rw rw
;
3410 struct nsi_ip_unicast_dynamic dyn
;
3411 struct nsi_ip_unicast_static stat
;
3412 const NPI_MODULEID
*mod
;
3413 DWORD err
, key_size
;
3416 TRACE( "%p\n", row
);
3418 if (!row
) return ERROR_INVALID_PARAMETER
;
3419 mod
= ip_module_id( row
->Address
.si_family
);
3420 if (!mod
) return ERROR_INVALID_PARAMETER
;
3422 if (!row
->InterfaceLuid
.Value
)
3424 err
= ConvertInterfaceIndexToLuid( row
->InterfaceIndex
, &row
->InterfaceLuid
);
3425 if (err
) return err
;
3428 if (row
->Address
.si_family
== WS_AF_INET
)
3430 key4
.luid
= row
->InterfaceLuid
;
3431 key4
.addr
= row
->Address
.Ipv4
.sin_addr
;
3434 key_size
= sizeof(key4
);
3436 else if (row
->Address
.si_family
== WS_AF_INET6
)
3438 key6
.luid
= row
->InterfaceLuid
;
3439 key6
.addr
= row
->Address
.Ipv6
.sin6_addr
;
3441 key_size
= sizeof(key6
);
3443 else return ERROR_INVALID_PARAMETER
;
3445 err
= NsiGetAllParameters( 1, mod
, NSI_IP_UNICAST_TABLE
, key
, key_size
, &rw
, sizeof(rw
),
3446 &dyn
, sizeof(dyn
), &stat
, sizeof(stat
) );
3447 if (!err
) unicast_row_fill( row
, row
->Address
.si_family
, key
, &rw
, &dyn
, &stat
);
3451 DWORD WINAPI
GetUnicastIpAddressTable(ADDRESS_FAMILY family
, MIB_UNICASTIPADDRESS_TABLE
**table
)
3453 void *key
[2] = { NULL
, NULL
};
3454 struct nsi_ip_unicast_rw
*rw
[2] = { NULL
, NULL
};
3455 struct nsi_ip_unicast_dynamic
*dyn
[2] = { NULL
, NULL
};
3456 struct nsi_ip_unicast_static
*stat
[2] = { NULL
, NULL
};
3457 static const USHORT fam
[2] = { WS_AF_INET
, WS_AF_INET6
};
3458 static const DWORD key_size
[2] = { sizeof(struct nsi_ipv4_unicast_key
), sizeof(struct nsi_ipv6_unicast_key
) };
3459 DWORD err
, i
, size
, count
[2] = { 0, 0 };
3461 TRACE( "%u, %p\n", family
, table
);
3463 if (!table
|| (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
&& family
!= WS_AF_UNSPEC
))
3464 return ERROR_INVALID_PARAMETER
;
3466 for (i
= 0; i
< 2; i
++)
3468 if (family
!= WS_AF_UNSPEC
&& family
!= fam
[i
]) continue;
3470 err
= NsiAllocateAndGetTable( 1, ip_module_id( fam
[i
] ), NSI_IP_UNICAST_TABLE
, key
+ i
, key_size
[i
],
3471 (void **)rw
+ i
, sizeof(**rw
), (void **)dyn
+ i
, sizeof(**dyn
),
3472 (void **)stat
+ i
, sizeof(**stat
), count
+ i
, 0 );
3476 size
= FIELD_OFFSET(MIB_UNICASTIPADDRESS_TABLE
, Table
[ count
[0] + count
[1] ]);
3477 *table
= heap_alloc( size
);
3480 err
= ERROR_NOT_ENOUGH_MEMORY
;
3484 (*table
)->NumEntries
= count
[0] + count
[1];
3485 for (i
= 0; i
< count
[0]; i
++)
3487 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ i
;
3488 struct nsi_ipv4_unicast_key
*key4
= (struct nsi_ipv4_unicast_key
*)key
[0];
3490 unicast_row_fill( row
, fam
[0], (void *)(key4
+ i
), rw
[0] + i
, dyn
[0] + i
, stat
[0] + i
);
3493 for (i
= 0; i
< count
[1]; i
++)
3495 MIB_UNICASTIPADDRESS_ROW
*row
= (*table
)->Table
+ count
[0] + i
;
3496 struct nsi_ipv6_unicast_key
*key6
= (struct nsi_ipv6_unicast_key
*)key
[1];
3498 unicast_row_fill( row
, fam
[1], (void *)(key6
+ i
), rw
[1] + i
, dyn
[1] + i
, stat
[1] + i
);
3502 for (i
= 0; i
< 2; i
++) NsiFreeTable( key
[i
], rw
[i
], dyn
[i
], stat
[i
] );
3506 /******************************************************************
3507 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
3509 * This is a Win98-only function to get information on "unidirectional"
3510 * adapters. Since this is pretty nonsensical in other contexts, it
3511 * never returns anything.
3514 * pIPIfInfo [Out] buffer for adapter infos
3515 * dwOutBufLen [Out] length of the output buffer
3519 * Failure: error code from winerror.h
3522 * Stub, returns ERROR_NOT_SUPPORTED.
3524 DWORD WINAPI
GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo
, PULONG dwOutBufLen
)
3526 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo
, dwOutBufLen
);
3527 /* a unidirectional adapter?? not bloody likely! */
3528 return ERROR_NOT_SUPPORTED
;
3532 /******************************************************************
3533 * IpReleaseAddress (IPHLPAPI.@)
3535 * Release an IP obtained through DHCP,
3538 * AdapterInfo [In] adapter to release IP address
3542 * Failure: error code from winerror.h
3545 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3546 * this function does nothing.
3549 * Stub, returns ERROR_NOT_SUPPORTED.
3551 DWORD WINAPI
IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3553 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3554 return ERROR_NOT_SUPPORTED
;
3558 /******************************************************************
3559 * IpRenewAddress (IPHLPAPI.@)
3561 * Renew an IP obtained through DHCP.
3564 * AdapterInfo [In] adapter to renew IP address
3568 * Failure: error code from winerror.h
3571 * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
3572 * this function does nothing.
3575 * Stub, returns ERROR_NOT_SUPPORTED.
3577 DWORD WINAPI
IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo
)
3579 FIXME("Stub AdapterInfo %p\n", AdapterInfo
);
3580 return ERROR_NOT_SUPPORTED
;
3584 /******************************************************************
3585 * NotifyAddrChange (IPHLPAPI.@)
3587 * Notify caller whenever the ip-interface map is changed.
3590 * Handle [Out] handle usable in asynchronous notification
3591 * overlapped [In] overlapped structure that notifies the caller
3595 * Failure: error code from winerror.h
3598 * Stub, returns ERROR_NOT_SUPPORTED.
3600 DWORD WINAPI
NotifyAddrChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3602 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
3603 if (Handle
) *Handle
= INVALID_HANDLE_VALUE
;
3604 if (overlapped
) ((IO_STATUS_BLOCK
*) overlapped
)->u
.Status
= STATUS_PENDING
;
3605 return ERROR_IO_PENDING
;
3609 /******************************************************************
3610 * NotifyIpInterfaceChange (IPHLPAPI.@)
3612 DWORD WINAPI
NotifyIpInterfaceChange(ADDRESS_FAMILY family
, PIPINTERFACE_CHANGE_CALLBACK callback
,
3613 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3615 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3616 family
, callback
, context
, init_notify
, handle
);
3617 if (handle
) *handle
= NULL
;
3621 /******************************************************************
3622 * NotifyRouteChange2 (IPHLPAPI.@)
3624 DWORD WINAPI
NotifyRouteChange2(ADDRESS_FAMILY family
, PIPFORWARD_CHANGE_CALLBACK callback
, VOID
* context
,
3625 BOOLEAN init_notify
, HANDLE
* handle
)
3627 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): stub\n",
3628 family
, callback
, context
, init_notify
, handle
);
3629 if (handle
) *handle
= NULL
;
3634 /******************************************************************
3635 * NotifyRouteChange (IPHLPAPI.@)
3637 * Notify caller whenever the ip routing table is changed.
3640 * Handle [Out] handle usable in asynchronous notification
3641 * overlapped [In] overlapped structure that notifies the caller
3645 * Failure: error code from winerror.h
3648 * Stub, returns ERROR_NOT_SUPPORTED.
3650 DWORD WINAPI
NotifyRouteChange(PHANDLE Handle
, LPOVERLAPPED overlapped
)
3652 FIXME("(Handle %p, overlapped %p): stub\n", Handle
, overlapped
);
3653 return ERROR_NOT_SUPPORTED
;
3657 /******************************************************************
3658 * NotifyUnicastIpAddressChange (IPHLPAPI.@)
3660 DWORD WINAPI
NotifyUnicastIpAddressChange(ADDRESS_FAMILY family
, PUNICAST_IPADDRESS_CHANGE_CALLBACK callback
,
3661 PVOID context
, BOOLEAN init_notify
, PHANDLE handle
)
3663 FIXME("(family %d, callback %p, context %p, init_notify %d, handle %p): semi-stub\n",
3664 family
, callback
, context
, init_notify
, handle
);
3665 if (handle
) *handle
= NULL
;
3668 callback(context
, NULL
, MibInitialNotification
);
3673 /******************************************************************
3674 * SendARP (IPHLPAPI.@)
3676 * Send an ARP request.
3679 * DestIP [In] attempt to obtain this IP
3680 * SrcIP [In] optional sender IP address
3681 * pMacAddr [Out] buffer for the mac address
3682 * PhyAddrLen [In/Out] length of the output buffer
3686 * Failure: error code from winerror.h
3689 * Stub, returns ERROR_NOT_SUPPORTED.
3691 DWORD WINAPI
SendARP(IPAddr DestIP
, IPAddr SrcIP
, PULONG pMacAddr
, PULONG PhyAddrLen
)
3693 FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
3694 DestIP
, SrcIP
, pMacAddr
, PhyAddrLen
);
3695 return ERROR_NOT_SUPPORTED
;
3699 /******************************************************************
3700 * SetIfEntry (IPHLPAPI.@)
3702 * Set the administrative status of an interface.
3705 * pIfRow [In] dwAdminStatus member specifies the new status.
3709 * Failure: error code from winerror.h
3712 * Stub, returns ERROR_NOT_SUPPORTED.
3714 DWORD WINAPI
SetIfEntry(PMIB_IFROW pIfRow
)
3716 FIXME("(pIfRow %p): stub\n", pIfRow
);
3717 /* this is supposed to set an interface administratively up or down.
3718 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
3719 this sort of down is indistinguishable from other sorts of down (e.g. no
3721 return ERROR_NOT_SUPPORTED
;
3725 /******************************************************************
3726 * SetIpForwardEntry (IPHLPAPI.@)
3728 * Modify an existing route.
3731 * pRoute [In] route with the new information
3735 * Failure: error code from winerror.h
3738 * Stub, returns NO_ERROR.
3740 DWORD WINAPI
SetIpForwardEntry(PMIB_IPFORWARDROW pRoute
)
3742 FIXME("(pRoute %p): stub\n", pRoute
);
3743 /* this is to add a route entry, how's it distinguishable from
3744 CreateIpForwardEntry?
3745 could use SIOCADDRT, not sure I want to */
3750 /******************************************************************
3751 * SetIpNetEntry (IPHLPAPI.@)
3753 * Modify an existing ARP entry.
3756 * pArpEntry [In] ARP entry with the new information
3760 * Failure: error code from winerror.h
3763 * Stub, returns NO_ERROR.
3765 DWORD WINAPI
SetIpNetEntry(PMIB_IPNETROW pArpEntry
)
3767 FIXME("(pArpEntry %p): stub\n", pArpEntry
);
3768 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
3773 /******************************************************************
3774 * SetIpStatistics (IPHLPAPI.@)
3776 * Toggle IP forwarding and det the default TTL value.
3779 * pIpStats [In] IP statistics with the new information
3783 * Failure: error code from winerror.h
3786 * Stub, returns NO_ERROR.
3788 DWORD WINAPI
SetIpStatistics(PMIB_IPSTATS pIpStats
)
3790 FIXME("(pIpStats %p): stub\n", pIpStats
);
3795 /******************************************************************
3796 * SetIpTTL (IPHLPAPI.@)
3798 * Set the default TTL value.
3801 * nTTL [In] new TTL value
3805 * Failure: error code from winerror.h
3808 * Stub, returns NO_ERROR.
3810 DWORD WINAPI
SetIpTTL(UINT nTTL
)
3812 FIXME("(nTTL %d): stub\n", nTTL
);
3813 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
3814 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
3819 /******************************************************************
3820 * SetTcpEntry (IPHLPAPI.@)
3822 * Set the state of a TCP connection.
3825 * pTcpRow [In] specifies connection with new state
3829 * Failure: error code from winerror.h
3832 * Stub, returns NO_ERROR.
3834 DWORD WINAPI
SetTcpEntry(PMIB_TCPROW pTcpRow
)
3836 FIXME("(pTcpRow %p): stub\n", pTcpRow
);
3840 /******************************************************************
3841 * SetPerTcpConnectionEStats (IPHLPAPI.@)
3843 DWORD WINAPI
SetPerTcpConnectionEStats(PMIB_TCPROW row
, TCP_ESTATS_TYPE state
, PBYTE rw
,
3844 ULONG version
, ULONG size
, ULONG offset
)
3846 FIXME("(row %p, state %d, rw %p, version %u, size %u, offset %u): stub\n",
3847 row
, state
, rw
, version
, size
, offset
);
3848 return ERROR_NOT_SUPPORTED
;
3852 /******************************************************************
3853 * UnenableRouter (IPHLPAPI.@)
3855 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3856 * if it reaches zero.
3859 * pOverlapped [In/Out] should be the same as in EnableRouter()
3860 * lpdwEnableCount [Out] optional, receives reference count
3864 * Failure: error code from winerror.h
3867 * Stub, returns ERROR_NOT_SUPPORTED.
3869 DWORD WINAPI
UnenableRouter(OVERLAPPED
* pOverlapped
, LPDWORD lpdwEnableCount
)
3871 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped
,
3873 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
3874 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
3876 return ERROR_NOT_SUPPORTED
;
3879 /******************************************************************
3880 * PfCreateInterface (IPHLPAPI.@)
3882 DWORD WINAPI
PfCreateInterface(DWORD dwName
, PFFORWARD_ACTION inAction
, PFFORWARD_ACTION outAction
,
3883 BOOL bUseLog
, BOOL bMustBeUnique
, INTERFACE_HANDLE
*ppInterface
)
3885 FIXME("(%d %d %d %x %x %p) stub\n", dwName
, inAction
, outAction
, bUseLog
, bMustBeUnique
, ppInterface
);
3886 return ERROR_CALL_NOT_IMPLEMENTED
;
3889 /******************************************************************
3890 * PfUnBindInterface (IPHLPAPI.@)
3892 DWORD WINAPI
PfUnBindInterface(INTERFACE_HANDLE interface
)
3894 FIXME("(%p) stub\n", interface
);
3895 return ERROR_CALL_NOT_IMPLEMENTED
;
3898 /******************************************************************
3899 * PfDeleteInterface(IPHLPAPI.@)
3901 DWORD WINAPI
PfDeleteInterface(INTERFACE_HANDLE interface
)
3903 FIXME("(%p) stub\n", interface
);
3904 return ERROR_CALL_NOT_IMPLEMENTED
;
3907 /******************************************************************
3908 * PfBindInterfaceToIPAddress(IPHLPAPI.@)
3910 DWORD WINAPI
PfBindInterfaceToIPAddress(INTERFACE_HANDLE interface
, PFADDRESSTYPE type
, PBYTE ip
)
3912 FIXME("(%p %d %p) stub\n", interface
, type
, ip
);
3913 return ERROR_CALL_NOT_IMPLEMENTED
;
3916 /******************************************************************
3917 * ConvertInterfaceAliasToLuid (IPHLPAPI.@)
3919 DWORD WINAPI
ConvertInterfaceAliasToLuid( const WCHAR
*alias
, NET_LUID
*luid
)
3921 struct nsi_ndis_ifinfo_rw
*data
;
3922 DWORD err
, count
, i
, len
;
3925 TRACE( "(%s %p)\n", debugstr_w(alias
), luid
);
3927 if (!alias
|| !*alias
|| !luid
) return ERROR_INVALID_PARAMETER
;
3929 len
= strlenW( alias
);
3931 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
3932 (void **)&data
, sizeof(*data
), NULL
, 0, NULL
, 0, &count
, 0 );
3933 if (err
) return err
;
3935 err
= ERROR_INVALID_PARAMETER
;
3936 for (i
= 0; i
< count
; i
++)
3938 if (data
[i
].alias
.Length
== len
* 2 && !memcmp( data
[i
].alias
.String
, alias
, len
* 2 ))
3940 luid
->Value
= keys
[i
].Value
;
3941 err
= ERROR_SUCCESS
;
3945 NsiFreeTable( keys
, data
, NULL
, NULL
);
3949 /******************************************************************
3950 * ConvertInterfaceGuidToLuid (IPHLPAPI.@)
3952 DWORD WINAPI
ConvertInterfaceGuidToLuid(const GUID
*guid
, NET_LUID
*luid
)
3954 struct nsi_ndis_ifinfo_static
*data
;
3955 DWORD err
, count
, i
;
3958 TRACE( "(%s %p)\n", debugstr_guid(guid
), luid
);
3960 if (!guid
|| !luid
) return ERROR_INVALID_PARAMETER
;
3963 err
= NsiAllocateAndGetTable( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, (void **)&keys
, sizeof(*keys
),
3964 NULL
, 0, NULL
, 0, (void **)&data
, sizeof(*data
), &count
, 0 );
3965 if (err
) return err
;
3967 err
= ERROR_INVALID_PARAMETER
;
3968 for (i
= 0; i
< count
; i
++)
3970 if (IsEqualGUID( &data
[i
].if_guid
, guid
))
3972 luid
->Value
= keys
[i
].Value
;
3973 err
= ERROR_SUCCESS
;
3977 NsiFreeTable( keys
, NULL
, NULL
, data
);
3981 /******************************************************************
3982 * ConvertInterfaceIndexToLuid (IPHLPAPI.@)
3984 DWORD WINAPI
ConvertInterfaceIndexToLuid(NET_IFINDEX index
, NET_LUID
*luid
)
3988 TRACE( "(%u %p)\n", index
, luid
);
3990 if (!luid
) return ERROR_INVALID_PARAMETER
;
3992 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_INDEX_LUID_TABLE
, &index
, sizeof(index
),
3993 NSI_PARAM_TYPE_STATIC
, luid
, sizeof(*luid
), 0 );
3994 if (err
) luid
->Value
= 0;
3998 /******************************************************************
3999 * ConvertInterfaceLuidToAlias (IPHLPAPI.@)
4001 DWORD WINAPI
ConvertInterfaceLuidToAlias( const NET_LUID
*luid
, WCHAR
*alias
, SIZE_T len
)
4004 IF_COUNTED_STRING name
;
4006 TRACE( "(%p %p %u)\n", luid
, alias
, (DWORD
)len
);
4008 if (!luid
|| !alias
) return ERROR_INVALID_PARAMETER
;
4010 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4011 NSI_PARAM_TYPE_RW
, &name
, sizeof(name
),
4012 FIELD_OFFSET(struct nsi_ndis_ifinfo_rw
, alias
) );
4013 if (err
) return err
;
4015 if (len
<= name
.Length
/ sizeof(WCHAR
)) return ERROR_NOT_ENOUGH_MEMORY
;
4016 memcpy( alias
, name
.String
, name
.Length
);
4017 alias
[name
.Length
/ sizeof(WCHAR
)] = '\0';
4022 /******************************************************************
4023 * ConvertInterfaceLuidToGuid (IPHLPAPI.@)
4025 DWORD WINAPI
ConvertInterfaceLuidToGuid(const NET_LUID
*luid
, GUID
*guid
)
4029 TRACE( "(%p %p)\n", luid
, guid
);
4031 if (!luid
|| !guid
) return ERROR_INVALID_PARAMETER
;
4033 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4034 NSI_PARAM_TYPE_STATIC
, guid
, sizeof(*guid
),
4035 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_guid
) );
4036 if (err
) memset( guid
, 0, sizeof(*guid
) );
4040 /******************************************************************
4041 * ConvertInterfaceLuidToIndex (IPHLPAPI.@)
4043 DWORD WINAPI
ConvertInterfaceLuidToIndex(const NET_LUID
*luid
, NET_IFINDEX
*index
)
4047 TRACE( "(%p %p)\n", luid
, index
);
4049 if (!luid
|| !index
) return ERROR_INVALID_PARAMETER
;
4051 err
= NsiGetParameter( 1, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, luid
, sizeof(*luid
),
4052 NSI_PARAM_TYPE_STATIC
, index
, sizeof(*index
),
4053 FIELD_OFFSET(struct nsi_ndis_ifinfo_static
, if_index
) );
4054 if (err
) *index
= 0;
4058 /******************************************************************
4059 * ConvertInterfaceLuidToNameA (IPHLPAPI.@)
4061 DWORD WINAPI
ConvertInterfaceLuidToNameA(const NET_LUID
*luid
, char *name
, SIZE_T len
)
4064 WCHAR nameW
[IF_MAX_STRING_SIZE
+ 1];
4066 TRACE( "(%p %p %u)\n", luid
, name
, (DWORD
)len
);
4068 if (!luid
) return ERROR_INVALID_PARAMETER
;
4069 if (!name
|| !len
) return ERROR_NOT_ENOUGH_MEMORY
;
4071 err
= ConvertInterfaceLuidToNameW( luid
, nameW
, ARRAY_SIZE(nameW
) );
4072 if (err
) return err
;
4074 if (!WideCharToMultiByte( CP_UNIXCP
, 0, nameW
, -1, name
, len
, NULL
, NULL
))
4075 err
= GetLastError();
4079 static const WCHAR otherW
[] = {'o','t','h','e','r',0};
4080 static const WCHAR ethernetW
[] = {'e','t','h','e','r','n','e','t',0};
4081 static const WCHAR tokenringW
[] = {'t','o','k','e','n','r','i','n','g',0};
4082 static const WCHAR pppW
[] = {'p','p','p',0};
4083 static const WCHAR loopbackW
[] = {'l','o','o','p','b','a','c','k',0};
4084 static const WCHAR atmW
[] = {'a','t','m',0};
4085 static const WCHAR wirelessW
[] = {'w','i','r','e','l','e','s','s',0};
4086 static const WCHAR tunnelW
[] = {'t','u','n','n','e','l',0};
4087 static const WCHAR ieee1394W
[] = {'i','e','e','e','1','3','9','4',0};
4091 const WCHAR
*prefix
;
4094 static const struct name_prefix name_prefixes
[] =
4096 { otherW
, IF_TYPE_OTHER
},
4097 { ethernetW
, IF_TYPE_ETHERNET_CSMACD
},
4098 { tokenringW
, IF_TYPE_ISO88025_TOKENRING
},
4099 { pppW
, IF_TYPE_PPP
},
4100 { loopbackW
, IF_TYPE_SOFTWARE_LOOPBACK
},
4101 { atmW
, IF_TYPE_ATM
},
4102 { wirelessW
, IF_TYPE_IEEE80211
},
4103 { tunnelW
, IF_TYPE_TUNNEL
},
4104 { ieee1394W
, IF_TYPE_IEEE1394
}
4107 /******************************************************************
4108 * ConvertInterfaceLuidToNameW (IPHLPAPI.@)
4110 DWORD WINAPI
ConvertInterfaceLuidToNameW(const NET_LUID
*luid
, WCHAR
*name
, SIZE_T len
)
4113 const WCHAR
*prefix
= NULL
;
4114 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4115 static const WCHAR prefix_fmt
[] = {'%','s','_','%','d',0};
4116 static const WCHAR unk_fmt
[] = {'i','f','t','y','p','e','%','d','_','%','d',0};
4118 TRACE( "(%p %p %u)\n", luid
, name
, (DWORD
)len
);
4120 if (!luid
|| !name
) return ERROR_INVALID_PARAMETER
;
4122 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4124 if (luid
->Info
.IfType
== name_prefixes
[i
].type
)
4126 prefix
= name_prefixes
[i
].prefix
;
4131 if (prefix
) needed
= snprintfW( buf
, len
, prefix_fmt
, prefix
, luid
->Info
.NetLuidIndex
);
4132 else needed
= snprintfW( buf
, len
, unk_fmt
, luid
->Info
.IfType
, luid
->Info
.NetLuidIndex
);
4134 if (needed
>= len
) return ERROR_NOT_ENOUGH_MEMORY
;
4135 memcpy( name
, buf
, (needed
+ 1) * sizeof(WCHAR
) );
4136 return ERROR_SUCCESS
;
4139 /******************************************************************
4140 * ConvertInterfaceNameToLuidA (IPHLPAPI.@)
4142 DWORD WINAPI
ConvertInterfaceNameToLuidA(const char *name
, NET_LUID
*luid
)
4144 WCHAR nameW
[IF_MAX_STRING_SIZE
];
4146 TRACE( "(%s %p)\n", debugstr_a(name
), luid
);
4148 if (!name
) return ERROR_INVALID_NAME
;
4149 if (!MultiByteToWideChar( CP_UNIXCP
, 0, name
, -1, nameW
, ARRAY_SIZE(nameW
) ))
4150 return GetLastError();
4152 return ConvertInterfaceNameToLuidW( nameW
, luid
);
4155 /******************************************************************
4156 * ConvertInterfaceNameToLuidW (IPHLPAPI.@)
4158 DWORD WINAPI
ConvertInterfaceNameToLuidW(const WCHAR
*name
, NET_LUID
*luid
)
4161 static const WCHAR iftype
[] = {'i','f','t','y','p','e',0};
4162 DWORD type
= ~0u, i
;
4163 WCHAR buf
[IF_MAX_STRING_SIZE
+ 1];
4165 TRACE( "(%s %p)\n", debugstr_w(name
), luid
);
4167 if (!luid
) return ERROR_INVALID_PARAMETER
;
4168 memset( luid
, 0, sizeof(*luid
) );
4170 if (!name
|| !(sep
= strchrW( name
, '_' )) || sep
>= name
+ ARRAY_SIZE(buf
)) return ERROR_INVALID_NAME
;
4171 memcpy( buf
, name
, (sep
- name
) * sizeof(WCHAR
) );
4172 buf
[sep
- name
] = '\0';
4174 if (sep
- name
> ARRAY_SIZE(iftype
) - 1 && !memcmp( buf
, iftype
, (ARRAY_SIZE(iftype
) - 1) * sizeof(WCHAR
) ))
4176 type
= atoiW( buf
+ ARRAY_SIZE(iftype
) - 1 );
4180 for (i
= 0; i
< ARRAY_SIZE(name_prefixes
); i
++)
4182 if (!strcmpW( buf
, name_prefixes
[i
].prefix
))
4184 type
= name_prefixes
[i
].type
;
4189 if (type
== ~0u) return ERROR_INVALID_NAME
;
4191 luid
->Info
.NetLuidIndex
= atoiW( sep
+ 1 );
4192 luid
->Info
.IfType
= type
;
4193 return ERROR_SUCCESS
;
4196 /******************************************************************
4197 * ConvertLengthToIpv4Mask (IPHLPAPI.@)
4199 DWORD WINAPI
ConvertLengthToIpv4Mask(ULONG mask_len
, ULONG
*mask
)
4203 *mask
= INADDR_NONE
;
4204 return ERROR_INVALID_PARAMETER
;
4210 *mask
= htonl(~0u << (32 - mask_len
));
4215 /******************************************************************
4216 * if_nametoindex (IPHLPAPI.@)
4218 IF_INDEX WINAPI
IPHLP_if_nametoindex(const char *name
)
4224 TRACE( "(%s)\n", name
);
4226 err
= ConvertInterfaceNameToLuidA( name
, &luid
);
4229 err
= ConvertInterfaceLuidToIndex( &luid
, &index
);
4234 /******************************************************************
4235 * if_indextoname (IPHLPAPI.@)
4237 char *WINAPI
IPHLP_if_indextoname( NET_IFINDEX index
, char *name
)
4242 TRACE( "(%u, %p)\n", index
, name
);
4244 err
= ConvertInterfaceIndexToLuid( index
, &luid
);
4245 if (err
) return NULL
;
4247 err
= ConvertInterfaceLuidToNameA( &luid
, name
, IF_MAX_STRING_SIZE
);
4248 if (err
) return NULL
;
4252 /******************************************************************
4253 * GetIpInterfaceTable (IPHLPAPI.@)
4255 DWORD WINAPI
GetIpInterfaceTable(ADDRESS_FAMILY family
, PMIB_IPINTERFACE_TABLE
*table
)
4257 FIXME("(%u %p): stub\n", family
, table
);
4258 return ERROR_NOT_SUPPORTED
;
4261 /******************************************************************
4262 * GetBestRoute2 (IPHLPAPI.@)
4264 DWORD WINAPI
GetBestRoute2(NET_LUID
*luid
, NET_IFINDEX index
,
4265 const SOCKADDR_INET
*source
, const SOCKADDR_INET
*destination
,
4266 ULONG options
, PMIB_IPFORWARD_ROW2 bestroute
,
4267 SOCKADDR_INET
*bestaddress
)
4272 FIXME("(%p, %d, %p, %p, 0x%08x, %p, %p): stub\n", luid
, index
, source
,
4273 destination
, options
, bestroute
, bestaddress
);
4275 if (!destination
|| !bestroute
|| !bestaddress
)
4276 return ERROR_INVALID_PARAMETER
;
4278 return ERROR_NOT_SUPPORTED
;
4281 /******************************************************************
4282 * ParseNetworkString (IPHLPAPI.@)
4284 DWORD WINAPI
ParseNetworkString(const WCHAR
*str
, DWORD type
,
4285 NET_ADDRESS_INFO
*info
, USHORT
*port
, BYTE
*prefix_len
)
4288 IN6_ADDR temp_addr6
;
4290 USHORT temp_port
= 0;
4293 TRACE("(%s, %d, %p, %p, %p)\n", debugstr_w(str
), type
, info
, port
, prefix_len
);
4296 return ERROR_INVALID_PARAMETER
;
4298 if (type
& NET_STRING_IPV4_ADDRESS
)
4300 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4301 if (SUCCEEDED(status
) && !temp_port
)
4305 info
->Format
= NET_ADDRESS_IPV4
;
4306 info
->u
.Ipv4Address
.sin_addr
= temp_addr4
;
4307 info
->u
.Ipv4Address
.sin_port
= 0;
4309 if (port
) *port
= 0;
4310 if (prefix_len
) *prefix_len
= 255;
4311 return ERROR_SUCCESS
;
4314 if (type
& NET_STRING_IPV4_SERVICE
)
4316 status
= RtlIpv4StringToAddressExW(str
, TRUE
, &temp_addr4
, &temp_port
);
4317 if (SUCCEEDED(status
) && temp_port
)
4321 info
->Format
= NET_ADDRESS_IPV4
;
4322 info
->u
.Ipv4Address
.sin_addr
= temp_addr4
;
4323 info
->u
.Ipv4Address
.sin_port
= temp_port
;
4325 if (port
) *port
= ntohs(temp_port
);
4326 if (prefix_len
) *prefix_len
= 255;
4327 return ERROR_SUCCESS
;
4330 if (type
& NET_STRING_IPV6_ADDRESS
)
4332 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4333 if (SUCCEEDED(status
) && !temp_port
)
4337 info
->Format
= NET_ADDRESS_IPV6
;
4338 info
->u
.Ipv6Address
.sin6_addr
= temp_addr6
;
4339 info
->u
.Ipv6Address
.sin6_scope_id
= temp_scope
;
4340 info
->u
.Ipv6Address
.sin6_port
= 0;
4342 if (port
) *port
= 0;
4343 if (prefix_len
) *prefix_len
= 255;
4344 return ERROR_SUCCESS
;
4347 if (type
& NET_STRING_IPV6_SERVICE
)
4349 status
= RtlIpv6StringToAddressExW(str
, &temp_addr6
, &temp_scope
, &temp_port
);
4350 if (SUCCEEDED(status
) && temp_port
)
4354 info
->Format
= NET_ADDRESS_IPV6
;
4355 info
->u
.Ipv6Address
.sin6_addr
= temp_addr6
;
4356 info
->u
.Ipv6Address
.sin6_scope_id
= temp_scope
;
4357 info
->u
.Ipv6Address
.sin6_port
= temp_port
;
4359 if (port
) *port
= ntohs(temp_port
);
4360 if (prefix_len
) *prefix_len
= 255;
4361 return ERROR_SUCCESS
;
4365 if (info
) info
->Format
= NET_ADDRESS_FORMAT_UNSPECIFIED
;
4367 if (type
& ~(NET_STRING_IPV4_ADDRESS
|NET_STRING_IPV4_SERVICE
|NET_STRING_IPV6_ADDRESS
|NET_STRING_IPV6_SERVICE
))
4369 FIXME("Unimplemented type 0x%x\n", type
);
4370 return ERROR_NOT_SUPPORTED
;
4373 return ERROR_INVALID_PARAMETER
;