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