Move implementation of these 2 options into ntdll, and add 2 ioctl codes for calling from ws2_32.
Query configured IPX interfaces by reading /proc/net/ipx/interface of Linux procfs, enabling applications to iterate multiple IPX interfaces. This can be useful when a node have multiple IPX interfaces, and application need to receive/send packets from/to a non-primary IPX interface.
Signed-off-by: WHR whr@rivoreo.one
From: WHR whr@rivoreo.one
Move implementation of these 2 options into ntdll, and add 2 ioctl codes for calling from ws2_32.
Query configured IPX interfaces by reading /proc/net/ipx/interface of Linux procfs, enabling applications to iterate multiple IPX interfaces. This can be useful when a node have multiple IPX interfaces, and application need to receive/send packets from/to a non-primary IPX interface.
Signed-off-by: WHR whr@rivoreo.one --- dlls/ntdll/unix/socket.c | 122 +++++++++++++++++++++++++++++++++++++++ dlls/ws2_32/socket.c | 37 +++--------- include/wine/afd.h | 2 + 3 files changed, 132 insertions(+), 29 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 53292246648..0e00455fabe 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -78,6 +78,9 @@ #include "ws2tcpip.h" #include "wsipx.h" #include "af_irda.h" +#ifdef HAS_IPX +#include "wsnwlink.h" +#endif #include "wine/afd.h"
#include "unix_private.h" @@ -2426,6 +2429,125 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc return do_setsockopt( handle, io, 0, SO_DEFAULT_HEADERS, &value, sizeof(value) ); } #endif + case IOCTL_AFD_WINE_GET_IPX_ADDRESS: + { + const IPX_ADDRESS_DATA *in_data; + IPX_ADDRESS_DATA *out_data; +#ifdef __linux__ + FILE *f; +#endif + + /* + * On a Win2000 system with one network card there are usually + * three ipx devices one with a speed of 28.8kbps, 10Mbps and 100Mbps. + * Using this call you can then retrieve info about this all. + * In case of Linux it is a bit different. Usually you have + * only "one" device active and further it is not possible to + * query things like the linkspeed. + */ + in_data = in_buffer; + out_data = out_buffer; + + TRACE("IOCTL_AFD_WINE_GET_IPX_ADDRESS: adapternum = %d\n", in_data->adapternum); + if(in_data->adapternum < 0) + { + status = STATUS_INVALID_PARAMETER; + break; + } + +#ifdef __linux__ + f = fopen("/proc/net/ipx/interface", "r"); + if (!f) + { + f = fopen("/proc/net/ipx_interface", "r"); + } + if (f) + { + int c; + int i = 0; + + status = STATUS_INVALID_PARAMETER; + while ((c = fgetc(f)) != EOF) + { + if (c != '\n' || i++ != in_data->adapternum) + { + continue; + } + c = fscanf(f, "%02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", + out_data->netnum, out_data->netnum+1, out_data->netnum+2, out_data->netnum+3, + out_data->nodenum, out_data->nodenum+1, out_data->nodenum+2, + out_data->nodenum+3, out_data->nodenum+4, out_data->nodenum+5); + status = (c < 10) ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS; + break; + } + fclose(f); + if (status != STATUS_SUCCESS) break; + } +#endif + else + { + union unix_sockaddr addr; + struct WS_sockaddr_ipx ws_addr; + socklen_t namelen; + + FIXME("IOCTL_AFD_WINE_GET_IPX_ADDRESS\n"); + if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) + return status; + namelen = sizeof(struct sockaddr_ipx); + memset( &addr.ipx, 0, sizeof(struct sockaddr_ipx) ); + if(getsockname( fd, (struct sockaddr *)&addr.ipx, &namelen ) < 0) + { + status = sock_errno_to_status( errno ); + break; + } + sockaddr_from_unix( &addr, (struct WS_sockaddr *)&ws_addr, sizeof(ws_addr) ); + memcpy(out_data->nodenum, ws_addr.sa_nodenum, sizeof(out_data->nodenum)); + memcpy(out_data->netnum, ws_addr.sa_netnum, sizeof(out_data->netnum)); + } + out_data->wan = FALSE; /* We are not on a wan for now .. */ + out_data->status = FALSE; /* Since we are not on a wan, the wan link isn't up */ + out_data->maxpkt = 1467; /* This value is the default one, at least on Win2k/WinXP */ + out_data->linkspeed = 100000; /* Set the line speed in 100bit/s to 10 Mbit; + * note 1MB = 1000kB in this case */ + status = STATUS_SUCCESS; + break; + } + + case IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM: + { + int *count = out_buffer; +#ifdef __linux__ + FILE *f; + int c; + f = fopen("/proc/net/ipx/interface", "r"); + if (!f) + { + f = fopen("/proc/net/ipx_interface", "r"); + if (!f) + { + *count = 0; + status = STATUS_SUCCESS; + break; + } + } + *count = -1; /* Initial value -1 for skipping the header line */ + while ((c = fgetc(f)) != EOF) + { + if(c == '\n') (*count)++; + } + fclose(f); + if (*count < 0) + { + *count = 0; + } + TRACE("IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM: *count = %d\n", *count); +#else + FIXME("IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM\n"); + *count = 1; /* As noted under IPX_ADDRESS we have just one card. */ +#endif + status = STATUS_SUCCESS; + break; + } #endif
#ifdef HAS_IRDA diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index eb84558cbac..aec4c11504e 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1862,40 +1862,19 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl
case NSPROTO_IPX: { - struct sockaddr_ipx addr; - IPX_ADDRESS_DATA *data; - int namelen; + IO_STATUS_BLOCK io; + NTSTATUS status; switch(optname) { case IPX_ADDRESS: - /* - * On a Win2000 system with one network card there are usually - * three ipx devices one with a speed of 28.8kbps, 10Mbps and 100Mbps. - * Using this call you can then retrieve info about this all. - * In case of Linux it is a bit different. Usually you have - * only "one" device active and further it is not possible to - * query things like the linkspeed. - */ - FIXME("IPX_ADDRESS\n"); - namelen = sizeof(struct sockaddr_ipx); - memset( &addr, 0, sizeof(struct sockaddr_ipx) ); - getsockname( s, (struct sockaddr *)&addr, &namelen ); - - data = (IPX_ADDRESS_DATA*)optval; - memcpy(data->nodenum,addr.sa_nodenum,sizeof(data->nodenum)); - memcpy(data->netnum,addr.sa_netnum,sizeof(data->netnum)); - data->adapternum = 0; - data->wan = FALSE; /* We are not on a wan for now .. */ - data->status = FALSE; /* Since we are not on a wan, the wan link isn't up */ - data->maxpkt = 1467; /* This value is the default one, at least on Win2k/WinXP */ - data->linkspeed = 100000; /* Set the line speed in 100bit/s to 10 Mbit; - * note 1MB = 1000kB in this case */ - return 0; + status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, + IOCTL_AFD_WINE_GET_IPX_ADDRESS, optval, *optlen, optval, *optlen ); + if (status == STATUS_SUCCESS) *optlen = io.Information; + SetLastError( NtStatusToWSAError( status ) ); + return status == STATUS_SUCCESS ? 0 : SOCKET_ERROR;
case IPX_MAX_ADAPTER_NUM: - FIXME("IPX_MAX_ADAPTER_NUM\n"); - *(int*)optval = 1; /* As noted under IPX_ADDRESS we have just one card. */ - return 0; + return server_getsockopt( s, IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM, optval, optlen );
case IPX_PTYPE: return server_getsockopt( s, IOCTL_AFD_WINE_GET_IPX_PTYPE, optval, optlen ); diff --git a/include/wine/afd.h b/include/wine/afd.h index aba559ebd8a..ba82ac95930 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -291,6 +291,8 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 ); #define IOCTL_AFD_WINE_SET_TCP_KEEPCNT WINE_AFD_IOC(302) #define IOCTL_AFD_WINE_GET_TCP_KEEPINTVL WINE_AFD_IOC(303) #define IOCTL_AFD_WINE_SET_TCP_KEEPINTVL WINE_AFD_IOC(304) +#define IOCTL_AFD_WINE_GET_IPX_ADDRESS WINE_AFD_IOC(305) +#define IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM WINE_AFD_IOC(306)
struct afd_iovec {
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=147480
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:733: Test failed: peek: raw_legacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey F, message WM_KEYDOWN, extra 0 input.c:733: Test failed: peek: raw_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0x46, lparam 0x10001 input.c:733: Test failed: peek: raw_legacy: 0: test->expect 2 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_CHAR, wparam 0x66, lparam 0x10001 input.c:734: Test failed: peek: raw_legacy: 0: got F: 0 input.c:733: Test failed: peek: raw_legacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey F, message WM_KEYUP, extra 0 input.c:733: Test failed: peek: raw_legacy: 1: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0x46, lparam 0xffffffffc0020001 input.c:733: Test failed: peek: raw_vk_packet_legacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey 0xe7, message WM_KEYDOWN, extra 0 input.c:733: Test failed: peek: raw_vk_packet_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0xe7, lparam 0x10001 input.c:734: Test failed: peek: raw_vk_packet_legacy: 0: got 0xe7: 0 input.c:733: Test failed: peek: raw_vk_packet_legacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey 0xe7, message WM_KEYUP, extra 0 input.c:733: Test failed: peek: raw_vk_packet_legacy: 1: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0xe7, lparam 0xffffffffc0020001 input.c:733: Test failed: peek: raw_unicode_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_CHAR, wparam 0x3c0, lparam 0x1 input.c:734: Test failed: peek: raw_unicode_legacy: 0: got 0xe7: 0 input.c:733: Test failed: peek: raw_unicode_vkey_ctrl_legacy: 0: test->expect 0 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0x11, lparam 0xc00001 input.c:734: Test failed: peek: raw_unicode_vkey_ctrl_legacy: 0: got VK_CONTROL: 0 input.c:734: Test failed: peek: raw_unicode_vkey_ctrl_legacy: 0: got VK_LCONTROL: 0 input.c:733: Test failed: peek: raw_unicode_vkey_ctrl_legacy: 1: test->expect 0 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0x11, lparam 0xffffffffc0c00001 input.c:733: Test failed: peek: raw_nolegacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey F, message WM_KEYDOWN, extra 0 input.c:733: Test failed: peek: raw_nolegacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey F, message WM_KEYUP, extra 0 input.c:733: Test failed: peek: raw_vk_packet_nolegacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey 0xe7, message WM_KEYDOWN, extra 0 input.c:733: Test failed: peek: raw_vk_packet_nolegacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey 0xe7, message WM_KEYUP, extra 0 input.c:733: Test failed: receive: raw_legacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey F, message WM_KEYDOWN, extra 0 input.c:733: Test failed: receive: raw_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0x46, lparam 0x10001 input.c:733: Test failed: receive: raw_legacy: 0: test->expect 2 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_CHAR, wparam 0x66, lparam 0x10001 input.c:734: Test failed: receive: raw_legacy: 0: got F: 0 input.c:733: Test failed: receive: raw_legacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey F, message WM_KEYUP, extra 0 input.c:733: Test failed: receive: raw_legacy: 1: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0x46, lparam 0xffffffffc0020001 input.c:733: Test failed: receive: raw_vk_packet_legacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey 0xe7, message WM_KEYDOWN, extra 0 input.c:733: Test failed: receive: raw_vk_packet_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0xe7, lparam 0x10001 input.c:734: Test failed: receive: raw_vk_packet_legacy: 0: got 0xe7: 0 input.c:733: Test failed: receive: raw_vk_packet_legacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey 0xe7, message WM_KEYUP, extra 0 input.c:733: Test failed: receive: raw_vk_packet_legacy: 1: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0xe7, lparam 0xffffffffc0020001 input.c:733: Test failed: receive: raw_unicode_legacy: 0: test->expect 1 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_CHAR, wparam 0x3c0, lparam 0x1 input.c:734: Test failed: receive: raw_unicode_legacy: 0: got 0xe7: 0 input.c:733: Test failed: receive: raw_unicode_vkey_ctrl_legacy: 0: test->expect 0 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYDOWN, wparam 0x11, lparam 0xc00001 input.c:734: Test failed: receive: raw_unicode_vkey_ctrl_legacy: 0: got VK_CONTROL: 0 input.c:734: Test failed: receive: raw_unicode_vkey_ctrl_legacy: 0: got VK_LCONTROL: 0 input.c:733: Test failed: receive: raw_unicode_vkey_ctrl_legacy: 1: test->expect 0 (missing): MSG_TEST_WIN hwnd 0000000000000000, WM_KEYUP, wparam 0x11, lparam 0xffffffffc0c00001 input.c:733: Test failed: receive: raw_nolegacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey F, message WM_KEYDOWN, extra 0 input.c:733: Test failed: receive: raw_nolegacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey F, message WM_KEYUP, extra 0 input.c:733: Test failed: receive: raw_vk_packet_nolegacy: 0: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x1, flags 0, vkey 0xe7, message WM_KEYDOWN, extra 0 input.c:733: Test failed: receive: raw_vk_packet_nolegacy: 1: test->expect 0 (missing): got WM_INPUT key hwnd 0000000000000000, code 0, make_code 0x2, flags 0x1, vkey 0xe7, message WM_KEYUP, extra 0
Elizabeth Figura (@zfigura) commented about dlls/ntdll/unix/socket.c:
FILE *f;
+#endif
/*
* On a Win2000 system with one network card there are usually
* three ipx devices one with a speed of 28.8kbps, 10Mbps and 100Mbps.
* Using this call you can then retrieve info about this all.
* In case of Linux it is a bit different. Usually you have
* only "one" device active and further it is not possible to
* query things like the linkspeed.
*/
in_data = in_buffer;
out_data = out_buffer;
TRACE("IOCTL_AFD_WINE_GET_IPX_ADDRESS: adapternum = %d\n", in_data->adapternum);
if(in_data->adapternum < 0)
Missing space here. There's another instance below.
Elizabeth Figura (@zfigura) commented about dlls/ntdll/unix/socket.c:
#include "ws2tcpip.h" #include "wsipx.h" #include "af_irda.h" +#ifdef HAS_IPX +#include "wsnwlink.h" +#endif
I guess include-guarding this is helpful to give the preprocessor less work to do, but usually we don't bother include-guarding Windows headers...
Elizabeth Figura (@zfigura) commented about dlls/ntdll/unix/socket.c:
if (c != '\n' || i++ != in_data->adapternum)
{
continue;
}
c = fscanf(f, "%02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
out_data->netnum, out_data->netnum+1, out_data->netnum+2, out_data->netnum+3,
out_data->nodenum, out_data->nodenum+1, out_data->nodenum+2,
out_data->nodenum+3, out_data->nodenum+4, out_data->nodenum+5);
status = (c < 10) ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS;
break;
}
fclose(f);
if (status != STATUS_SUCCESS) break;
}
+#endif
else
Is it correct to fall back if we're on Linux and there's no IPX exposed in procfs? Should we report some form of failure in that case, on the grounds that there really is no IPX support? Note that this is what you do in IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM.
Elizabeth Figura (@zfigura) commented about dlls/ntdll/unix/socket.c:
status = STATUS_INVALID_PARAMETER;
while ((c = fgetc(f)) != EOF)
{
if (c != '\n' || i++ != in_data->adapternum)
{
continue;
}
c = fscanf(f, "%02hhX%02hhX%02hhX%02hhX %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
out_data->netnum, out_data->netnum+1, out_data->netnum+2, out_data->netnum+3,
out_data->nodenum, out_data->nodenum+1, out_data->nodenum+2,
out_data->nodenum+3, out_data->nodenum+4, out_data->nodenum+5);
status = (c < 10) ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS;
break;
}
fclose(f);
if (status != STATUS_SUCCESS) break;
The way this loop is written is compact, but doesn't seem very idiomatic or readable. The reuse of "c" for two different purposes doesn't help matters either. I'd advocate for something like
```c for (;;) { /* nb this skips the first line, which is a header */ while ((c = fgetc(f)) != EOF && c != '\n') ;
ret = fscanf(f, ...); if (ret == EOF) { status = STATUS_INVALID_PARAMETER; break; } else if (ret != 10) { /* it may be nice to ERR() with the failing line... */ status = STATUS_INVALID_ADDRESS; break; }
if (i++ == count) { status = STATUS_SUCCESS; break; } } ```
I'd also personally argue for a helper instead of using that trampoline at the end.
Elizabeth Figura (@zfigura) commented about dlls/ntdll/unix/socket.c:
in_data = in_buffer;
out_data = out_buffer;
TRACE("IOCTL_AFD_WINE_GET_IPX_ADDRESS: adapternum = %d\n", in_data->adapternum);
if(in_data->adapternum < 0)
{
status = STATUS_INVALID_PARAMETER;
break;
}
+#ifdef __linux__
f = fopen("/proc/net/ipx/interface", "r");
if (!f)
{
f = fopen("/proc/net/ipx_interface", "r");
}
No need to use braces around a one-line body.
Can you please fix the authorship of the commit to be your full name (and it should also match the name you use for Gitlab)?
On Mon Aug 5 19:16:46 2024 +0000, Elizabeth Figura wrote:
Is it correct to fall back if we're on Linux and there's no IPX exposed in procfs? Should we report some form of failure in that case, on the grounds that there really is no IPX support? Note that this is what you do in IOCTL_AFD_WINE_GET_IPX_MAX_ADAPTER_NUM.
Makes sense. If IPX-related files are missing from procfs, it would be certain that the kernel is lacking IPX support.