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