xref: /freebsd/sys/compat/linux/linux_socket.c (revision eb00d48411fa0c9a910d0bafa0d7080dcb979702)
1 /*-
2  * Copyright (c) 1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_socket.c,v 1.7 1997/02/22 09:38:25 peter Exp $
29  */
30 
31 /* XXX we use functions that might not exist. */
32 #define	COMPAT_43	1
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysproto.h>
37 #include <sys/socket.h>
38 
39 #include <netinet/in.h>
40 
41 #include <i386/linux/linux.h>
42 #include <i386/linux/linux_proto.h>
43 
44 static int
45 linux_to_bsd_domain(int domain)
46 {
47     switch (domain) {
48     case LINUX_AF_UNSPEC:
49 	return AF_UNSPEC;
50     case LINUX_AF_UNIX:
51 	return AF_LOCAL;
52     case LINUX_AF_INET:
53 	return AF_INET;
54     case LINUX_AF_AX25:
55 	return AF_CCITT;
56     case LINUX_AF_IPX:
57 	return AF_IPX;
58     case LINUX_AF_APPLETALK:
59 	return AF_APPLETALK;
60     default:
61 	return -1;
62     }
63 }
64 
65 static int
66 linux_to_bsd_sockopt_level(int level)
67 {
68     switch (level) {
69     case LINUX_SOL_SOCKET:
70 	return SOL_SOCKET;
71     default:
72 	return level;
73     }
74 }
75 
76 static int linux_to_bsd_ip_sockopt(int opt)
77 {
78     switch (opt) {
79     case LINUX_IP_TOS:
80 	return IP_TOS;
81     case LINUX_IP_TTL:
82 	return IP_TTL;
83     case LINUX_IP_OPTIONS:
84 	return IP_OPTIONS;
85     case LINUX_IP_MULTICAST_IF:
86 	return IP_MULTICAST_IF;
87     case LINUX_IP_MULTICAST_TTL:
88 	return IP_MULTICAST_TTL;
89     case LINUX_IP_MULTICAST_LOOP:
90 	return IP_MULTICAST_LOOP;
91     case LINUX_IP_ADD_MEMBERSHIP:
92 	return IP_ADD_MEMBERSHIP;
93     case LINUX_IP_DROP_MEMBERSHIP:
94 	return IP_DROP_MEMBERSHIP;
95     case LINUX_IP_HDRINCL:
96     default:
97 	return -1;
98     }
99 }
100 
101 static int
102 linux_to_bsd_so_sockopt(int opt)
103 {
104     switch (opt) {
105     case LINUX_SO_DEBUG:
106 	return SO_DEBUG;
107     case LINUX_SO_REUSEADDR:
108 	return SO_REUSEADDR;
109     case LINUX_SO_TYPE:
110 	return SO_TYPE;
111     case LINUX_SO_ERROR:
112 	return SO_ERROR;
113     case LINUX_SO_DONTROUTE:
114 	return SO_DONTROUTE;
115     case LINUX_SO_BROADCAST:
116 	return SO_BROADCAST;
117     case LINUX_SO_SNDBUF:
118 	return SO_SNDBUF;
119     case LINUX_SO_RCVBUF:
120 	return SO_RCVBUF;
121     case LINUX_SO_KEEPALIVE:
122 	return SO_KEEPALIVE;
123     case LINUX_SO_OOBINLINE:
124 	return SO_OOBINLINE;
125     case LINUX_SO_LINGER:
126 	return SO_LINGER;
127     case LINUX_SO_PRIORITY:
128     case LINUX_SO_NO_CHECK:
129     default:
130 	return -1;
131     }
132 }
133 
134 struct linux_socket_args {
135     int domain;
136     int type;
137     int protocol;
138 };
139 
140 static int
141 linux_socket(struct proc *p, struct linux_socket_args *args, int *retval)
142 {
143     struct linux_socket_args linux_args;
144     struct socket_args /* {
145 	int domain;
146 	int type;
147 	int protocol;
148     } */ bsd_args;
149     int error;
150 
151     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
152 	return error;
153     bsd_args.protocol = linux_args.protocol;
154     bsd_args.type = linux_args.type;
155     bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
156     if (bsd_args.domain == -1)
157 	return EINVAL;
158     return socket(p, &bsd_args, retval);
159 }
160 
161 struct linux_bind_args {
162     int s;
163     struct sockaddr *name;
164     int namelen;
165 };
166 
167 static int
168 linux_bind(struct proc *p, struct linux_bind_args *args, int *retval)
169 {
170     struct linux_bind_args linux_args;
171     struct bind_args /* {
172 	int s;
173 	caddr_t name;
174 	int namelen;
175     } */ bsd_args;
176     int error;
177 
178     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
179 	return error;
180     bsd_args.s = linux_args.s;
181     bsd_args.name = (caddr_t)linux_args.name;
182     bsd_args.namelen = linux_args.namelen;
183     return bind(p, &bsd_args, retval);
184 }
185 
186 struct linux_connect_args {
187     int s;
188     struct sockaddr * name;
189     int namelen;
190 };
191 
192 static int
193 linux_connect(struct proc *p, struct linux_connect_args *args, int *retval)
194 {
195     struct linux_connect_args linux_args;
196     struct connect_args /* {
197 	int s;
198 	caddr_t name;
199 	int namelen;
200     } */ bsd_args;
201     int error;
202 
203     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
204 	return error;
205     bsd_args.s = linux_args.s;
206     bsd_args.name = (caddr_t)linux_args.name;
207     bsd_args.namelen = linux_args.namelen;
208     return connect(p, &bsd_args, retval);
209 }
210 
211 struct linux_listen_args {
212     int s;
213     int backlog;
214 };
215 
216 static int
217 linux_listen(struct proc *p, struct linux_listen_args *args, int *retval)
218 {
219     struct linux_listen_args linux_args;
220     struct listen_args /* {
221 	int s;
222 	int backlog;
223     } */ bsd_args;
224     int error;
225 
226     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
227 	return error;
228     bsd_args.s = linux_args.s;
229     bsd_args.backlog = linux_args.backlog;
230     return listen(p, &bsd_args, retval);
231 }
232 
233 struct linux_accept_args {
234     int s;
235     struct sockaddr *addr;
236     int *namelen;
237 };
238 
239 static int
240 linux_accept(struct proc *p, struct linux_accept_args *args, int *retval)
241 {
242     struct linux_accept_args linux_args;
243     struct accept_args /* {
244 	int s;
245 	caddr_t name;
246 	int *anamelen;
247     } */ bsd_args;
248     int error;
249 
250     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
251 	return error;
252     bsd_args.s = linux_args.s;
253     bsd_args.name = (caddr_t)linux_args.addr;
254     bsd_args.anamelen = linux_args.namelen;
255     return oaccept(p, &bsd_args, retval);
256 }
257 
258 struct linux_getsockname_args {
259     int s;
260     struct sockaddr *addr;
261     int *namelen;
262 };
263 
264 static int
265 linux_getsockname(struct proc *p, struct linux_getsockname_args *args, int *retval)
266 {
267     struct linux_getsockname_args linux_args;
268     struct getsockname_args /* {
269 	int fdes;
270 	caddr_t asa;
271 	int *alen;
272     } */ bsd_args;
273     int error;
274 
275     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
276 	return error;
277     bsd_args.fdes = linux_args.s;
278     bsd_args.asa = (caddr_t) linux_args.addr;
279     bsd_args.alen = linux_args.namelen;
280     return ogetsockname(p, &bsd_args, retval);
281 }
282 
283 struct linux_getpeername_args {
284     int s;
285     struct sockaddr *addr;
286     int *namelen;
287 };
288 
289 static int
290 linux_getpeername(struct proc *p, struct linux_getpeername_args *args, int *retval)
291 {
292     struct linux_getpeername_args linux_args;
293     struct ogetpeername_args /* {
294 	int fdes;
295 	caddr_t asa;
296 	int *alen;
297     } */ bsd_args;
298     int error;
299 
300     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
301 	return error;
302     bsd_args.fdes = linux_args.s;
303     bsd_args.asa = (caddr_t) linux_args.addr;
304     bsd_args.alen = linux_args.namelen;
305     return ogetpeername(p, &bsd_args, retval);
306 }
307 
308 struct linux_socketpair_args {
309     int domain;
310     int type;
311     int protocol;
312     int *rsv;
313 };
314 
315 static int
316 linux_socketpair(struct proc *p, struct linux_socketpair_args *args, int *retval)
317 {
318     struct linux_socketpair_args linux_args;
319     struct socketpair_args /* {
320 	int domain;
321 	int type;
322 	int protocol;
323 	int *rsv;
324     } */ bsd_args;
325     int error;
326 
327     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
328 	return error;
329     bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
330     if (bsd_args.domain == -1)
331 	return EINVAL;
332     bsd_args.type = linux_args.type;
333     bsd_args.protocol = linux_args.protocol;
334     bsd_args.rsv = linux_args.rsv;
335     return socketpair(p, &bsd_args, retval);
336 }
337 
338 struct linux_send_args {
339     int s;
340     void *msg;
341     int len;
342     int flags;
343 };
344 
345 static int
346 linux_send(struct proc *p, struct linux_send_args *args, int *retval)
347 {
348     struct linux_send_args linux_args;
349     struct osend_args /* {
350 	int s;
351 	caddr_t buf;
352 	int len;
353 	int flags;
354     } */ bsd_args;
355     int error;
356 
357     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
358 	return error;
359     bsd_args.s = linux_args.s;
360     bsd_args.buf = linux_args.msg;
361     bsd_args.len = linux_args.len;
362     bsd_args.flags = linux_args.flags;
363     return osend(p, &bsd_args, retval);
364 }
365 
366 struct linux_recv_args {
367     int s;
368     void *msg;
369     int len;
370     int flags;
371 };
372 
373 static int
374 linux_recv(struct proc *p, struct linux_recv_args *args, int *retval)
375 {
376     struct linux_recv_args linux_args;
377     struct orecv_args /* {
378 	int s;
379 	caddr_t buf;
380 	int len;
381 	int flags;
382     } */ bsd_args;
383     int error;
384 
385     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
386 	return error;
387     bsd_args.s = linux_args.s;
388     bsd_args.buf = linux_args.msg;
389     bsd_args.len = linux_args.len;
390     bsd_args.flags = linux_args.flags;
391     return orecv(p, &bsd_args, retval);
392 }
393 
394 struct linux_sendto_args {
395     int s;
396     void *msg;
397     int len;
398     int flags;
399     caddr_t to;
400     int tolen;
401 };
402 
403 static int
404 linux_sendto(struct proc *p, struct linux_sendto_args *args, int *retval)
405 {
406     struct linux_sendto_args linux_args;
407     struct sendto_args /* {
408 	int s;
409 	caddr_t buf;
410 	size_t len;
411 	int flags;
412 	caddr_t to;
413 	int tolen;
414     } */ bsd_args;
415     int error;
416 
417     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
418 	return error;
419     bsd_args.s = linux_args.s;
420     bsd_args.buf = linux_args.msg;
421     bsd_args.len = linux_args.len;
422     bsd_args.flags = linux_args.flags;
423     bsd_args.to = linux_args.to;
424     bsd_args.tolen = linux_args.tolen;
425     return sendto(p, &bsd_args, retval);
426 }
427 
428 struct linux_recvfrom_args {
429     int s;
430     void *buf;
431     int len;
432     int flags;
433     caddr_t from;
434     int *fromlen;
435 };
436 
437 static int
438 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args, int *retval)
439 {
440     struct linux_recvfrom_args linux_args;
441     struct recvfrom_args /* {
442 	int s;
443 	caddr_t buf;
444 	size_t len;
445 	int flags;
446 	caddr_t from;
447 	int *fromlenaddr;
448     } */ bsd_args;
449     int error;
450 
451     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
452 	return error;
453     bsd_args.s = linux_args.s;
454     bsd_args.buf = linux_args.buf;
455     bsd_args.len = linux_args.len;
456     bsd_args.flags = linux_args.flags;
457     bsd_args.from = linux_args.from;
458     bsd_args.fromlenaddr = linux_args.fromlen;
459     return orecvfrom(p, &bsd_args, retval);
460 }
461 
462 struct linux_shutdown_args {
463     int s;
464     int how;
465 };
466 
467 static int
468 linux_shutdown(struct proc *p, struct linux_shutdown_args *args, int *retval)
469 {
470     struct linux_shutdown_args linux_args;
471     struct shutdown_args /* {
472 	int s;
473 	int how;
474     } */ bsd_args;
475     int error;
476 
477     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
478 	return error;
479     bsd_args.s = linux_args.s;
480     bsd_args.how = linux_args.how;
481     return shutdown(p, &bsd_args, retval);
482 }
483 
484 struct linux_setsockopt_args {
485     int s;
486     int level;
487     int optname;
488     void *optval;
489     int optlen;
490 };
491 
492 static int
493 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args, int *retval)
494 {
495     struct linux_setsockopt_args linux_args;
496     struct setsockopt_args /* {
497 	int s;
498 	int level;
499 	int name;
500 	caddr_t val;
501 	int valsize;
502     } */ bsd_args;
503     int error, name;
504 
505     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
506 	return error;
507     bsd_args.s = linux_args.s;
508     bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
509     switch (bsd_args.level) {
510     case SOL_SOCKET:
511 	name = linux_to_bsd_so_sockopt(linux_args.optname);
512 	break;
513     case IPPROTO_IP:
514 	name = linux_to_bsd_ip_sockopt(linux_args.optname);
515 	break;
516     default:
517 	return EINVAL;
518     }
519     if (name == -1)
520 	return EINVAL;
521     bsd_args.name = name;
522     bsd_args.val = linux_args.optval;
523     bsd_args.valsize = linux_args.optlen;
524     return setsockopt(p, &bsd_args, retval);
525 }
526 
527 struct linux_getsockopt_args {
528     int s;
529     int level;
530     int optname;
531     void *optval;
532     int *optlen;
533 };
534 
535 static int
536 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args, int *retval)
537 {
538     struct linux_getsockopt_args linux_args;
539     struct getsockopt_args /* {
540 	int s;
541 	int level;
542 	int name;
543 	caddr_t val;
544 	int *avalsize;
545     } */ bsd_args;
546     int error, name;
547 
548     if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
549 	return error;
550     bsd_args.s = linux_args.s;
551     bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
552     switch (bsd_args.level) {
553     case SOL_SOCKET:
554 	name = linux_to_bsd_so_sockopt(linux_args.optname);
555 	break;
556     case IPPROTO_IP:
557 	name = linux_to_bsd_ip_sockopt(linux_args.optname);
558 	break;
559     default:
560 	return EINVAL;
561     }
562     if (name == -1)
563 	return EINVAL;
564     bsd_args.val = linux_args.optval;
565     bsd_args.avalsize = linux_args.optlen;
566     return getsockopt(p, &bsd_args, retval);
567 }
568 
569 int
570 linux_socketcall(struct proc *p, struct linux_socketcall_args *args,int *retval)
571 {
572     switch (args->what) {
573     case LINUX_SOCKET:
574 	return linux_socket(p, args->args, retval);
575     case LINUX_BIND:
576 	return linux_bind(p, args->args, retval);
577     case LINUX_CONNECT:
578 	return linux_connect(p, args->args, retval);
579     case LINUX_LISTEN:
580 	return linux_listen(p, args->args, retval);
581     case LINUX_ACCEPT:
582 	return linux_accept(p, args->args, retval);
583     case LINUX_GETSOCKNAME:
584 	return linux_getsockname(p, args->args, retval);
585     case LINUX_GETPEERNAME:
586 	return linux_getpeername(p, args->args, retval);
587     case LINUX_SOCKETPAIR:
588 	return linux_socketpair(p, args->args, retval);
589     case LINUX_SEND:
590 	return linux_send(p, args->args, retval);
591     case LINUX_RECV:
592 	return linux_recv(p, args->args, retval);
593     case LINUX_SENDTO:
594 	return linux_sendto(p, args->args, retval);
595     case LINUX_RECVFROM:
596 	return linux_recvfrom(p, args->args, retval);
597     case LINUX_SHUTDOWN:
598 	return linux_shutdown(p, args->args, retval);
599     case LINUX_SETSOCKOPT:
600 	return linux_setsockopt(p, args->args, retval);
601     case LINUX_GETSOCKOPT:
602 	return linux_getsockopt(p, args->args, retval);
603     default:
604 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
605 	return ENOSYS;
606     }
607 }
608