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 {