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