Returns MAC address by: - search local interfaces, or - send UDP packed that does not need linux privilege, then search local cache
solve https://bugs.winehq.org/show_bug.cgi?id=9418
files updated - /dlls/iphlpapi/iphlpapi_main.c - /dlls/iphlpapi/tests/iphlpapi.c
From: Thi Garlet garlet@gmail.com
- /dlls/iphlpapi/iphlpapi_main.c - /dlls/iphlpapi/tests/iphlpapi.c --- dlls/iphlpapi/iphlpapi_main.c | 117 +++++++++++++++++++++++++++++++-- dlls/iphlpapi/tests/iphlpapi.c | 40 +++++++++++ 2 files changed, 151 insertions(+), 6 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 172afbd62b8..8f92c488c8a 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -3964,15 +3964,120 @@ DWORD WINAPI NotifyUnicastIpAddressChange(ADDRESS_FAMILY family, PUNICAST_IPADDR * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h - * - * FIXME - * Stub, returns ERROR_NOT_SUPPORTED. */ DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen) { - FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n", - DestIP, SrcIP, pMacAddr, PhyAddrLen); - return ERROR_NOT_SUPPORTED; + int i=3, time_out=420; + ULONG size=16000; + struct sockaddr_in dst, src; + struct WSAData wd; + SOCKET s; + MIB_IPNETTABLE *table = NULL; + PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; + PIP_ADAPTER_ADDRESSES pInterfaces = NULL, pCurrInterface = NULL; + + if( DestIP == 0 ) + return ERROR_BAD_NET_NAME; + if( pMacAddr == NULL ) + return ERROR_INVALID_PARAMETER; + if( PhyAddrLen == NULL ) + return ERROR_INVALID_USER_BUFFER; + if( (*PhyAddrLen) < 6 ) + return ERROR_BUFFER_OVERFLOW; + + // copy DestIP to MAC, in case MAC cant be found + (*PhyAddrLen) = 6; + memcpy(pMacAddr, &DestIP, 4); + memcpy(pMacAddr+1, &DestIP, 2); + // retunr NO_ERROR; + + + // first, check if DestIP is a local adapter + do + { + pInterfaces = (IP_ADAPTER_ADDRESSES *) heap_alloc_zero(size); + if (pInterfaces == NULL) + { + ERR("Memory allocation failed for IP_ADAPTER_ADDRESSES struct"); + return ERROR_BUFFER_OVERFLOW; + } + + i = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST + GAA_FLAG_SKIP_MULTICAST + + GAA_FLAG_SKIP_DNS_SERVER + GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, pInterfaces, &size); + + if (i == NO_ERROR ) + { + pCurrInterface = pInterfaces; + while ( pCurrInterface ) + { + + pUnicast = pCurrInterface->FirstUnicastAddress; + while ( pUnicast ) + { + if ( DestIP == ((struct sockaddr_in *) pUnicast->Address.lpSockaddr)->sin_addr.s_addr ) + { + memcpy(pMacAddr, pCurrInterface->PhysicalAddress, 6); + heap_free(pInterfaces); + return NO_ERROR; // 0 + } + pUnicast = pUnicast->Next; + } + pCurrInterface = pCurrInterface->Next; + } + } + heap_free(pInterfaces); + + } while ( i == ERROR_BUFFER_OVERFLOW && i-- > 0 ); + + + // prepare config, to send an UDP packed instead of privileged ARP + src.sin_family = AF_INET; + src.sin_addr.s_addr = SrcIP; // del? + src.sin_port = 10123; // del? + dst.sin_family = AF_INET; + dst.sin_addr.s_addr = DestIP; + dst.sin_port = 10123; // del? + + // send UDP + if( WSAStartup( MAKEWORD( 2, 2 ), &wd ) != 0 ) + return ERROR_NOT_SUPPORTED; + s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); // SOCK_RAW, IPPROTO_ICMP + bind( s, (SOCKADDR *) &src, sizeof(src) ); + i = sendto( s, (const char *) &time_out, 4, 0, (SOCKADDR *) &dst, sizeof(dst) ); + closesocket(s); + WSACleanup(); + if( i == SOCKET_ERROR ) // -1 + return ERROR_GEN_FAILURE; // 31 + + + // search cached arp table + size = 16000; + while( time_out-- > 0 ) + { + table = heap_alloc_zero(size); + if( table == NULL ) + { + ERR("Memory allocation failed for IpNetTable struct"); + return ERROR_BUFFER_OVERFLOW; + } + + if( GetIpNetTable( table, &size, 0 ) == NO_ERROR ) + { + for (i = 0; i < table->dwNumEntries; ++i) + { + if( table->table[i].dwAddr == DestIP ) + { + memcpy(pMacAddr, table->table[i].bPhysAddr, 6); + heap_free(table); + return NO_ERROR; // 0 + } + } + } + Sleep(1); + heap_free(table); + } + + return ERROR_NOT_FOUND; // 1168 }
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index da3a06d54ca..7e14b2ad5d0 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -3098,6 +3098,45 @@ static void test_compartments(void) ok(id == NET_IF_COMPARTMENT_ID_PRIMARY, "got %u\n", id); }
+static void test_SendARP(void) +{ + DWORD apiReturn; + ULONG dwSize = 0; + ULONG MacAddr[2]={0,0}; + + apiReturn = SendARP(0, 0, NULL, NULL); + if (apiReturn == ERROR_NOT_SUPPORTED) { + skip("SendARP is not supported\n"); + return; + } + ok(apiReturn == ERROR_BAD_NET_NAME, + "SendARP(0, 0, NULL, NULL) returned %ld, expected ERROR_BAD_NET_NAME\n", + apiReturn); + + apiReturn = SendARP( inet_addr("127.0.0.1"), 0, NULL, NULL); + ok(apiReturn == ERROR_INVALID_PARAMETER, + "SendARP(inet_addr('127.0.0.1'), 0, NULL, NULL) returned %ld, expected ERROR_INVALID_PARAMETER\n", + apiReturn); + + apiReturn = SendARP( inet_addr("127.0.0.1"), 0, (PULONG) &MacAddr, NULL); + ok(apiReturn == ERROR_INVALID_USER_BUFFER, + "SendARP(inet_addr('127.0.0.1'), 0, (PULONG) &MacAddr, NULL) returned %ld, expected ERROR_INVALID_USER_BUFFER\n", + apiReturn); + + apiReturn = SendARP( inet_addr("127.0.0.1"), 0, (PULONG) &MacAddr, &dwSize); + ok(apiReturn == ERROR_BUFFER_OVERFLOW, + "SendARP(inet_addr('127.0.0.1'), 0, (PULONG) &MacAddr, &dwSize=0) returned %ld, expected ERROR_BUFFER_OVERFLOW\n", + apiReturn); + + dwSize = 6; + apiReturn = SendARP( inet_addr("127.0.0.1"), 0, (PULONG) &MacAddr, &dwSize); + if (apiReturn == ERROR_NOT_FOUND) { + trace( "SendARP(inet_addr('127.0.0.1'), 0, (PULONG) &MacAddr, &dwSize) did not found a mac address\n" ); + } else { + trace( "SendARP(inet_addr('127.0.0.1'), 0, (PULONG) &MacAddr, &dwSize) returned %lu mac: %lu - %lu.\n", apiReturn, MacAddr[0], MacAddr[1] ); + } +} + START_TEST(iphlpapi) { WSADATA wsa_data; @@ -3139,6 +3178,7 @@ START_TEST(iphlpapi) test_NotifyUnicastIpAddressChange(); test_ConvertGuidToString(); test_compartments(); + test_SendARP(); freeIPHlpApi(); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149877
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
iphlpapi: 0284:iphlpapi: unhandled exception c0000005 at 7378F508
=== w7u_adm (32 bit report) ===
iphlpapi: 0860:iphlpapi: unhandled exception c0000005 at 7379F508
=== w7u_el (32 bit report) ===
iphlpapi: 0a6c:iphlpapi: unhandled exception c0000005 at 7311F508
=== w8 (32 bit report) ===
iphlpapi: 0c28:iphlpapi: unhandled exception c0000005 at 71C12AF6
=== w8adm (32 bit report) ===
iphlpapi: 0da0:iphlpapi: unhandled exception c0000005 at 71DF2AF6
=== w864 (32 bit report) ===
iphlpapi: 0804:iphlpapi: unhandled exception c0000005 at 739E2AF6
=== w1064v1507 (32 bit report) ===
iphlpapi: 0f60:iphlpapi: unhandled exception c0000005 at 7497FB64
=== w1064v1809 (32 bit report) ===
iphlpapi: 1dc8:iphlpapi: unhandled exception c0000005 at 74B3F45C
=== w1064_tsign (32 bit report) ===
iphlpapi: 1fac:iphlpapi: unhandled exception c0000005 at 755CEADC
=== w10pro64 (32 bit report) ===
iphlpapi: 20d4:iphlpapi: unhandled exception c0000005 at 73E3EADC
=== w10pro64_en_AE_u8 (32 bit report) ===
iphlpapi: 2348:iphlpapi: unhandled exception c0000005 at 7496EADC
=== w11pro64 (32 bit report) ===
iphlpapi: 1708:iphlpapi: unhandled exception c0000005 at 748F08EC
=== w7pro64 (64 bit report) ===
iphlpapi: 0b84:iphlpapi: unhandled exception c0000005 at 000007FEFA36F44D
=== w864 (64 bit report) ===
iphlpapi: 0b40:iphlpapi: unhandled exception c0000005 at 00007FFA43C4755B
=== w1064v1507 (64 bit report) ===
iphlpapi: 0be4:iphlpapi: unhandled exception c0000005 at 00007FFAD846F59B
=== w1064v1809 (64 bit report) ===
iphlpapi: 1db0:iphlpapi: unhandled exception c0000005 at 00007FFFC130EA23
=== w1064_2qxl (64 bit report) ===
iphlpapi: 1e08:iphlpapi: unhandled exception c0000005 at 00007FFFFA1EDD22
=== w1064_adm (64 bit report) ===
iphlpapi: 1d3c:iphlpapi: unhandled exception c0000005 at 00007FFA535EDD22
=== w1064_tsign (64 bit report) ===
iphlpapi: 1e78:iphlpapi: unhandled exception c0000005 at 00007FFC6BFADD22
=== w10pro64 (64 bit report) ===
iphlpapi: 2058:iphlpapi: unhandled exception c0000005 at 00007FFF2B95DD22
=== w10pro64_ar (64 bit report) ===
iphlpapi: 2338:iphlpapi: unhandled exception c0000005 at 00007FFA063FDD22
=== w10pro64_ja (64 bit report) ===
iphlpapi: 0658:iphlpapi: unhandled exception c0000005 at 00007FF96D8FDD22
=== w10pro64_zh_CN (64 bit report) ===
iphlpapi: 1d88:iphlpapi: unhandled exception c0000005 at 00007FF8B45DDD22
=== w11pro64_amd (64 bit report) ===
iphlpapi: 1a94:iphlpapi: unhandled exception c0000005 at 00007FFA75AE2E22
=== debian11b (64 bit WoW report) ===
user32: win.c:4070: Test failed: Expected active window 0000000006840176, got 0000000000000000. win.c:4071: Test failed: Expected focus window 0000000006840176, got 0000000000000000.
iphlpapi.c:3098: this is the last test seen before the exception 20dc:iphlpapi:0.328 unhandled exception c0000005 at 7406EADC
Apparently SendARP(0, 0, NULL, NULL) does not return ERROR_NOT_SUPPORTED on native. It may have done so on older Windows, but it doesn't anymore. Let's just remove those segfaulting tests, testing error handlers isn't very useful.
(PULONG) &MacAddr
Should just be MacAddr.
SendARP( inet_addr("127.0.0.1"), 0, ...)
I tried it.
Windows reports success and a zero-byte MAC address. We may or may not want to mimic that, but we definitely don't want to use that as the primary test.
I suspect this is because localhost doesn't have a mac address - it doesn't go through any networking hardware, it just stays inside the kernel. Sorry if I'm the one who told you to use localhost, I'm not particularly familiar with this stuff.
You can, however, use 255.255.255.255 as the target. That requests the MAC address of everything on the network, and returns the first one to respond (usually the local one).
I didn't check the implementation (yet), only the tests. Let's get the tests passing on Windows first, so we know what exact behavior our SendARP should implement.
Thx, I was not understanding that the win fail was with native iphlpapi.dll;
"(PULONG) &MacAddr"
I had to put the cast because of warnings, and the '&' because MacAddr on test is not malloc'ed anymore
I also got 127.0.0.1 returning mac == 0 (wich is what correct looking at `ip a`) 255.255.255.255 crossed my mind, but just forgot. thx
Should I close this request, redo the commit and make a new merge request ?
On Fri Nov 22 17:22:17 2024 +0000, Thi Garlet wrote:
Thx, I was not understanding that the win fail was with native iphlpapi.dll; what was the result of SendARP(0, 0, NULL, NULL) ?
"(PULONG) &MacAddr"
I had to put the cast because of warnings, and the '&' because MacAddr on test is not malloc'ed anymore I also got 127.0.0.1 returning mac == 0 (wich is what correct looking at `ip a`) 255.255.255.255 crossed my mind, but just forgot. thx Should I close this request, redo the commit and make a new merge request ?
It's an array, so you can use it as a pointer as is. Taking the address of an array is almost never correct. (I think it will do the right thing, but it'll confuse readers.)
Testing the returned length of the mac address sounds like a good idea. Feel free to test both 127.0.0.1 and 255.255.255.255, more tests never hurt.
Redo the commit and force push, and it'll show up in this MR. Closing and recreating just sounds like a waste of time for everyone.
Redo the commit and force push
Can this be done on the web interface ?
On Fri Nov 22 17:24:40 2024 +0000, Thi Garlet wrote:
Redo the commit and force push
Can this be done on the web interface ?
Also, probably I need to reorder the error checking section, matching the native code
On Fri Nov 22 17:27:58 2024 +0000, Thi Garlet wrote:
Also, probably I need to reorder the error checking section, matching the native code
I don't know. Probably not. Better clone the repo and use Git locally. (We're not trying to be difficult, we just want to uphold our long-standing tradition of commit log cleanliness; it makes bisects/etc easier.)
Wine's goal is to run real-life Windows programs; matching native behavior in error cases is generally unnecessary. Especially when native behavior is segfault or otherwise hard to test.