xref: /netbsd-src/sys/compat/linux/common/linux_socket.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
1 /*	$NetBSD: linux_socket.c,v 1.18 1998/10/04 00:02:43 fvdl 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 
64 #include <sys/syscallargs.h>
65 
66 #include <compat/linux/common/linux_types.h>
67 #include <compat/linux/common/linux_util.h>
68 #include <compat/linux/common/linux_signal.h>
69 #include <compat/linux/common/linux_ioctl.h>
70 #include <compat/linux/common/linux_socket.h>
71 #include <compat/linux/common/linux_socketcall.h>
72 #include <compat/linux/common/linux_sockio.h>
73 
74 #include <compat/linux/linux_syscallargs.h>
75 
76 /*
77  * The calls in this file are entered either via the linux_socketcall()
78  * interface or, on the Alpha, as individual syscalls.  The
79  * linux_socketcall function does any massaging of arguments so that all
80  * the calls in here need not think that they are anything other
81  * than a normal syscall.
82  */
83 
84 int linux_to_bsd_domain __P((int));
85 int linux_to_bsd_sopt_level __P((int));
86 int linux_to_bsd_so_sockopt __P((int));
87 int linux_to_bsd_ip_sockopt __P((int));
88 int linux_to_bsd_tcp_sockopt __P((int));
89 int linux_to_bsd_udp_sockopt __P((int));
90 
91 /*
92  * Convert between Linux and BSD socket domain values
93  */
94 int
95 linux_to_bsd_domain(ldom)
96 	int ldom;
97 {
98 
99 	switch (ldom) {
100 	case LINUX_AF_UNSPEC:
101 		return AF_UNSPEC;
102 	case LINUX_AF_UNIX:
103 		return AF_LOCAL;
104 	case LINUX_AF_INET:
105 		return AF_INET;
106 	case LINUX_AF_AX25:
107 		return AF_CCITT;
108 	case LINUX_AF_IPX:
109 		return AF_IPX;
110 	case LINUX_AF_APPLETALK:
111 		return AF_APPLETALK;
112 	case LINUX_AF_X25:
113 		return AF_CCITT;
114 	case LINUX_AF_INET6:
115 		return AF_INET6;
116 	case LINUX_AF_DECnet:
117 		return AF_DECnet;
118 	case LINUX_AF_NETLINK:
119 		return AF_ROUTE;
120 	/* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */
121 	/* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */
122 	default:
123 		return -1;
124 	}
125 }
126 
127 int
128 linux_sys_socket(p, v, retval)
129 	struct proc *p;
130 	void *v;
131 	register_t *retval;
132 {
133 	struct linux_sys_socket_args /* {
134 		syscallarg(int)	domain;
135 		syscallarg(int)	type;
136 		syscallarg(int) protocol;
137 	} */ *uap = v;
138 	struct sys_socket_args bsa;
139 
140 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
141 	SCARG(&bsa, type) = SCARG(uap, type);
142 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
143 	if (SCARG(&bsa, domain) == -1)
144 		return EINVAL;
145 	return sys_socket(p, &bsa, retval);
146 }
147 
148 int
149 linux_sys_socketpair(p, v, retval)
150 	struct proc *p;
151 	void *v;
152 	register_t *retval;
153 {
154 	struct linux_sys_socketpair_args /* {
155 		syscallarg(int) domain;
156 		syscallarg(int) type;
157 		syscallarg(int) protocol;
158 		syscallarg(int *) rsv;
159 	} */ *uap = v;
160 	struct sys_socketpair_args bsa;
161 
162 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
163 	if (SCARG(&bsa, domain) == -1)
164 		return EINVAL;
165 	SCARG(&bsa, type) = SCARG(uap, type);
166 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
167 	SCARG(&bsa, rsv) = SCARG(uap, rsv);
168 
169 	return sys_socketpair(p, &bsa, retval);
170 }
171 
172 int
173 linux_sys_sendto(p, v, retval)
174 	struct proc *p;
175 	void *v;
176 	register_t *retval;
177 {
178 	struct linux_sys_sendto_args /* {
179 		syscallarg(int) s;
180 		syscallarg(void *) msg;
181 		syscallarg(int) len;
182 		syscallarg(int) flags;
183 		syscallarg(sockaddr *) to;
184 		syscallarg(int) tolen;
185 	} */ *uap = v;
186 	struct sys_sendto_args bsa;
187 
188 	SCARG(&bsa, s) = SCARG(uap, s);
189 	SCARG(&bsa, buf) = SCARG(uap, msg);
190 	SCARG(&bsa, len) = SCARG(uap, len);
191 	SCARG(&bsa, flags) = SCARG(uap, flags);
192 	SCARG(&bsa, to) = (void *) SCARG(uap, to);
193 	SCARG(&bsa, tolen) = SCARG(uap, tolen);
194 
195 	return sys_sendto(p, &bsa, retval);
196 }
197 
198 int
199 linux_sys_recvfrom(p, v, retval)
200 	struct proc *p;
201 	void *v;
202 	register_t *retval;
203 {
204 	struct linux_sys_recvfrom_args /* {
205 		syscallarg(int) s;
206 		syscallarg(void *) buf;
207 		syscallarg(int) len;
208 		syscallarg(int) flags;
209 		syscallarg(struct sockaddr *) from;
210 		syscallarg(int *) fromlen;
211 	} */ *uap = v;
212 	struct compat_43_sys_recvfrom_args bra;
213 
214 	SCARG(&bra, s) = SCARG(uap, s);
215 	SCARG(&bra, buf) = SCARG(uap, buf);
216 	SCARG(&bra, len) = SCARG(uap, len);
217 	SCARG(&bra, flags) = SCARG(uap, flags);
218 	SCARG(&bra, from) = (caddr_t) SCARG(uap, from);
219 	SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen);
220 
221 	return compat_43_sys_recvfrom(p, &bra, retval);
222 }
223 
224 /*
225  * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET
226  * is different, the rest matches IPPROTO_* on both systems.
227  */
228 int
229 linux_to_bsd_sopt_level(llevel)
230 	int llevel;
231 {
232 
233 	switch (llevel) {
234 	case LINUX_SOL_SOCKET:
235 		return SOL_SOCKET;
236 	case LINUX_SOL_IP:
237 		return IPPROTO_IP;
238 	case LINUX_SOL_TCP:
239 		return IPPROTO_TCP;
240 	case LINUX_SOL_UDP:
241 		return IPPROTO_UDP;
242 	default:
243 		return -1;
244 	}
245 }
246 
247 /*
248  * Convert Linux socket level socket option numbers to NetBSD values.
249  */
250 int
251 linux_to_bsd_so_sockopt(lopt)
252 	int lopt;
253 {
254 
255 	switch (lopt) {
256 	case LINUX_SO_DEBUG:
257 		return SO_DEBUG;
258 	case LINUX_SO_REUSEADDR:
259 		return SO_REUSEADDR;
260 	case LINUX_SO_TYPE:
261 		return SO_TYPE;
262 	case LINUX_SO_ERROR:
263 		return SO_ERROR;
264 	case LINUX_SO_DONTROUTE:
265 		return SO_DONTROUTE;
266 	case LINUX_SO_BROADCAST:
267 		return SO_BROADCAST;
268 	case LINUX_SO_SNDBUF:
269 		return SO_SNDBUF;
270 	case LINUX_SO_RCVBUF:
271 		return SO_RCVBUF;
272 	case LINUX_SO_KEEPALIVE:
273 		return SO_KEEPALIVE;
274 	case LINUX_SO_OOBINLINE:
275 		return SO_OOBINLINE;
276 	case LINUX_SO_LINGER:
277 		return SO_LINGER;
278 	case LINUX_SO_PRIORITY:
279 	case LINUX_SO_NO_CHECK:
280 	default:
281 		return -1;
282 	}
283 }
284 
285 /*
286  * Convert Linux IP level socket option number to NetBSD values.
287  */
288 int
289 linux_to_bsd_ip_sockopt(lopt)
290 	int lopt;
291 {
292 
293 	switch (lopt) {
294 	case LINUX_IP_TOS:
295 		return IP_TOS;
296 	case LINUX_IP_TTL:
297 		return IP_TTL;
298 	case LINUX_IP_MULTICAST_TTL:
299 		return IP_MULTICAST_TTL;
300 	case LINUX_IP_MULTICAST_LOOP:
301 		return IP_MULTICAST_LOOP;
302 	case LINUX_IP_MULTICAST_IF:
303 		return IP_MULTICAST_IF;
304 	case LINUX_IP_ADD_MEMBERSHIP:
305 		return IP_ADD_MEMBERSHIP;
306 	case LINUX_IP_DROP_MEMBERSHIP:
307 		return IP_DROP_MEMBERSHIP;
308 	default:
309 		return -1;
310 	}
311 }
312 
313 /*
314  * Convert Linux TCP level socket option number to NetBSD values.
315  */
316 int
317 linux_to_bsd_tcp_sockopt(lopt)
318 	int lopt;
319 {
320 
321 	switch (lopt) {
322 	case LINUX_TCP_NODELAY:
323 		return TCP_NODELAY;
324 	case LINUX_TCP_MAXSEG:
325 		return TCP_MAXSEG;
326 	default:
327 		return -1;
328 	}
329 }
330 
331 /*
332  * Convert Linux UDP level socket option number to NetBSD values.
333  */
334 int
335 linux_to_bsd_udp_sockopt(lopt)
336 	int lopt;
337 {
338 
339 	switch (lopt) {
340 	default:
341 		return -1;
342 	}
343 }
344 
345 /*
346  * Another reasonably straightforward function: setsockopt(2).
347  * The level and option numbers are converted; the values passed
348  * are not (yet) converted, the ones currently implemented don't
349  * need conversion, as they are the same on both systems.
350  */
351 int
352 linux_sys_setsockopt(p, v, retval)
353 	struct proc *p;
354 	void *v;
355 	register_t *retval;
356 {
357 	struct linux_sys_setsockopt_args /* {
358 		syscallarg(int) s;
359 		syscallarg(int) level;
360 		syscallarg(int) optname;
361 		syscallarg(void *) optval;
362 		syscallarg(int) optlen;
363 	} */ *uap = v;
364 	struct sys_setsockopt_args bsa;
365 	int name;
366 
367 	SCARG(&bsa, s) = SCARG(uap, s);
368 	SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
369 	SCARG(&bsa, val) = SCARG(uap, optval);
370 	SCARG(&bsa, valsize) = SCARG(uap, optlen);
371 
372 	switch (SCARG(&bsa, level)) {
373 		case SOL_SOCKET:
374 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
375 			break;
376 		case IPPROTO_IP:
377 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
378 			break;
379 		case IPPROTO_TCP:
380 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
381 			break;
382 		case IPPROTO_UDP:
383 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
384 			break;
385 		default:
386 			return EINVAL;
387 	}
388 
389 	if (name == -1)
390 		return EINVAL;
391 	SCARG(&bsa, name) = name;
392 
393 	return sys_setsockopt(p, &bsa, retval);
394 }
395 
396 /*
397  * getsockopt(2) is very much the same as setsockopt(2) (see above)
398  */
399 int
400 linux_sys_getsockopt(p, v, retval)
401 	struct proc *p;
402 	void *v;
403 	register_t *retval;
404 {
405 	struct linux_sys_getsockopt_args /* {
406 		syscallarg(int) s;
407 		syscallarg(int) level;
408 		syscallarg(int) optname;
409 		syscallarg(void *) optval;
410 		syscallarg(int *) optlen;
411 	} */ *uap = v;
412 	struct sys_getsockopt_args bga;
413 	int name;
414 
415 	SCARG(&bga, s) = SCARG(uap, s);
416 	SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
417 	SCARG(&bga, val) = SCARG(uap, optval);
418 	SCARG(&bga, avalsize) = SCARG(uap, optlen);
419 
420 	switch (SCARG(&bga, level)) {
421 		case SOL_SOCKET:
422 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
423 			break;
424 		case IPPROTO_IP:
425 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
426 			break;
427 		case IPPROTO_TCP:
428 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
429 			break;
430 		case IPPROTO_UDP:
431 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
432 			break;
433 		default:
434 			return EINVAL;
435 	}
436 
437 	if (name == -1)
438 		return EINVAL;
439 	SCARG(&bga, name) = name;
440 
441 	return sys_getsockopt(p, &bga, retval);
442 }
443 
444 int
445 linux_ioctl_socket(p, uap, retval)
446 	register struct proc *p;
447 	register struct linux_sys_ioctl_args /* {
448 		syscallarg(int) fd;
449 		syscallarg(u_long) com;
450 		syscallarg(caddr_t) data;
451 	} */ *uap;
452 	register_t *retval;
453 {
454 	u_long com;
455 	struct sys_ioctl_args ia;
456 
457 	com = SCARG(uap, com);
458 	retval[0] = 0;
459 
460 	switch (com) {
461 	case LINUX_SIOCGIFCONF:
462 		SCARG(&ia, com) = OSIOCGIFCONF;
463 		break;
464 	case LINUX_SIOCGIFFLAGS:
465 		SCARG(&ia, com) = SIOCGIFFLAGS;
466 		break;
467 	case LINUX_SIOCGIFADDR:
468 		SCARG(&ia, com) = OSIOCGIFADDR;
469 		break;
470 	case LINUX_SIOCGIFDSTADDR:
471 		SCARG(&ia, com) = OSIOCGIFDSTADDR;
472 		break;
473 	case LINUX_SIOCGIFBRDADDR:
474 		SCARG(&ia, com) = OSIOCGIFBRDADDR;
475 		break;
476 	case LINUX_SIOCGIFNETMASK:
477 		SCARG(&ia, com) = OSIOCGIFNETMASK;
478 		break;
479 	case LINUX_SIOCADDMULTI:
480 		SCARG(&ia, com) = SIOCADDMULTI;
481 		break;
482 	case LINUX_SIOCDELMULTI:
483 		SCARG(&ia, com) = SIOCDELMULTI;
484 		break;
485 	default:
486 		return EINVAL;
487 	}
488 
489 	SCARG(&ia, fd) = SCARG(uap, fd);
490 	SCARG(&ia, data) = SCARG(uap, data);
491 	return sys_ioctl(p, &ia, retval);
492 }
493