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 * $FreeBSD$
29 */
30
31 /* XXX we use functions that might not exist. */
32 #include "opt_compat.h"
33
34 #ifndef COMPAT_43
35 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
36 #endif
37
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 #include <sys/sysproto.h>
42 #include <sys/fcntl.h>
43 #include <sys/socket.h>
44 #include <sys/uio.h>
45
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49
50 #include <i386/linux/linux.h>
51 #include <i386/linux/linux_proto.h>
52 #include <i386/linux/linux_util.h>
53
54 static int
55 linux_to_bsd_domain(int domain)
56 {
57 switch (domain) {
58 case LINUX_AF_UNSPEC:
59 return AF_UNSPEC;
60 case LINUX_AF_UNIX:
61 return AF_LOCAL;
62 case LINUX_AF_INET:
63 return AF_INET;
64 case LINUX_AF_AX25:
65 return AF_CCITT;
66 case LINUX_AF_IPX:
67 return AF_IPX;
68 case LINUX_AF_APPLETALK:
69 return AF_APPLETALK;
70 default:
71 return -1;
72 }
73 }
74
75 static int
76 linux_to_bsd_sockopt_level(int level)
77 {
78 switch (level) {
79 case LINUX_SOL_SOCKET:
80 return SOL_SOCKET;
81 default:
82 return level;
83 }
84 }
85
86 static int linux_to_bsd_ip_sockopt(int opt)
87 {
88 switch (opt) {
89 case LINUX_IP_TOS:
90 return IP_TOS;
91 case LINUX_IP_TTL:
92 return IP_TTL;
93 case LINUX_IP_OPTIONS:
94 return IP_OPTIONS;
95 case LINUX_IP_MULTICAST_IF:
96 return IP_MULTICAST_IF;
97 case LINUX_IP_MULTICAST_TTL:
98 return IP_MULTICAST_TTL;
99 case LINUX_IP_MULTICAST_LOOP:
100 return IP_MULTICAST_LOOP;
101 case LINUX_IP_ADD_MEMBERSHIP:
102 return IP_ADD_MEMBERSHIP;
103 case LINUX_IP_DROP_MEMBERSHIP:
104 return IP_DROP_MEMBERSHIP;
105 case LINUX_IP_HDRINCL:
106 return IP_HDRINCL;
107 default:
108 return -1;
109 }
110 }
111
112 static int
113 linux_to_bsd_so_sockopt(int opt)
114 {
115 switch (opt) {
116 case LINUX_SO_DEBUG:
117 return SO_DEBUG;
118 case LINUX_SO_REUSEADDR:
119 return SO_REUSEADDR;
120 case LINUX_SO_TYPE:
121 return SO_TYPE;
122 case LINUX_SO_ERROR:
123 return SO_ERROR;
124 case LINUX_SO_DONTROUTE:
125 return SO_DONTROUTE;
126 case LINUX_SO_BROADCAST:
127 return SO_BROADCAST;
128 case LINUX_SO_SNDBUF:
129 return SO_SNDBUF;
130 case LINUX_SO_RCVBUF:
131 return SO_RCVBUF;
132 case LINUX_SO_KEEPALIVE:
133 return SO_KEEPALIVE;
134 case LINUX_SO_OOBINLINE:
135 return SO_OOBINLINE;
136 case LINUX_SO_LINGER:
137 return SO_LINGER;
138 case LINUX_SO_PRIORITY:
139 case LINUX_SO_NO_CHECK:
140 default:
141 return -1;
142 }
143 }
144
145 /* Return 0 if IP_HDRINCL is set of the given socket, not 0 otherwise */
146 static int
147 linux_check_hdrincl(struct proc *p, int s)
148 {
149 struct getsockopt_args /* {
150 int s;
151 int level;
152 int name;
153 caddr_t val;
154 int *avalsize;
155 } */ bsd_args;
156 int error;
157 caddr_t sg, val, valsize;
158 int size_val = sizeof val;
159 int optval;
160
161 sg = stackgap_init();
162 val = stackgap_alloc(&sg, sizeof(int));
163 valsize = stackgap_alloc(&sg, sizeof(int));
164
165 if ((error=copyout(&size_val, valsize, sizeof(size_val))))
166 return error;
167 bsd_args.s = s;
168 bsd_args.level = IPPROTO_IP;
169 bsd_args.name = IP_HDRINCL;
170 bsd_args.val = val;
171 bsd_args.avalsize = (int *)valsize;
172 if ((error=getsockopt(p, &bsd_args)))
173 return error;
174 if ((error=copyin(val, &optval, sizeof(optval))))
175 return error;
176 return optval == 0;
177 }
178
179 /*
180 * Updated sendto() when IP_HDRINCL is set:
181 * tweak endian-dependent fields in the IP packet.
182 */
183 static int
184 linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args)
185 {
186 /*
187 * linux_ip_copysize defines how many bytes we should copy
188 * from the beginning of the IP packet before we customize it for BSD.
189 * It should include all the fields we modify (ip_len and ip_off)
190 * and be as small as possible to minimize copying overhead.
191 */
192 #define linux_ip_copysize 8
193
194 caddr_t sg;
195 struct ip *packet;
196 struct msghdr *msg;
197 struct iovec *iov;
198
199 int error;
200 struct sendmsg_args /* {
201 int s;
202 caddr_t msg;
203 int flags;
204 } */ sendmsg_args;
205
206 /* Check the packet isn't too small before we mess with it */
207 if (bsd_args->len < linux_ip_copysize)
208 return EINVAL;
209
210 /*
211 * Tweaking the user buffer in place would be bad manners.
212 * We create a corrected IP header with just the needed length,
213 * then use an iovec to glue it to the rest of the user packet
214 * when calling sendmsg().
215 */
216 sg = stackgap_init();
217 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
218 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
219 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
220
221 /* Make a copy of the beginning of the packet to be sent */
222 if ((error = copyin(bsd_args->buf, (caddr_t)packet, linux_ip_copysize)))
223 return error;
224
225 /* Convert fields from Linux to BSD raw IP socket format */
226 packet->ip_len = bsd_args->len;
227 packet->ip_off = ntohs(packet->ip_off);
228
229 /* Prepare the msghdr and iovec structures describing the new packet */
230 msg->msg_name = bsd_args->to;
231 msg->msg_namelen = bsd_args->tolen;
232 msg->msg_iov = iov;
233 msg->msg_iovlen = 2;
234 msg->msg_control = NULL;
235 msg->msg_controllen = 0;
236 msg->msg_flags = 0;
237 iov[0].iov_base = (char *)packet;
238 iov[0].iov_len = linux_ip_copysize;
239 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
240 iov[1].iov_len = bsd_args->len - linux_ip_copysize;
241
242 sendmsg_args.s = bsd_args->s;
243 sendmsg_args.msg = (caddr_t)msg;
244 sendmsg_args.flags = bsd_args->flags;
245 return sendmsg(p, &sendmsg_args);
246 }
247
248 struct linux_socket_args {
249 int domain;
250 int type;
251 int protocol;
252 };
253
254 static int
255 linux_socket(struct proc *p, struct linux_socket_args *args)
256 {
257 struct linux_socket_args linux_args;
258 struct socket_args /* {
259 int domain;
260 int type;
261 int protocol;
262 } */ bsd_args;
263 int error;
264 int retval_socket;
265
266 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
267 return error;
268 bsd_args.protocol = linux_args.protocol;
269 bsd_args.type = linux_args.type;
270 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
271 if (bsd_args.domain == -1)
272 return EINVAL;
273
274 retval_socket = socket(p, &bsd_args);
275 if (bsd_args.type == SOCK_RAW
276 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
277 && bsd_args.domain == AF_INET
278 && retval_socket >= 0) {
279 /* It's a raw IP socket: set the IP_HDRINCL option. */
280 struct setsockopt_args /* {
281 int s;
282 int level;
283 int name;
284 caddr_t val;
285 int valsize;
286 } */ bsd_setsockopt_args;
287 caddr_t sg;
288 int *hdrincl;
289
290 sg = stackgap_init();
291 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
292 *hdrincl = 1;
293 bsd_setsockopt_args.s = p->p_retval[0];
294 bsd_setsockopt_args.level = IPPROTO_IP;
295 bsd_setsockopt_args.name = IP_HDRINCL;
296 bsd_setsockopt_args.val = (caddr_t)hdrincl;
297 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
298 /* We ignore any error returned by setsockopt() */
299 setsockopt(p, &bsd_setsockopt_args);
300 /* Copy back the return value from socket() */
301 p->p_retval[0] = bsd_setsockopt_args.s;
302 }
303 return retval_socket;
304 }
305
306 struct linux_bind_args {
307 int s;
308 struct sockaddr *name;
309 int namelen;
310 };
311
312 static int
313 linux_bind(struct proc *p, struct linux_bind_args *args)
314 {
315 struct linux_bind_args linux_args;
316 struct bind_args /* {
317 int s;
318 caddr_t name;
319 int namelen;
320 } */ bsd_args;
321 int error;
322
323 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
324 return error;
325 bsd_args.s = linux_args.s;
326 bsd_args.name = (caddr_t)linux_args.name;
327 bsd_args.namelen = linux_args.namelen;
328 return bind(p, &bsd_args);
329 }
330
331 struct linux_connect_args {
332 int s;
333 struct sockaddr * name;
334 int namelen;
335 };
336
337 static int
338 linux_connect(struct proc *p, struct linux_connect_args *args)
339 {
340 struct linux_connect_args linux_args;
341 struct connect_args /* {
342 int s;
343 caddr_t name;
344 int namelen;
345 } */ bsd_args;
346 int error;
347
348 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
349 return error;
350 bsd_args.s = linux_args.s;
351 bsd_args.name = (caddr_t)linux_args.name;
352 bsd_args.namelen = linux_args.namelen;
353 error = connect(p, &bsd_args);
354 if (error == EISCONN) {
355 /*
356 * Linux doesn't return EISCONN the first time it occurs,
357 * when on a non-blocking socket. Instead it returns the
358 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
359 */
360 struct fcntl_args /* {
361 int fd;
362 int cmd;
363 int arg;
364 } */ bsd_fcntl_args;
365 struct getsockopt_args /* {
366 int s;
367 int level;
368 int name;
369 caddr_t val;
370 int *avalsize;
371 } */ bsd_getsockopt_args;
372 void *status, *statusl;
373 int stat, statl = sizeof stat;
374 caddr_t sg;
375
376 /* Check for non-blocking */
377 bsd_fcntl_args.fd = linux_args.s;
378 bsd_fcntl_args.cmd = F_GETFL;
379 bsd_fcntl_args.arg = 0;
380 error = fcntl(p, &bsd_fcntl_args);
381 if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) {
382 sg = stackgap_init();
383 status = stackgap_alloc(&sg, sizeof stat);
384 statusl = stackgap_alloc(&sg, sizeof statusl);
385
386 if ((error = copyout(&statl, statusl, sizeof statl)))
387 return error;
388
389 bsd_getsockopt_args.s = linux_args.s;
390 bsd_getsockopt_args.level = SOL_SOCKET;
391 bsd_getsockopt_args.name = SO_ERROR;
392 bsd_getsockopt_args.val = status;
393 bsd_getsockopt_args.avalsize = statusl;
394
395 error = getsockopt(p, &bsd_getsockopt_args);
396 if (error)
397 return error;
398 if ((error = copyin(status, &stat, sizeof stat)))
399 return error;
400 p->p_retval[0] = stat;
401 return 0;
402 }
403 }
404 return error;
405 }
406
407 struct linux_listen_args {
408 int s;
409 int backlog;
410 };
411
412 static int
413 linux_listen(struct proc *p, struct linux_listen_args *args)
414 {
415 struct linux_listen_args linux_args;
416 struct listen_args /* {
417 int s;
418 int backlog;
419 } */ bsd_args;
420 int error;
421
422 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
423 return error;
424 bsd_args.s = linux_args.s;
425 bsd_args.backlog = linux_args.backlog;
426 return listen(p, &bsd_args);
427 }
428
429 struct linux_accept_args {
430 int s;
431 struct sockaddr *addr;
432 int *namelen;
433 };
434
435 static int
436 linux_accept(struct proc *p, struct linux_accept_args *args)
437 {
438 struct linux_accept_args linux_args;
439 struct accept_args /* {
440 int s;
441 caddr_t name;
442 int *anamelen;
443 } */ bsd_args;
444 int error;
445
446 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
447 return error;
448 bsd_args.s = linux_args.s;
449 bsd_args.name = (caddr_t)linux_args.addr;
450 bsd_args.anamelen = linux_args.namelen;
451 return oaccept(p, &bsd_args);
452 }
453
454 struct linux_getsockname_args {
455 int s;
456 struct sockaddr *addr;
457 int *namelen;
458 };
459
460 static int
461 linux_getsockname(struct proc *p, struct linux_getsockname_args *args)
462 {
463 struct linux_getsockname_args linux_args;
464 struct getsockname_args /* {
465 int fdes;
466 caddr_t asa;
467 int *alen;
468 } */ bsd_args;
469 int error;
470
471 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
472 return error;
473 bsd_args.fdes = linux_args.s;
474 bsd_args.asa = (caddr_t) linux_args.addr;
475 bsd_args.alen = linux_args.namelen;
476 return ogetsockname(p, &bsd_args);
477 }
478
479 struct linux_getpeername_args {
480 int s;
481 struct sockaddr *addr;
482 int *namelen;
483 };
484
485 static int
486 linux_getpeername(struct proc *p, struct linux_getpeername_args *args)
487 {
488 struct linux_getpeername_args linux_args;
489 struct ogetpeername_args /* {
490 int fdes;
491 caddr_t asa;
492 int *alen;
493 } */ bsd_args;
494 int error;
495
496 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
497 return error;
498 bsd_args.fdes = linux_args.s;
499 bsd_args.asa = (caddr_t) linux_args.addr;
500 bsd_args.alen = linux_args.namelen;
501 return ogetpeername(p, &bsd_args);
502 }
503
504 struct linux_socketpair_args {
505 int domain;
506 int type;
507 int protocol;
508 int *rsv;
509 };
510
511 static int
512 linux_socketpair(struct proc *p, struct linux_socketpair_args *args)
513 {
514 struct linux_socketpair_args linux_args;
515 struct socketpair_args /* {
516 int domain;
517 int type;
518 int protocol;
519 int *rsv;
520 } */ bsd_args;
521 int error;
522
523 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
524 return error;
525 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
526 if (bsd_args.domain == -1)
527 return EINVAL;
528 bsd_args.type = linux_args.type;
529 bsd_args.protocol = linux_args.protocol;
530 bsd_args.rsv = linux_args.rsv;
531 return socketpair(p, &bsd_args);
532 }
533
534 struct linux_send_args {
535 int s;
536 void *msg;
537 int len;
538 int flags;
539 };
540
541 static int
542 linux_send(struct proc *p, struct linux_send_args *args)
543 {
544 struct linux_send_args linux_args;
545 struct osend_args /* {
546 int s;
547 caddr_t buf;
548 int len;
549 int flags;
550 } */ bsd_args;
551 int error;
552
553 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
554 return error;
555 bsd_args.s = linux_args.s;
556 bsd_args.buf = linux_args.msg;
557 bsd_args.len = linux_args.len;
558 bsd_args.flags = linux_args.flags;
559 return osend(p, &bsd_args);
560 }
561
562 struct linux_recv_args {
563 int s;
564 void *msg;
565 int len;
566 int flags;
567 };
568
569 static int
570 linux_recv(struct proc *p, struct linux_recv_args *args)
571 {
572 struct linux_recv_args linux_args;
573 struct orecv_args /* {
574 int s;
575 caddr_t buf;
576 int len;
577 int flags;
578 } */ bsd_args;
579 int error;
580
581 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
582 return error;
583 bsd_args.s = linux_args.s;
584 bsd_args.buf = linux_args.msg;
585 bsd_args.len = linux_args.len;
586 bsd_args.flags = linux_args.flags;
587 return orecv(p, &bsd_args);
588 }
589
590 struct linux_sendto_args {
591 int s;
592 void *msg;
593 int len;
594 int flags;
595 caddr_t to;
596 int tolen;
597 };
598
599 static int
600 linux_sendto(struct proc *p, struct linux_sendto_args *args)
601 {
602 struct linux_sendto_args linux_args;
603 struct sendto_args /* {
604 int s;
605 caddr_t buf;
606 size_t len;
607 int flags;
608 caddr_t to;
609 int tolen;
610 } */ bsd_args;
611 int error;
612
613 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
614 return error;
615 bsd_args.s = linux_args.s;
616 bsd_args.buf = linux_args.msg;
617 bsd_args.len = linux_args.len;
618 bsd_args.flags = linux_args.flags;
619 bsd_args.to = linux_args.to;
620 bsd_args.tolen = linux_args.tolen;
621
622 if (linux_check_hdrincl(p, linux_args.s) == 0)
623 /* IP_HDRINCL set, tweak the packet before sending */
624 return linux_sendto_hdrincl(p, &bsd_args);
625
626 return sendto(p, &bsd_args);
627 }
628
629 struct linux_recvfrom_args {
630 int s;
631 void *buf;
632 int len;
633 int flags;
634 caddr_t from;
635 int *fromlen;
636 };
637
638 static int
639 linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args)
640 {
641 struct linux_recvfrom_args linux_args;
642 struct recvfrom_args /* {
643 int s;
644 caddr_t buf;
645 size_t len;
646 int flags;
647 caddr_t from;
648 int *fromlenaddr;
649 } */ bsd_args;
650 int error;
651
652 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
653 return error;
654 bsd_args.s = linux_args.s;
655 bsd_args.buf = linux_args.buf;
656 bsd_args.len = linux_args.len;
657 bsd_args.flags = linux_args.flags;
658 bsd_args.from = linux_args.from;
659 bsd_args.fromlenaddr = linux_args.fromlen;
660 return orecvfrom(p, &bsd_args);
661 }
662
663 struct linux_shutdown_args {
664 int s;
665 int how;
666 };
667
668 static int
669 linux_shutdown(struct proc *p, struct linux_shutdown_args *args)
670 {
671 struct linux_shutdown_args linux_args;
672 struct shutdown_args /* {
673 int s;
674 int how;
675 } */ bsd_args;
676 int error;
677
678 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
679 return error;
680 bsd_args.s = linux_args.s;
681 bsd_args.how = linux_args.how;
682 return shutdown(p, &bsd_args);
683 }
684
685 struct linux_setsockopt_args {
686 int s;
687 int level;
688 int optname;
689 void *optval;
690 int optlen;
691 };
692
693 static int
694 linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args)
695 {
696 struct linux_setsockopt_args linux_args;
697 struct setsockopt_args /* {
698 int s;
699 int level;
700 int name;
701 caddr_t val;
702 int valsize;
703 } */ bsd_args;
704 int error, name;
705
706 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
707 return error;
708 bsd_args.s = linux_args.s;
709 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
710 switch (bsd_args.level) {
711 case SOL_SOCKET:
712 name = linux_to_bsd_so_sockopt(linux_args.optname);
713 break;
714 case IPPROTO_IP:
715 name = linux_to_bsd_ip_sockopt(linux_args.optname);
716 break;
717 case IPPROTO_TCP:
718 /* Linux TCP option values match BSD's */
719 name = linux_args.optname;
720 break;
721 default:
722 return EINVAL;
723 }
724 if (name == -1)
725 return EINVAL;
726 bsd_args.name = name;
727 bsd_args.val = linux_args.optval;
728 bsd_args.valsize = linux_args.optlen;
729 return setsockopt(p, &bsd_args);
730 }
731
732 struct linux_getsockopt_args {
733 int s;
734 int level;
735 int optname;
736 void *optval;
737 int *optlen;
738 };
739
740 static int
741 linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args)
742 {
743 struct linux_getsockopt_args linux_args;
744 struct getsockopt_args /* {
745 int s;
746 int level;
747 int name;
748 caddr_t val;
749 int *avalsize;
750 } */ bsd_args;
751 int error, name;
752
753 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
754 return error;
755 bsd_args.s = linux_args.s;
756 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
757 switch (bsd_args.level) {
758 case SOL_SOCKET:
759 name = linux_to_bsd_so_sockopt(linux_args.optname);
760 break;
761 case IPPROTO_IP:
762 name = linux_to_bsd_ip_sockopt(linux_args.optname);
763 break;
764 case IPPROTO_TCP:
765 /* Linux TCP option values match BSD's */
766 name = linux_args.optname;
767 break;
768 default:
769 return EINVAL;
770 }
771 if (name == -1)
772 return EINVAL;
773 bsd_args.name = name;
774 bsd_args.val = linux_args.optval;
775 bsd_args.avalsize = linux_args.optlen;
776 return getsockopt(p, &bsd_args);
777 }
778
779 int
780 linux_socketcall(struct proc *p, struct linux_socketcall_args *args)
781 {
782 switch (args->what) {
783 case LINUX_SOCKET:
784 return linux_socket(p, args->args);
785 case LINUX_BIND:
786 return linux_bind(p, args->args);
787 case LINUX_CONNECT:
788 return linux_connect(p, args->args);
789 case LINUX_LISTEN:
790 return linux_listen(p, args->args);
791 case LINUX_ACCEPT:
792 return linux_accept(p, args->args);
793 case LINUX_GETSOCKNAME:
794 return linux_getsockname(p, args->args);
795 case LINUX_GETPEERNAME:
796 return linux_getpeername(p, args->args);
797 case LINUX_SOCKETPAIR:
798 return linux_socketpair(p, args->args);
799 case LINUX_SEND:
800 return linux_send(p, args->args);
801 case LINUX_RECV:
802 return linux_recv(p, args->args);
803 case LINUX_SENDTO:
804 return linux_sendto(p, args->args);
805 case LINUX_RECVFROM:
806 return linux_recvfrom(p, args->args);
807 case LINUX_SHUTDOWN:
808 return linux_shutdown(p, args->args);
809 case LINUX_SETSOCKOPT:
810 return linux_setsockopt(p, args->args);
811 case LINUX_GETSOCKOPT:
812 return linux_getsockopt(p, args->args);
813 case LINUX_SENDMSG:
814 do {
815 int error;
816 int level;
817 caddr_t control;
818 struct {
819 int s;
820 const struct msghdr *msg;
821 int flags;
822 } *uap = args->args;
823
824 error = copyin(&uap->msg->msg_control,
825 &control, sizeof(caddr_t));
826 if (error)
827 return error;
828 if (control == NULL)
829 goto done;
830 error = copyin(&((struct cmsghdr *)control)->cmsg_level,
831 &level, sizeof(int));
832 if (error)
833 return error;
834 if (level == 1) {
835 /*
836 * Linux thinks that SOL_SOCKET is 1; we know that it's really
837 * 0xffff, of course.
838 */
839 level = SOL_SOCKET;
840 error = copyout(&level, &((struct cmsghdr *)control)->
841 cmsg_level, sizeof(int));
842 if (error)
843 return error;
844 }
845 done:
846 return sendmsg(p, args->args);
847 } while (0);
848 case LINUX_RECVMSG:
849 return recvmsg(p, args->args);
850
851 default:
852 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
853 return ENOSYS;
854 }
855 }
Cache object: 016bab88673058eef69ba7c482243fe7
|