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