Hi, Here are some patches which improve winsock's ipx support. Using these patches games C&C Tiberian Sun, Red Alert (v3.x) and Red Alert II work over a lan. First patches 1 and 3 add a new ipx related header. Patch 1 is the new header I made and patch 3 contains some extra structs submitted by vincent beron. Patch 2 adds various missing pieces to the winsock code. For one of the new pieces of code a new wineserver call was required. In short the problem is that the way in which you can set the ipx packet type is different. On linux you can change the ipx packet type by setting an attribute of the linux ipx sockaddr structure. On windows it is changed using (WS_)setsockopt. The attribute that exists in the linux sockaddr structure doesn't exist on windows. In our winsock dll all winsock structures are in the end converted to their linux equivalent. When we receive a request to change the ipx packet type we only have access to the winsock structure and because of this we can't change the packet type. (since it misses the attribute) To be able to get and set the packet type it needs to be stored in the wineserver. (Mike McCormack advised me this) ChangeLog: - implement getsockopt/setsockopt's IPX_PTYPE, IPX_ADDRESS and IPX_MAD_ADAPATER_NUM Roderick Colenbrander
Index: dlls/winsock/socket.c =================================================================== RCS file: /home/wine/wine/dlls/winsock/socket.c,v retrieving revision 1.138 diff -u -r1.138 socket.c --- dlls/winsock/socket.c 14 Oct 2003 05:27:43 -0000 1.138 +++ dlls/winsock/socket.c 8 Nov 2003 19:30:10 -0000 @@ -122,6 +122,7 @@ #include "winsock2.h" #include "ws2tcpip.h" #include "wsipx.h" +#include "wsnwlink.h" #include "wine/winsock16.h" #include "winnt.h" #include "wownt32.h" @@ -1248,7 +1249,7 @@ * Work horse for both synchronous and asynchronous send() operations. */ static int WS2_send ( int fd, struct iovec* iov, int count, - const struct WS_sockaddr *to, INT tolen, DWORD dwFlags ) + const struct WS_sockaddr *to, INT tolen, DWORD dwFlags, SOCKET s ) { struct msghdr hdr; int n = -1; @@ -1262,7 +1263,27 @@ #if DEBUG_SOCKADDR dump_sockaddr (to); #endif - hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); + +#ifdef HAVE_IPX + if(to->sa_family == WS_AF_IPX) + { + struct sockaddr_ipx* uipx; + uipx = (struct sockaddr_ipx*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); + + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_GET_PTYPE; + req->handle = SOCKET2HANDLE(s); + wine_server_call( req ); + uipx->sipx_type=reply->ptype; + } + SERVER_END_REQ; + hdr.msg_name = (struct sockaddr*) uipx; + } + else +#endif + hdr.msg_name = (struct sockaddr*) ws_sockaddr_ws2u ( to, tolen, &hdr.msg_namelen ); + if ( !hdr.msg_name ) { WSASetLastError ( WSAEFAULT ); @@ -1309,7 +1330,7 @@ } result = WS2_send ( wsa->async.fd, wsa->iovec, wsa->n_iovecs, - wsa->addr, wsa->addrlen.val, wsa->flags ); + wsa->addr, wsa->addrlen.val, wsa->flags, 0); if (result >= 0) { @@ -1827,6 +1848,55 @@ return 0; } +#ifdef HAVE_IPX + if(level == NSPROTO_IPX) + { + struct WS_sockaddr_ipx addr; + IPX_ADDRESS_DATA *data; + int namelen; + switch(optname) + { + case IPX_PTYPE: + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_GET_PTYPE; + req->handle = SOCKET2HANDLE (s); + + wine_server_call( req ); + *(int*)optval = reply->ptype; + *optlen = sizeof(int); + } + SERVER_END_REQ; + return 0; + break; + case IPX_ADDRESS: + namelen = sizeof(struct WS_sockaddr); + memset(&addr, 0, sizeof(struct WS_sockaddr)); + WS_getsockname(s, (struct WS_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 = 1500; /* Is this value correct, I found it on a IPX page */ + data->linkspeed = 100000; /* Set the line speed in 100bits, for now assume 10Mbit */ + FIXME("IPX_ADDRESS\n"); + return 0; + break; + case IPX_MAX_ADAPTER_NUM: + *(int*)optval = 1; /* Only one card for the moment .. */ + FIXME("IPX_MAX_ADAPTER_NUM\n"); + return 0; + break; + default: + FIXME("opt_name:%x\n", optname); + return SOCKET_ERROR; + } + } +#endif + fd = _get_sock_fd(s); if (fd != -1) { @@ -2504,7 +2574,7 @@ do_block(fd, POLLOUT); } - n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags ); + n = WS2_send ( fd, iovec, dwBufferCount, to, tolen, dwFlags, s); if ( n == -1 ) { err = wsaErrno(); @@ -2600,6 +2670,46 @@ return 0; } + +#ifdef HAVE_IPX + if(level == NSPROTO_IPX) + { + struct WS_sockaddr addr; + struct sockaddr_ipx* sipx; + int namelen, uaddrlen; + switch(optname) + { + case IPX_PTYPE: + namelen = sizeof(struct WS_sockaddr); + memset(&addr, 0, sizeof(struct WS_sockaddr)); + WS_getsockname(s, &addr, &namelen); + sipx = (struct sockaddr_ipx*)ws_sockaddr_ws2u(&addr, sizeof(addr), &uaddrlen); + + SERVER_START_REQ(packet_type ) + { + req->flags = IPX_SET_PTYPE; + req->handle = SOCKET2HANDLE (s); + + req->value = *optval; + wine_server_call( req ); + } + SERVER_END_REQ; + + return 0; + break; + case IPX_FILTERPTYPE: + /* sets the receive filter packet type */ + /* SO_ATTACH_FILTER ??*/ + FIXME("IPX_FILTERPTYPE: %x\n", *optval); + return 0; + break; + default: + FIXME("opt_name:%x\n", optname); + return SOCKET_ERROR; + } + return 0; + } +#endif fd = _get_sock_fd(s); if (fd != -1) Index: include/wine/server_protocol.h =================================================================== RCS file: /home/wine/wine/include/wine/server_protocol.h,v retrieving revision 1.88 diff -u -r1.88 server_protocol.h --- include/wine/server_protocol.h 14 Oct 2003 01:30:42 -0000 1.88 +++ include/wine/server_protocol.h 8 Nov 2003 19:30:13 -0000 @@ -3114,6 +3114,23 @@ #define SET_GLOBAL_TASKMAN_WINDOW 0x04 +struct packet_type_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + int value; +}; +struct packet_type_reply +{ + struct reply_header __header; + int ptype; +}; + +#define IPX_GET_PTYPE 0x1 +#define IPX_SET_PTYPE 0x2 + + enum request { REQ_new_process, @@ -3295,6 +3312,7 @@ REQ_set_clipboard_info, REQ_open_token, REQ_set_global_windows, + REQ_packet_type, REQ_NB_REQUESTS }; @@ -3481,6 +3499,7 @@ struct set_clipboard_info_request set_clipboard_info_request; struct open_token_request open_token_request; struct set_global_windows_request set_global_windows_request; + struct packet_type_request packet_type_request; }; union generic_reply { @@ -3665,8 +3684,9 @@ struct set_clipboard_info_reply set_clipboard_info_reply; struct open_token_reply open_token_reply; struct set_global_windows_reply set_global_windows_reply; + struct packet_type_reply packet_type_reply; }; -#define SERVER_PROTOCOL_VERSION 126 +#define SERVER_PROTOCOL_VERSION 129 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.87 diff -u -r1.87 protocol.def --- server/protocol.def 14 Oct 2003 01:30:42 -0000 1.87 +++ server/protocol.def 8 Nov 2003 19:30:16 -0000 @@ -2175,3 +2175,15 @@ #define SET_GLOBAL_SHELL_WINDOWS 0x01 /* set both main shell and listview windows */ #define SET_GLOBAL_PROGMAN_WINDOW 0x02 #define SET_GLOBAL_TASKMAN_WINDOW 0x04 + +/* store ipx packet type to work around linux/windows socket incompatibilities */ +@REQ(packet_type) + obj_handle_t handle; /* handle to the socket */ + unsigned int flags; /* get/set packet type */ + int value; /* packet type */ +@REPLY + int ptype; +@END + +#define IPX_GET_PTYPE 0x1 /* get ipx packet type */ +#define IPX_SET_PTYPE 0x2 /* set ipx packet type */ Index: server/sock.c =================================================================== RCS file: /home/wine/wine/server/sock.c,v retrieving revision 1.46 diff -u -r1.46 sock.c --- server/sock.c 5 Sep 2003 23:15:41 -0000 1.46 +++ server/sock.c 8 Nov 2003 19:30:17 -0000 @@ -84,6 +84,7 @@ struct sock* deferred; /* socket that waits for a deferred accept */ struct async_queue read_q; /* Queue for asynchronous reads */ struct async_queue write_q; /* Queue for asynchronous writes */ + int ptype; /* packte type in the case of IPX */ }; static void sock_dump( struct object *obj, int verbose ); @@ -616,6 +617,7 @@ sock->event = NULL; sock->window = 0; sock->message = 0; + sock->ptype = 0; sock->wparam = 0; sock->deferred = NULL; if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj ))) @@ -925,3 +927,23 @@ sock->deferred = acceptsock; release_object ( sock ); } + +DECL_HANDLER(packet_type) +{ + struct sock *sock; + + sock=(struct sock*)get_handle_obj( current->process,req->handle, + GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops ); + if(!sock) + { + return; + } + + if(req->flags == IPX_GET_PTYPE) + reply->ptype = sock->ptype; + else + sock->ptype = req->value; + + release_object ( sock ); +} +
--- /dev/null 2003-01-18 20:54:32.000000000 +0100 +++ ./include/wsnwlink.h 2003-07-12 14:21:34.000000000 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Roderick Colenbrander + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WSNWLINK_ +#define _WSNWLINK_ + +#include "wtypes.h" + +#define IPX_PTYPE 0x4000 +#define IPX_FILTERPTYPE 0x4001 +#define IPX_DSTYPE 0x4002 +#define IPX_STOPFILTERPTYPE 0x4003 +#define IPX_EXTENDED_ADDRESS 0x4004 +#define IPX_RECVHDR 0x4005 +#define IPX_MAXSIZE 0x4006 +#define IPX_ADDRESS 0x4007 +#define IPX_GETNETINFO 0x4008 +#define IPX_GETNETINFO_NORIP 0x4009 +#define IPX_SPXGETCONNECTIONSTATUS 0x400b +#define IPX_ADDRESS_NOTIFY 0x400c +#define IPX_MAX_ADAPTER_NUM 0x400d +#define IPX_RERIPNETNUMBER 0x400e +#define IPX_RECEIVE_BROADCAST 0x400f +#define IPX_IMMEDIATESPXACK 0x4010 + +typedef struct _IPX_ADDRESS_DATA { + INT adapternum; + UCHAR netnum[4]; + UCHAR nodenum[6]; + BOOLEAN wan; + BOOLEAN status; + INT maxpkt; + ULONG linkspeed; +} IPX_ADDRESS_DATA, *PIPX_ADDRESS_DATA; + +#endif +
--- wsnwlink.h-orig 2003-07-12 10:09:57.000000000 -0400 +++ wsnwlink.h 2003-07-12 10:09:38.000000000 -0400 @@ -48,5 +48,34 @@ ULONG linkspeed; } IPX_ADDRESS_DATA, *PIPX_ADDRESS_DATA; +typedef struct _IPX_NETNUM_DATA { + UCHAR netnum[4]; + USHORT hopcount; + USHORT netdelay; + INT cardnum; + UCHAR router[6]; +} IPX_NETNUM_DATA, *PIPX_NETNUM_DATA; + +typedef struct _IPX_SPXCONNSTATUS_DATA { + UCHAR ConnectionState; + UCHAR WatchDogActive; + USHORT LocalConnectionId; + USHORT RemoteConnectionId; + USHORT LocalSequenceNumber; + USHORT LocalAckNumber; + USHORT LocalAllocNumber; + USHORT RemoteAckNumber; + USHORT RemoteAllocNumber; + USHORT LocalSocket; + UCHAR ImmediateAddress[6]; + UCHAR RemoteNetwork[4]; + UCHAR RemoteNode[6]; + USHORT RemoteSocket; + USHORT RetransmissionCount; + USHORT EstimatedRoundTripDelay; + USHORT RetransmittedPackets; + USHORT SuppressedPacket; +} IPX_SPXCONNSTATUS_DATA, *PIPX_SPXCONNSTATUS_DATA; + #endif