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