xref: /netbsd-src/sys/compat/linux/common/linux_socket.c (revision 29c9d4318df6a71325080b99b3d09c7beb19ad6b)
1 /*	$NetBSD: linux_socket.c,v 1.20 1999/05/05 20:01:03 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank van der Linden and Eric Haszlakiewicz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Functions in multiarch:
41  *	linux_sys_socketcall		: linux_socketcall.c
42  */
43 
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/buf.h>
48 #include <sys/malloc.h>
49 #include <sys/ioctl.h>
50 #include <sys/tty.h>
51 #include <sys/file.h>
52 #include <sys/filedesc.h>
53 #include <sys/select.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <net/if.h>
57 #include <netinet/in.h>
58 #include <netinet/tcp.h>
59 #include <sys/mount.h>
60 #include <sys/proc.h>
61 #include <sys/vnode.h>
62 #include <sys/device.h>
63 #include <sys/protosw.h>
64 
65 #include <sys/syscallargs.h>
66 
67 #include <compat/linux/common/linux_types.h>
68 #include <compat/linux/common/linux_util.h>
69 #include <compat/linux/common/linux_signal.h>
70 #include <compat/linux/common/linux_ioctl.h>
71 #include <compat/linux/common/linux_socket.h>
72 #include <compat/linux/common/linux_socketcall.h>
73 #include <compat/linux/common/linux_sockio.h>
74 
75 #include <compat/linux/linux_syscallargs.h>
76 
77 /*
78  * The calls in this file are entered either via the linux_socketcall()
79  * interface or, on the Alpha, as individual syscalls.  The
80  * linux_socketcall function does any massaging of arguments so that all
81  * the calls in here need not think that they are anything other
82  * than a normal syscall.
83  */
84 
85 int linux_to_bsd_domain __P((int));
86 int linux_to_bsd_sopt_level __P((int));
87 int linux_to_bsd_so_sockopt __P((int));
88 int linux_to_bsd_ip_sockopt __P((int));
89 int linux_to_bsd_tcp_sockopt __P((int));
90 int linux_to_bsd_udp_sockopt __P((int));
91 
92 /*
93  * Convert between Linux and BSD socket domain values
94  */
95 int
96 linux_to_bsd_domain(ldom)
97 	int ldom;
98 {
99 
100 	switch (ldom) {
101 	case LINUX_AF_UNSPEC:
102 		return AF_UNSPEC;
103 	case LINUX_AF_UNIX:
104 		return AF_LOCAL;
105 	case LINUX_AF_INET:
106 		return AF_INET;
107 	case LINUX_AF_AX25:
108 		return AF_CCITT;
109 	case LINUX_AF_IPX:
110 		return AF_IPX;
111 	case LINUX_AF_APPLETALK:
112 		return AF_APPLETALK;
113 	case LINUX_AF_X25:
114 		return AF_CCITT;
115 	case LINUX_AF_INET6:
116 		return AF_INET6;
117 	case LINUX_AF_DECnet:
118 		return AF_DECnet;
119 	case LINUX_AF_NETLINK:
120 		return AF_ROUTE;
121 	/* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */
122 	/* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */
123 	default:
124 		return -1;
125 	}
126 }
127 
128 int
129 linux_sys_socket(p, v, retval)
130 	struct proc *p;
131 	void *v;
132 	register_t *retval;
133 {
134 	struct linux_sys_socket_args /* {
135 		syscallarg(int)	domain;
136 		syscallarg(int)	type;
137 		syscallarg(int) protocol;
138 	} */ *uap = v;
139 	struct sys_socket_args bsa;
140 
141 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
142 	SCARG(&bsa, type) = SCARG(uap, type);
143 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
144 	if (SCARG(&bsa, domain) == -1)
145 		return EINVAL;
146 	return sys_socket(p, &bsa, retval);
147 }
148 
149 int
150 linux_sys_socketpair(p, v, retval)
151 	struct proc *p;
152 	void *v;
153 	register_t *retval;
154 {
155 	struct linux_sys_socketpair_args /* {
156 		syscallarg(int) domain;
157 		syscallarg(int) type;
158 		syscallarg(int) protocol;
159 		syscallarg(int *) rsv;
160 	} */ *uap = v;
161 	struct sys_socketpair_args bsa;
162 
163 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
164 	if (SCARG(&bsa, domain) == -1)
165 		return EINVAL;
166 	SCARG(&bsa, type) = SCARG(uap, type);
167 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
168 	SCARG(&bsa, rsv) = SCARG(uap, rsv);
169 
170 	return sys_socketpair(p, &bsa, retval);
171 }
172 
173 int
174 linux_sys_sendto(p, v, retval)
175 	struct proc *p;
176 	void *v;
177 	register_t *retval;
178 {
179 	struct linux_sys_sendto_args /* {
180 		syscallarg(int) s;
181 		syscallarg(void *) msg;
182 		syscallarg(int) len;
183 		syscallarg(int) flags;
184 		syscallarg(sockaddr *) to;
185 		syscallarg(int) tolen;
186 	} */ *uap = v;
187 	struct sys_sendto_args bsa;
188 
189 	SCARG(&bsa, s) = SCARG(uap, s);
190 	SCARG(&bsa, buf) = SCARG(uap, msg);
191 	SCARG(&bsa, len) = SCARG(uap, len);
192 	SCARG(&bsa, flags) = SCARG(uap, flags);
193 	SCARG(&bsa, to) = (void *) SCARG(uap, to);
194 	SCARG(&bsa, tolen) = SCARG(uap, tolen);
195 
196 	return sys_sendto(p, &bsa, retval);
197 }
198 
199 int
200 linux_sys_recvfrom(p, v, retval)
201 	struct proc *p;
202 	void *v;
203 	register_t *retval;
204 {
205 	struct linux_sys_recvfrom_args /* {
206 		syscallarg(int) s;
207 		syscallarg(void *) buf;
208 		syscallarg(int) len;
209 		syscallarg(int) flags;
210 		syscallarg(struct sockaddr *) from;
211 		syscallarg(int *) fromlen;
212 	} */ *uap = v;
213 	struct compat_43_sys_recvfrom_args bra;
214 
215 	SCARG(&bra, s) = SCARG(uap, s);
216 	SCARG(&bra, buf) = SCARG(uap, buf);
217 	SCARG(&bra, len) = SCARG(uap, len);
218 	SCARG(&bra, flags) = SCARG(uap, flags);
219 	SCARG(&bra, from) = (caddr_t) SCARG(uap, from);
220 	SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen);
221 
222 	return compat_43_sys_recvfrom(p, &bra, retval);
223 }
224 
225 /*
226  * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET
227  * is different, the rest matches IPPROTO_* on both systems.
228  */
229 int
230 linux_to_bsd_sopt_level(llevel)
231 	int llevel;
232 {
233 
234 	switch (llevel) {
235 	case LINUX_SOL_SOCKET:
236 		return SOL_SOCKET;
237 	case LINUX_SOL_IP:
238 		return IPPROTO_IP;
239 	case LINUX_SOL_TCP:
240 		return IPPROTO_TCP;
241 	case LINUX_SOL_UDP:
242 		return IPPROTO_UDP;
243 	default:
244 		return -1;
245 	}
246 }
247 
248 /*
249  * Convert Linux socket level socket option numbers to NetBSD values.
250  */
251 int
252 linux_to_bsd_so_sockopt(lopt)
253 	int lopt;
254 {
255 
256 	switch (lopt) {
257 	case LINUX_SO_DEBUG:
258 		return SO_DEBUG;
259 	case LINUX_SO_REUSEADDR:
260 		return SO_REUSEADDR;
261 	case LINUX_SO_TYPE:
262 		return SO_TYPE;
263 	case LINUX_SO_ERROR:
264 		return SO_ERROR;
265 	case LINUX_SO_DONTROUTE:
266 		return SO_DONTROUTE;
267 	case LINUX_SO_BROADCAST:
268 		return SO_BROADCAST;
269 	case LINUX_SO_SNDBUF:
270 		return SO_SNDBUF;
271 	case LINUX_SO_RCVBUF:
272 		return SO_RCVBUF;
273 	case LINUX_SO_KEEPALIVE:
274 		return SO_KEEPALIVE;
275 	case LINUX_SO_OOBINLINE:
276 		return SO_OOBINLINE;
277 	case LINUX_SO_LINGER:
278 		return SO_LINGER;
279 	case LINUX_SO_PRIORITY:
280 	case LINUX_SO_NO_CHECK:
281 	default:
282 		return -1;
283 	}
284 }
285 
286 /*
287  * Convert Linux IP level socket option number to NetBSD values.
288  */
289 int
290 linux_to_bsd_ip_sockopt(lopt)
291 	int lopt;
292 {
293 
294 	switch (lopt) {
295 	case LINUX_IP_TOS:
296 		return IP_TOS;
297 	case LINUX_IP_TTL:
298 		return IP_TTL;
299 	case LINUX_IP_MULTICAST_TTL:
300 		return IP_MULTICAST_TTL;
301 	case LINUX_IP_MULTICAST_LOOP:
302 		return IP_MULTICAST_LOOP;
303 	case LINUX_IP_MULTICAST_IF:
304 		return IP_MULTICAST_IF;
305 	case LINUX_IP_ADD_MEMBERSHIP:
306 		return IP_ADD_MEMBERSHIP;
307 	case LINUX_IP_DROP_MEMBERSHIP:
308 		return IP_DROP_MEMBERSHIP;
309 	default:
310 		return -1;
311 	}
312 }
313 
314 /*
315  * Convert Linux TCP level socket option number to NetBSD values.
316  */
317 int
318 linux_to_bsd_tcp_sockopt(lopt)
319 	int lopt;
320 {
321 
322 	switch (lopt) {
323 	case LINUX_TCP_NODELAY:
324 		return TCP_NODELAY;
325 	case LINUX_TCP_MAXSEG:
326 		return TCP_MAXSEG;
327 	default:
328 		return -1;
329 	}
330 }
331 
332 /*
333  * Convert Linux UDP level socket option number to NetBSD values.
334  */
335 int
336 linux_to_bsd_udp_sockopt(lopt)
337 	int lopt;
338 {
339 
340 	switch (lopt) {
341 	default:
342 		return -1;
343 	}
344 }
345 
346 /*
347  * Another reasonably straightforward function: setsockopt(2).
348  * The level and option numbers are converted; the values passed
349  * are not (yet) converted, the ones currently implemented don't
350  * need conversion, as they are the same on both systems.
351  */
352 int
353 linux_sys_setsockopt(p, v, retval)
354 	struct proc *p;
355 	void *v;
356 	register_t *retval;
357 {
358 	struct linux_sys_setsockopt_args /* {
359 		syscallarg(int) s;
360 		syscallarg(int) level;
361 		syscallarg(int) optname;
362 		syscallarg(void *) optval;
363 		syscallarg(int) optlen;
364 	} */ *uap = v;
365 	struct sys_setsockopt_args bsa;
366 	int name;
367 
368 	SCARG(&bsa, s) = SCARG(uap, s);
369 	SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
370 	SCARG(&bsa, val) = SCARG(uap, optval);
371 	SCARG(&bsa, valsize) = SCARG(uap, optlen);
372 
373 	switch (SCARG(&bsa, level)) {
374 		case SOL_SOCKET:
375 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
376 			break;
377 		case IPPROTO_IP:
378 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
379 			break;
380 		case IPPROTO_TCP:
381 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
382 			break;
383 		case IPPROTO_UDP:
384 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
385 			break;
386 		default:
387 			return EINVAL;
388 	}
389 
390 	if (name == -1)
391 		return EINVAL;
392 	SCARG(&bsa, name) = name;
393 
394 	return sys_setsockopt(p, &bsa, retval);
395 }
396 
397 /*
398  * getsockopt(2) is very much the same as setsockopt(2) (see above)
399  */
400 int
401 linux_sys_getsockopt(p, v, retval)
402 	struct proc *p;
403 	void *v;
404 	register_t *retval;
405 {
406 	struct linux_sys_getsockopt_args /* {
407 		syscallarg(int) s;
408 		syscallarg(int) level;
409 		syscallarg(int) optname;
410 		syscallarg(void *) optval;
411 		syscallarg(int *) optlen;
412 	} */ *uap = v;
413 	struct sys_getsockopt_args bga;
414 	int name;
415 
416 	SCARG(&bga, s) = SCARG(uap, s);
417 	SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
418 	SCARG(&bga, val) = SCARG(uap, optval);
419 	SCARG(&bga, avalsize) = SCARG(uap, optlen);
420 
421 	switch (SCARG(&bga, level)) {
422 		case SOL_SOCKET:
423 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
424 			break;
425 		case IPPROTO_IP:
426 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
427 			break;
428 		case IPPROTO_TCP:
429 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
430 			break;
431 		case IPPROTO_UDP:
432 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
433 			break;
434 		default:
435 			return EINVAL;
436 	}
437 
438 	if (name == -1)
439 		return EINVAL;
440 	SCARG(&bga, name) = name;
441 
442 	return sys_getsockopt(p, &bga, retval);
443 }
444 
445 int
446 linux_ioctl_socket(p, uap, retval)
447 	register struct proc *p;
448 	register struct linux_sys_ioctl_args /* {
449 		syscallarg(int) fd;
450 		syscallarg(u_long) com;
451 		syscallarg(caddr_t) data;
452 	} */ *uap;
453 	register_t *retval;
454 {
455 	u_long com;
456 	struct sys_ioctl_args ia;
457 
458 	com = SCARG(uap, com);
459 	retval[0] = 0;
460 
461 	switch (com) {
462 	case LINUX_SIOCGIFCONF:
463 		SCARG(&ia, com) = OSIOCGIFCONF;
464 		break;
465 	case LINUX_SIOCGIFFLAGS:
466 		SCARG(&ia, com) = SIOCGIFFLAGS;
467 		break;
468 	case LINUX_SIOCGIFADDR:
469 		SCARG(&ia, com) = OSIOCGIFADDR;
470 		break;
471 	case LINUX_SIOCGIFDSTADDR:
472 		SCARG(&ia, com) = OSIOCGIFDSTADDR;
473 		break;
474 	case LINUX_SIOCGIFBRDADDR:
475 		SCARG(&ia, com) = OSIOCGIFBRDADDR;
476 		break;
477 	case LINUX_SIOCGIFNETMASK:
478 		SCARG(&ia, com) = OSIOCGIFNETMASK;
479 		break;
480 	case LINUX_SIOCADDMULTI:
481 		SCARG(&ia, com) = SIOCADDMULTI;
482 		break;
483 	case LINUX_SIOCDELMULTI:
484 		SCARG(&ia, com) = SIOCDELMULTI;
485 		break;
486 	default:
487 		return EINVAL;
488 	}
489 
490 	SCARG(&ia, fd) = SCARG(uap, fd);
491 	SCARG(&ia, data) = SCARG(uap, data);
492 	return sys_ioctl(p, &ia, retval);
493 }
494 
495 int
496 linux_sys_connect(p, v, retval)
497 	register struct proc *p;
498 	void *v;
499 	register_t *retval;
500 {
501 	int error;
502 
503 	register struct sys_connect_args /* {
504 		syscallarg(int) s;
505 		syscallarg(const struct sockaddr *) name;
506 		syscallarg(unsigned int) namelen;
507 	} */ *uap = v;
508 
509 	error = sys_connect (p, v, retval);
510 
511 	if (error == EISCONN) {
512 		struct file *fp;
513 		register struct socket *so;
514 		int s, state, prflags;
515 
516 		/* getsock() will use the descriptor for us */
517 	    	if (getsock(p->p_fd, SCARG(uap, s), &fp) != 0)
518 		    	return EISCONN;
519 
520 		s = splsoftnet();
521 		so = (struct socket *)fp->f_data;
522 		state = so->so_state;
523 		prflags = so->so_proto->pr_flags;
524 		splx(s);
525 		FILE_UNUSE(fp, p);
526 		/*
527 		 * We should only let this call succeed once per
528 		 * non-blocking connect; however we don't have
529 		 * a convenient place to keep that state..
530 		 */
531 		if ((state & SS_NBIO) && (state & SS_ISCONNECTED) &&
532 		    (prflags & PR_CONNREQUIRED))
533 			return 0;
534 	}
535 
536 	return error;
537 }
538