[PATCH 3/3] iphlpapi: Implement GetBestRoute2.
Jinoh Kang
wine at gitlab.winehq.org
Fri Jun 17 09:00:15 CDT 2022
From: Jinoh Kang <jinoh.kang.kr at gmail.com>
Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
dlls/iphlpapi/iphlpapi_main.c | 137 +++++++++++++++++++++++++++++++++-
1 file changed, 134 insertions(+), 3 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 33b12361d70..32e1d7e23a7 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -4441,16 +4441,147 @@ DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index,
ULONG options, PMIB_IPFORWARD_ROW2 bestroute,
SOCKADDR_INET *bestaddress)
{
- static int once;
+ MIB_IPFORWARD_TABLE2 *table;
+ MIB_UNICASTIPADDRESS_TABLE *table_ip;
+ const MIB_IPFORWARD_ROW2 *matched;
+ NET_LUID luid_match;
+ DWORD ndx, ndx_ip;
+ SOCKADDR_INET dest, matched_src;
+ UINT addr_bytes;
+ const BYTE *dest_prefix;
+ DWORD ret;
+ static unsigned int once;
if (!once++)
- FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid, index, source,
+ FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): partial stub\n", luid, index, source,
destination, options, bestroute, bestaddress);
if (!destination || !bestroute || !bestaddress)
return ERROR_INVALID_PARAMETER;
- return ERROR_NOT_SUPPORTED;
+ memcpy( &dest, destination, sizeof(dest) );
+ switch (dest.si_family)
+ {
+ case AF_INET:
+ addr_bytes = sizeof(dest.Ipv4.sin_addr);
+ dest_prefix = (const BYTE *)&dest.Ipv4.sin_addr;
+ break;
+ case AF_INET6:
+ addr_bytes = sizeof(dest.Ipv6.sin6_addr);
+ dest_prefix = (const BYTE *)&dest.Ipv6.sin6_addr;
+ break;
+ default:
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (luid)
+ {
+ NET_IFINDEX unused;
+ memcpy( &luid_match, luid, sizeof(luid_match) );
+ if (luid_match.Value)
+ {
+ /* check LUID existence */
+ ret = ConvertInterfaceLuidToIndex( &luid_match, &unused );
+ if (ret)
+ {
+ if (ret == ERROR_FILE_NOT_FOUND) ret = ERROR_NOT_FOUND;
+ goto fail;
+ }
+ }
+ }
+ else if (index)
+ {
+ ret = ConvertInterfaceIndexToLuid( index, &luid_match );
+ if (ret) goto fail;
+ }
+ else
+ {
+ memset( &luid_match, 0, sizeof(luid_match) );
+ }
+
+ ret = GetIpForwardTable2( dest.si_family, &table );
+ if (ret) goto fail;
+
+ ret = GetUnicastIpAddressTable( dest.si_family, &table_ip );
+ if (ret) goto free_ipforwardtable2;
+
+ for (ndx = 0, matched = NULL; ndx < table->NumEntries; ndx++)
+ {
+ const MIB_IPFORWARD_ROW2 *row = &table->Table[ndx];
+ const BYTE *row_prefix;
+ const SOCKADDR_INET *forward_src;
+ UINT prefix_bytes, prefix_lastshr;
+
+ if (luid_match.Value && row->InterfaceLuid.Value != luid_match.Value) continue;
+ if (row->DestinationPrefix.Prefix.si_family != dest.si_family) continue;
+
+ if (row->DestinationPrefix.PrefixLength > addr_bytes * 8) continue;
+ switch (row->DestinationPrefix.Prefix.si_family)
+ {
+ case AF_INET:
+ row_prefix = (const BYTE *)&row->DestinationPrefix.Prefix.Ipv4.sin_addr;
+ break;
+ case AF_INET6:
+ row_prefix = (const BYTE *)&row->DestinationPrefix.Prefix.Ipv6.sin6_addr;
+ break;
+ default:
+ continue;
+ }
+
+ prefix_bytes = row->DestinationPrefix.PrefixLength >> 3;
+ prefix_lastshr = -row->DestinationPrefix.PrefixLength & 7;
+ if (memcmp(dest_prefix, row_prefix, prefix_bytes) != 0 ||
+ (prefix_lastshr && ((dest_prefix[prefix_bytes] ^ row_prefix[prefix_bytes]) >>
+ prefix_lastshr) != 0)) continue;
+
+ forward_src = NULL;
+ for (ndx_ip = 0; ndx_ip < table_ip->NumEntries; ndx_ip++)
+ {
+ if (row->InterfaceLuid.Value == table_ip->Table[ndx_ip].InterfaceLuid.Value)
+ {
+ forward_src = &table_ip->Table[ndx_ip].Address;
+ break;
+ }
+ }
+ if (!forward_src) continue;
+
+ if (!matched || row->DestinationPrefix.PrefixLength > matched->DestinationPrefix.PrefixLength ||
+ (row->DestinationPrefix.PrefixLength == matched->DestinationPrefix.PrefixLength &&
+ row->Metric < matched->Metric))
+ {
+ matched = row;
+ memcpy( &matched_src, forward_src, sizeof(matched_src) );
+ }
+ }
+
+ if (matched)
+ {
+ ret = NO_ERROR;
+ }
+ else
+ {
+ /* No route matches, which can happen if there's no default route. */
+ ret = ERROR_HOST_UNREACHABLE;
+ }
+
+ heap_free( table_ip );
+
+free_ipforwardtable2:
+ heap_free( table );
+
+fail:
+ if (ret == NO_ERROR && matched)
+ {
+ memcpy( bestroute, matched, sizeof(*bestroute) );
+ memcpy( bestaddress, &matched_src, sizeof(*bestaddress) );
+ }
+ else
+ {
+ memset( bestroute, 0, sizeof(*bestroute) );
+ memset( bestaddress, 0, sizeof(*bestaddress) );
+ }
+ TRACE("returning %lu\n", ret);
+ return ret;
}
/******************************************************************
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/263
More information about the wine-devel
mailing list