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