]> icculus.org git repositories - btb/d2x.git/blob - arch/linux_ipx_bsd.c
unification of input headers
[btb/d2x.git] / arch / linux_ipx_bsd.c
1 /* IPX driver using BSD style sockets */
2 /* Mostly taken from dosemu */
3 #include <conf.h>
4 #ifdef __ENV_LINUX__
5 #ifdef NETWORK
6
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <string.h>
11
12 #ifdef HAVE_NETIPX_IPX_H
13 #include <netipx/ipx.h>
14 #else
15 # include <linux/ipx.h>
16 # ifndef IPX_TYPE
17 #  define IPX_TYPE 1
18 # endif
19 #endif
20
21 #include <netinet/in.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #include "pstypes.h"
26 #include "ipx_drv.h"
27 #include "ipx_bsd.h"
28
29 #ifndef DOSEMU
30 #include "mono.h"
31 #define n_printf(format, args...) mprintf((1, format, ## args))
32 #define enter_priv_on()
33 #define leave_priv_setting()
34 #endif
35
36 static int ipx_bsd_GetMyAddress( void )
37 {
38   int sock;
39   struct sockaddr_ipx ipxs;
40   struct sockaddr_ipx ipxs2;
41   int len;
42   int i;
43   
44   sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
45   if(sock==-1)
46   {
47     n_printf("IPX: could not open socket in GetMyAddress\n");
48     return(-1);
49   }
50
51   /* bind this socket to network 0 */  
52   ipxs.sipx_family=AF_IPX;
53 #ifdef IPX_MANUAL_ADDRESS
54   memcpy(&ipxs.sipx_network, ipx_MyAddress, 4);
55 #else
56   ipxs.sipx_network=0;
57 #endif  
58   ipxs.sipx_port=0;
59   
60   if(bind(sock,(struct sockaddr *)&ipxs,sizeof(ipxs))==-1)
61   {
62     n_printf("IPX: could bind to network 0 in GetMyAddress\n");
63     close( sock );
64     return(-1);
65   }
66   
67   len = sizeof(ipxs2);
68   if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
69     n_printf("IPX: could not get socket name in GetMyAddress\n");
70     close( sock );
71     return(-1);
72   }
73
74   memcpy(ipx_MyAddress, &ipxs2.sipx_network, 4);
75   for (i = 0; i < 6; i++) {
76     ipx_MyAddress[4+i] = ipxs2.sipx_node[i];
77   }
78   close( sock );
79   return(0);
80 }
81
82 static int ipx_bsd_OpenSocket(ipx_socket_t *sk, int port)
83 {
84   int sock;                     /* sock here means Linux socket handle */
85   int opt;
86   struct sockaddr_ipx ipxs;
87   int len;
88   struct sockaddr_ipx ipxs2;
89
90   /* DANG_FIXTHIS - kludge to support broken linux IPX stack */
91   /* need to convert dynamic socket open into a real socket number */
92 /*  if (port == 0) {
93     n_printf("IPX: using socket %x\n", nextDynamicSocket);
94     port = nextDynamicSocket++;
95   }
96 */
97   /* do a socket call, then bind to this port */
98   sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
99   if (sock == -1) {
100     n_printf("IPX: could not open IPX socket.\n");
101     return -1;
102   }
103
104 #ifdef DOSEMU
105   opt = 1;
106   /* turn on socket debugging */
107   if (d.network) {
108     enter_priv_on();
109     if (setsockopt(sock, SOL_SOCKET, SO_DEBUG, &opt, sizeof(opt)) == -1) {
110       leave_priv_setting();
111       n_printf("IPX: could not set socket option for debugging.\n");
112       return -1;
113     }
114     leave_priv_setting();
115   }
116 #endif  
117   opt = 1;
118   /* Permit broadcast output */
119   enter_priv_on();
120   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
121                  &opt, sizeof(opt)) == -1) {
122     leave_priv_setting();
123     n_printf("IPX: could not set socket option for broadcast.\n");
124     return -1;
125   }
126 #ifdef DOSEMU
127   /* allow setting the type field in the IPX header */
128   opt = 1;
129 #if 0 /* this seems to be wrong: IPX_TYPE can only be set on level SOL_IPX */
130   if (setsockopt(sock, SOL_SOCKET, IPX_TYPE, &opt, sizeof(opt)) == -1) {
131 #else
132   /* the socket _is_ an IPX socket, hence it first passes ipx_setsockopt()
133    * in file linux/net/ipx/af_ipx.c. This one handles SOL_IPX itself and
134    * passes SOL_SOCKET-levels down to sock_setsockopt().
135    * Hence I guess the below is correct (can somebody please verify this?)
136    * -- Hans, June 14 1997
137    */
138   if (setsockopt(sock, SOL_IPX, IPX_TYPE, &opt, sizeof(opt)) == -1) {
139 #endif
140     leave_priv_setting();
141     n_printf("IPX: could not set socket option for type.\n");
142     return -1;
143   }
144 #endif  
145   ipxs.sipx_family = AF_IPX;
146   ipxs.sipx_network = *((unsigned int *)&ipx_MyAddress[0]);
147 /*  ipxs.sipx_network = htonl(MyNetwork); */
148   bzero(ipxs.sipx_node, 6);     /* Please fill in my node name */
149   ipxs.sipx_port = htons(port);
150
151   /* now bind to this port */
152   if (bind(sock, (struct sockaddr *) &ipxs, sizeof(ipxs)) == -1) {
153     n_printf("IPX: could not bind socket to address\n");
154     close( sock );
155     leave_priv_setting();
156     return -1;
157   }
158   
159   if( port==0 ) {
160     len = sizeof(ipxs2);
161     if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
162       n_printf("IPX: could not get socket name in IPXOpenSocket\n");
163       close( sock );
164       leave_priv_setting();
165       return -1;
166     } else {
167       port = htons(ipxs2.sipx_port);
168       n_printf("IPX: opened dynamic socket %04x\n", port);
169     }
170   }
171   leave_priv_setting();
172   sk->fd = sock;
173   sk->socket = port;
174   return 0;
175 }
176
177 static void ipx_bsd_CloseSocket(ipx_socket_t *mysock) {
178   /* now close the file descriptor for the socket, and free it */
179   n_printf("IPX: closing file descriptor on socket %x\n", mysock->socket);
180   close(mysock->fd);
181 }
182
183 static int ipx_bsd_SendPacket(ipx_socket_t *mysock, IPXPacket_t *IPXHeader,
184  u_char *data, int dataLen) {
185   struct sockaddr_ipx ipxs;
186  
187   ipxs.sipx_family = AF_IPX;
188   /* get destination address from IPX packet header */
189   memcpy(&ipxs.sipx_network, IPXHeader->Destination.Network, 4);
190   /* if destination address is 0, then send to my net */
191   if (ipxs.sipx_network == 0) {
192     ipxs.sipx_network = *((unsigned int *)&ipx_MyAddress[0]);
193 /*  ipxs.sipx_network = htonl(MyNetwork); */
194   }
195   memcpy(&ipxs.sipx_node, IPXHeader->Destination.Node, 6);
196   memcpy(&ipxs.sipx_port, IPXHeader->Destination.Socket, 2);
197   ipxs.sipx_type = IPXHeader->PacketType;
198   /*    ipxs.sipx_port=htons(0x452); */
199   return sendto(mysock->fd, data, dataLen, 0,
200              (struct sockaddr *) &ipxs, sizeof(ipxs));
201 }
202
203 static int ipx_bsd_ReceivePacket(ipx_socket_t *s, char *buffer, int bufsize, 
204  struct ipx_recv_data *rd) {
205         int sz, size;
206         struct sockaddr_ipx ipxs;
207  
208         sz = sizeof(ipxs);
209         if ((size = recvfrom(s->fd, buffer, bufsize, 0,
210              (struct sockaddr *) &ipxs, &sz)) <= 0)
211              return size;
212         memcpy(rd->src_network, &ipxs.sipx_network, 4);
213         memcpy(rd->src_node, ipxs.sipx_node, 6);
214         rd->src_socket = ipxs.sipx_port;
215         rd->dst_socket = s->socket;
216         rd->pkt_type = ipxs.sipx_type;
217   
218         return size;
219 }
220
221 struct ipx_driver ipx_bsd = {
222         ipx_bsd_GetMyAddress,
223         ipx_bsd_OpenSocket,
224         ipx_bsd_CloseSocket,
225         ipx_bsd_SendPacket,
226         ipx_bsd_ReceivePacket,
227         ipx_general_PacketReady
228 };
229 #endif // NETWORK
230 #endif // __ENV_LINUX__