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 without 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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: releng/5.2/sys/compat/linux/linux_socket.c 122358 2003-11-09 17:04:04Z dwmalone $");
31
32 /* XXX we use functions that might not exist. */
33 #include "opt_compat.h"
34 #include "opt_inet6.h"
35
36 #ifndef COMPAT_43
37 #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
38 #endif
39
40 #include <sys/param.h>
41 #include <sys/proc.h>
42 #include <sys/systm.h>
43 #include <sys/sysproto.h>
44 #include <sys/fcntl.h>
45 #include <sys/file.h>
46 #include <sys/limits.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/syscallsubr.h>
52 #include <sys/uio.h>
53 #include <sys/syslog.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #ifdef INET6
59 #include <netinet/ip6.h>
60 #include <netinet6/ip6_var.h>
61 #endif
62
63 #include <machine/../linux/linux.h>
64 #include <machine/../linux/linux_proto.h>
65 #include <compat/linux/linux_socket.h>
66 #include <compat/linux/linux_util.h>
67
68 static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
69 struct malloc_type *);
70 static int linux_to_bsd_domain(int);
71
72 /*
73 * Reads a linux sockaddr and does any necessary translation.
74 * Linux sockaddrs don't have a length field, only a family.
75 */
76 static int
77 linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
78 {
79 int osalen = len;
80
81 return (do_sa_get(sap, osa, &osalen, M_SONAME));
82 }
83
84 /*
85 * Copy the osockaddr structure pointed to by osa to kernel, adjust
86 * family and convert to sockaddr.
87 */
88 static int
89 do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
90 struct malloc_type *mtype)
91 {
92 int error=0, bdom;
93 struct sockaddr *sa;
94 struct osockaddr *kosa;
95 int alloclen;
96 #ifdef INET6
97 int oldv6size;
98 struct sockaddr_in6 *sin6;
99 #endif
100
101 if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
102 return (EINVAL);
103
104 alloclen = *osalen;
105 #ifdef INET6
106 oldv6size = 0;
107 /*
108 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
109 * if it's a v4-mapped address, so reserve the proper space
110 * for it.
111 */
112 if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
113 alloclen = sizeof (struct sockaddr_in6);
114 oldv6size = 1;
115 }
116 #endif
117
118 MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
119
120 if ((error = copyin(osa, kosa, *osalen)))
121 goto out;
122
123 bdom = linux_to_bsd_domain(kosa->sa_family);
124 if (bdom == -1) {
125 error = EINVAL;
126 goto out;
127 }
128
129 #ifdef INET6
130 /*
131 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
132 * which lacks the scope id compared with RFC2553 one. If we detect
133 * the situation, reject the address and write a message to system log.
134 *
135 * Still accept addresses for which the scope id is not used.
136 */
137 if (oldv6size && bdom == AF_INET6) {
138 sin6 = (struct sockaddr_in6 *)kosa;
139 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
140 (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
141 !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
142 !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
143 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
144 !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
145 sin6->sin6_scope_id = 0;
146 } else {
147 log(LOG_DEBUG,
148 "obsolete pre-RFC2553 sockaddr_in6 rejected");
149 error = EINVAL;
150 goto out;
151 }
152 } else
153 #endif
154 if (bdom == AF_INET)
155 alloclen = sizeof(struct sockaddr_in);
156
157 sa = (struct sockaddr *) kosa;
158 sa->sa_family = bdom;
159 sa->sa_len = alloclen;
160
161 *sap = sa;
162 *osalen = alloclen;
163 return (0);
164
165 out:
166 FREE(kosa, mtype);
167 return (error);
168 }
169
170 static int
171 linux_to_bsd_domain(int domain)
172 {
173
174 switch (domain) {
175 case LINUX_AF_UNSPEC:
176 return (AF_UNSPEC);
177 case LINUX_AF_UNIX:
178 return (AF_LOCAL);
179 case LINUX_AF_INET:
180 return (AF_INET);
181 case LINUX_AF_INET6:
182 return (AF_INET6);
183 case LINUX_AF_AX25:
184 return (AF_CCITT);
185 case LINUX_AF_IPX:
186 return (AF_IPX);
187 case LINUX_AF_APPLETALK:
188 return (AF_APPLETALK);
189 }
190 return (-1);
191 }
192
193 #ifndef __alpha__
194 static int
195 bsd_to_linux_domain(int domain)
196 {
197
198 switch (domain) {
199 case AF_UNSPEC:
200 return (LINUX_AF_UNSPEC);
201 case AF_LOCAL:
202 return (LINUX_AF_UNIX);
203 case AF_INET:
204 return (LINUX_AF_INET);
205 case AF_INET6:
206 return (LINUX_AF_INET6);
207 case AF_CCITT:
208 return (LINUX_AF_AX25);
209 case AF_IPX:
210 return (LINUX_AF_IPX);
211 case AF_APPLETALK:
212 return (LINUX_AF_APPLETALK);
213 }
214 return (-1);
215 }
216
217 static int
218 linux_to_bsd_sockopt_level(int level)
219 {
220
221 switch (level) {
222 case LINUX_SOL_SOCKET:
223 return (SOL_SOCKET);
224 }
225 return (level);
226 }
227
228 static int
229 bsd_to_linux_sockopt_level(int level)
230 {
231
232 switch (level) {
233 case SOL_SOCKET:
234 return (LINUX_SOL_SOCKET);
235 }
236 return (level);
237 }
238
239 static int
240 linux_to_bsd_ip_sockopt(int opt)
241 {
242
243 switch (opt) {
244 case LINUX_IP_TOS:
245 return (IP_TOS);
246 case LINUX_IP_TTL:
247 return (IP_TTL);
248 case LINUX_IP_OPTIONS:
249 return (IP_OPTIONS);
250 case LINUX_IP_MULTICAST_IF:
251 return (IP_MULTICAST_IF);
252 case LINUX_IP_MULTICAST_TTL:
253 return (IP_MULTICAST_TTL);
254 case LINUX_IP_MULTICAST_LOOP:
255 return (IP_MULTICAST_LOOP);
256 case LINUX_IP_ADD_MEMBERSHIP:
257 return (IP_ADD_MEMBERSHIP);
258 case LINUX_IP_DROP_MEMBERSHIP:
259 return (IP_DROP_MEMBERSHIP);
260 case LINUX_IP_HDRINCL:
261 return (IP_HDRINCL);
262 }
263 return (-1);
264 }
265
266 static int
267 linux_to_bsd_so_sockopt(int opt)
268 {
269
270 switch (opt) {
271 case LINUX_SO_DEBUG:
272 return (SO_DEBUG);
273 case LINUX_SO_REUSEADDR:
274 return (SO_REUSEADDR);
275 case LINUX_SO_TYPE:
276 return (SO_TYPE);
277 case LINUX_SO_ERROR:
278 return (SO_ERROR);
279 case LINUX_SO_DONTROUTE:
280 return (SO_DONTROUTE);
281 case LINUX_SO_BROADCAST:
282 return (SO_BROADCAST);
283 case LINUX_SO_SNDBUF:
284 return (SO_SNDBUF);
285 case LINUX_SO_RCVBUF:
286 return (SO_RCVBUF);
287 case LINUX_SO_KEEPALIVE:
288 return (SO_KEEPALIVE);
289 case LINUX_SO_OOBINLINE:
290 return (SO_OOBINLINE);
291 case LINUX_SO_LINGER:
292 return (SO_LINGER);
293 }
294 return (-1);
295 }
296
297 static int
298 linux_to_bsd_msg_flags(int flags)
299 {
300 int ret_flags = 0;
301
302 if (flags & LINUX_MSG_OOB)
303 ret_flags |= MSG_OOB;
304 if (flags & LINUX_MSG_PEEK)
305 ret_flags |= MSG_PEEK;
306 if (flags & LINUX_MSG_DONTROUTE)
307 ret_flags |= MSG_DONTROUTE;
308 if (flags & LINUX_MSG_CTRUNC)
309 ret_flags |= MSG_CTRUNC;
310 if (flags & LINUX_MSG_TRUNC)
311 ret_flags |= MSG_TRUNC;
312 if (flags & LINUX_MSG_DONTWAIT)
313 ret_flags |= MSG_DONTWAIT;
314 if (flags & LINUX_MSG_EOR)
315 ret_flags |= MSG_EOR;
316 if (flags & LINUX_MSG_WAITALL)
317 ret_flags |= MSG_WAITALL;
318 #if 0 /* not handled */
319 if (flags & LINUX_MSG_PROXY)
320 ;
321 if (flags & LINUX_MSG_FIN)
322 ;
323 if (flags & LINUX_MSG_SYN)
324 ;
325 if (flags & LINUX_MSG_CONFIRM)
326 ;
327 if (flags & LINUX_MSG_RST)
328 ;
329 if (flags & LINUX_MSG_ERRQUEUE)
330 ;
331 if (flags & LINUX_MSG_NOSIGNAL)
332 ;
333 #endif
334 return ret_flags;
335 }
336
337 static int
338 linux_sa_put(struct osockaddr *osa)
339 {
340 struct osockaddr sa;
341 int error, bdom;
342
343 /*
344 * Only read/write the osockaddr family part, the rest is
345 * not changed.
346 */
347 error = copyin(osa, &sa, sizeof(sa.sa_family));
348 if (error)
349 return (error);
350
351 bdom = bsd_to_linux_domain(sa.sa_family);
352 if (bdom == -1)
353 return (EINVAL);
354
355 sa.sa_family = bdom;
356 error = copyout(&sa, osa, sizeof(sa.sa_family));
357 if (error)
358 return (error);
359
360 return (0);
361 }
362
363 static int
364 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags)
365 {
366 struct mbuf *control;
367 struct sockaddr *to;
368 int error;
369
370 if (mp->msg_name != NULL) {
371 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
372 if (error)
373 return (error);
374 mp->msg_name = to;
375 } else
376 to = NULL;
377
378 if (mp->msg_control != NULL) {
379 struct cmsghdr *cmsg;
380
381 if (mp->msg_controllen < sizeof(struct cmsghdr)) {
382 error = EINVAL;
383 goto bad;
384 }
385 error = sockargs(&control, mp->msg_control,
386 mp->msg_controllen, MT_CONTROL);
387 if (error)
388 goto bad;
389
390 cmsg = mtod(control, struct cmsghdr *);
391 cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
392 } else
393 control = NULL;
394
395 error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control);
396
397 bad:
398 if (to)
399 FREE(to, M_SONAME);
400 return (error);
401 }
402
403 /* Return 0 if IP_HDRINCL is set for the given socket. */
404 static int
405 linux_check_hdrincl(struct thread *td, caddr_t *sg, int s)
406 {
407 struct getsockopt_args /* {
408 int s;
409 int level;
410 int name;
411 caddr_t val;
412 int *avalsize;
413 } */ bsd_args;
414 int error;
415 caddr_t val, valsize;
416 int size_val = sizeof val;
417 int optval;
418
419 val = stackgap_alloc(sg, sizeof(int));
420 valsize = stackgap_alloc(sg, sizeof(int));
421
422 if ((error = copyout(&size_val, valsize, sizeof(size_val))))
423 return (error);
424
425 bsd_args.s = s;
426 bsd_args.level = IPPROTO_IP;
427 bsd_args.name = IP_HDRINCL;
428 bsd_args.val = val;
429 bsd_args.avalsize = (int *)valsize;
430 if ((error = getsockopt(td, &bsd_args)))
431 return (error);
432
433 if ((error = copyin(val, &optval, sizeof(optval))))
434 return (error);
435
436 return (optval == 0);
437 }
438
439 struct linux_sendto_args {
440 int s;
441 void *msg;
442 int len;
443 int flags;
444 caddr_t to;
445 int tolen;
446 };
447
448 /*
449 * Updated sendto() when IP_HDRINCL is set:
450 * tweak endian-dependent fields in the IP packet.
451 */
452 static int
453 linux_sendto_hdrincl(struct thread *td, caddr_t *sg, struct linux_sendto_args *linux_args)
454 {
455 /*
456 * linux_ip_copysize defines how many bytes we should copy
457 * from the beginning of the IP packet before we customize it for BSD.
458 * It should include all the fields we modify (ip_len and ip_off)
459 * and be as small as possible to minimize copying overhead.
460 */
461 #define linux_ip_copysize 8
462
463 struct ip *packet;
464 struct msghdr msg;
465 struct iovec aiov[2];
466 int error;
467
468 /* Check the packet isn't too small before we mess with it */
469 if (linux_args->len < linux_ip_copysize)
470 return (EINVAL);
471
472 /*
473 * Tweaking the user buffer in place would be bad manners.
474 * We create a corrected IP header with just the needed length,
475 * then use an iovec to glue it to the rest of the user packet
476 * when calling sendit().
477 */
478 packet = (struct ip *)stackgap_alloc(sg, linux_ip_copysize);
479
480 /* Make a copy of the beginning of the packet to be sent */
481 if ((error = copyin(linux_args->msg, packet, linux_ip_copysize)))
482 return (error);
483
484 /* Convert fields from Linux to BSD raw IP socket format */
485 packet->ip_len = linux_args->len;
486 packet->ip_off = ntohs(packet->ip_off);
487
488 /* Prepare the msghdr and iovec structures describing the new packet */
489 msg.msg_name = linux_args->to;
490 msg.msg_namelen = linux_args->tolen;
491 msg.msg_iov = aiov;
492 msg.msg_iovlen = 2;
493 msg.msg_control = NULL;
494 msg.msg_flags = 0;
495 aiov[0].iov_base = (char *)packet;
496 aiov[0].iov_len = linux_ip_copysize;
497 aiov[1].iov_base = (char *)(linux_args->msg) + linux_ip_copysize;
498 aiov[1].iov_len = linux_args->len - linux_ip_copysize;
499 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags);
500 return (error);
501 }
502
503 struct linux_socket_args {
504 int domain;
505 int type;
506 int protocol;
507 };
508
509 static int
510 linux_socket(struct thread *td, struct linux_socket_args *args)
511 {
512 struct linux_socket_args linux_args;
513 struct socket_args /* {
514 int domain;
515 int type;
516 int protocol;
517 } */ bsd_args;
518 struct setsockopt_args /* {
519 int s;
520 int level;
521 int name;
522 caddr_t val;
523 int valsize;
524 } */ bsd_setsockopt_args;
525 int error;
526 int retval_socket;
527
528 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
529 return (error);
530
531 bsd_args.protocol = linux_args.protocol;
532 bsd_args.type = linux_args.type;
533 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
534 if (bsd_args.domain == -1)
535 return (EINVAL);
536
537 retval_socket = socket(td, &bsd_args);
538 if (bsd_args.type == SOCK_RAW
539 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
540 && bsd_args.domain == AF_INET
541 && retval_socket >= 0) {
542 /* It's a raw IP socket: set the IP_HDRINCL option. */
543 caddr_t sg;
544 int *hdrincl;
545
546 sg = stackgap_init();
547 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
548 *hdrincl = 1;
549 bsd_setsockopt_args.s = td->td_retval[0];
550 bsd_setsockopt_args.level = IPPROTO_IP;
551 bsd_setsockopt_args.name = IP_HDRINCL;
552 bsd_setsockopt_args.val = (caddr_t)hdrincl;
553 bsd_setsockopt_args.valsize = sizeof(*hdrincl);
554 /* We ignore any error returned by setsockopt() */
555 setsockopt(td, &bsd_setsockopt_args);
556 /* Copy back the return value from socket() */
557 td->td_retval[0] = bsd_setsockopt_args.s;
558 }
559 #ifdef INET6
560 /*
561 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
562 * default and some apps depend on this. So, set V6ONLY to 0
563 * for Linux apps if the sysctl value is set to 1.
564 */
565 if (bsd_args.domain == PF_INET6 && retval_socket >= 0
566 #ifndef KLD_MODULE
567 /*
568 * XXX: Avoid undefined symbol error with an IPv4 only
569 * kernel.
570 */
571 && ip6_v6only
572 #endif
573 ) {
574 caddr_t sg;
575 int *v6only;
576
577 sg = stackgap_init();
578 v6only = (int *)stackgap_alloc(&sg, sizeof(*v6only));
579 *v6only = 0;
580 bsd_setsockopt_args.s = td->td_retval[0];
581 bsd_setsockopt_args.level = IPPROTO_IPV6;
582 bsd_setsockopt_args.name = IPV6_V6ONLY;
583 bsd_setsockopt_args.val = (caddr_t)v6only;
584 bsd_setsockopt_args.valsize = sizeof(*v6only);
585 /* We ignore any error returned by setsockopt() */
586 setsockopt(td, &bsd_setsockopt_args);
587 /* Copy back the return value from socket() */
588 td->td_retval[0] = bsd_setsockopt_args.s;
589 }
590 #endif
591
592 return (retval_socket);
593 }
594
595 struct linux_bind_args {
596 int s;
597 struct osockaddr *name;
598 int namelen;
599 };
600
601 static int
602 linux_bind(struct thread *td, struct linux_bind_args *args)
603 {
604 struct linux_bind_args linux_args;
605 struct sockaddr *sa;
606 int error;
607
608 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
609 return (error);
610
611 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
612 if (error)
613 return (error);
614
615 return (kern_bind(td, linux_args.s, sa));
616 }
617
618 struct linux_connect_args {
619 int s;
620 struct osockaddr * name;
621 int namelen;
622 };
623 int linux_connect(struct thread *, struct linux_connect_args *);
624 #endif /* !__alpha__*/
625
626 int
627 linux_connect(struct thread *td, struct linux_connect_args *args)
628 {
629 struct linux_connect_args linux_args;
630 struct socket *so;
631 struct sockaddr *sa;
632 u_int fflag;
633 int error;
634
635 #ifdef __alpha__
636 bcopy(args, &linux_args, sizeof(linux_args));
637 #else
638 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
639 return (error);
640 #endif /* __alpha__ */
641
642 error = linux_getsockaddr(&sa, (struct osockaddr *)linux_args.name,
643 linux_args.namelen);
644 if (error)
645 return (error);
646
647 error = kern_connect(td, linux_args.s, sa);
648 if (error != EISCONN)
649 return (error);
650
651 /*
652 * Linux doesn't return EISCONN the first time it occurs,
653 * when on a non-blocking socket. Instead it returns the
654 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
655 */
656 if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0)
657 return(error);
658 error = EISCONN;
659 if (fflag & FNONBLOCK) {
660 if (so->so_emuldata == 0)
661 error = so->so_error;
662 so->so_emuldata = (void *)1;
663 }
664 fputsock(so);
665 return (error);
666 }
667
668 #ifndef __alpha__
669
670 struct linux_listen_args {
671 int s;
672 int backlog;
673 };
674
675 static int
676 linux_listen(struct thread *td, struct linux_listen_args *args)
677 {
678 struct linux_listen_args linux_args;
679 struct listen_args /* {
680 int s;
681 int backlog;
682 } */ bsd_args;
683 int error;
684
685 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
686 return (error);
687
688 bsd_args.s = linux_args.s;
689 bsd_args.backlog = linux_args.backlog;
690 return (listen(td, &bsd_args));
691 }
692
693 struct linux_accept_args {
694 int s;
695 struct osockaddr *addr;
696 int *namelen;
697 };
698
699 static int
700 linux_accept(struct thread *td, struct linux_accept_args *args)
701 {
702 struct linux_accept_args linux_args;
703 struct accept_args /* {
704 int s;
705 caddr_t name;
706 int *anamelen;
707 } */ bsd_args;
708 struct close_args /* {
709 int fd;
710 } */ c_args;
711 struct fcntl_args /* {
712 int fd;
713 int cmd;
714 long arg;
715 } */ f_args;
716 int error;
717
718 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
719 return (error);
720
721 bsd_args.s = linux_args.s;
722 bsd_args.name = (caddr_t)linux_args.addr;
723 bsd_args.anamelen = linux_args.namelen;
724 error = oaccept(td, &bsd_args);
725 if (error)
726 return (error);
727 if (linux_args.addr) {
728 error = linux_sa_put(linux_args.addr);
729 if (error) {
730 c_args.fd = td->td_retval[0];
731 (void)close(td, &c_args);
732 return (error);
733 }
734 }
735
736 /*
737 * linux appears not to copy flags from the parent socket to the
738 * accepted one, so we must clear the flags in the new descriptor.
739 * Ignore any errors, because we already have an open fd.
740 */
741 f_args.fd = td->td_retval[0];
742 f_args.cmd = F_SETFL;
743 f_args.arg = 0;
744 (void)fcntl(td, &f_args);
745 td->td_retval[0] = f_args.fd;
746 return (0);
747 }
748
749 struct linux_getsockname_args {
750 int s;
751 struct osockaddr *addr;
752 int *namelen;
753 };
754
755 static int
756 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
757 {
758 struct linux_getsockname_args linux_args;
759 struct getsockname_args /* {
760 int fdes;
761 caddr_t asa;
762 int *alen;
763 } */ bsd_args;
764 int error;
765
766 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
767 return (error);
768
769 bsd_args.fdes = linux_args.s;
770 bsd_args.asa = (caddr_t) linux_args.addr;
771 bsd_args.alen = linux_args.namelen;
772 error = ogetsockname(td, &bsd_args);
773 if (error)
774 return (error);
775 error = linux_sa_put(linux_args.addr);
776 if (error)
777 return (error);
778 return (0);
779 }
780
781 struct linux_getpeername_args {
782 int s;
783 struct osockaddr *addr;
784 int *namelen;
785 };
786
787 static int
788 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
789 {
790 struct linux_getpeername_args linux_args;
791 struct ogetpeername_args /* {
792 int fdes;
793 caddr_t asa;
794 int *alen;
795 } */ bsd_args;
796 int error;
797
798 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
799 return (error);
800
801 bsd_args.fdes = linux_args.s;
802 bsd_args.asa = (caddr_t) linux_args.addr;
803 bsd_args.alen = linux_args.namelen;
804 error = ogetpeername(td, &bsd_args);
805 if (error)
806 return (error);
807 error = linux_sa_put(linux_args.addr);
808 if (error)
809 return (error);
810 return (0);
811 }
812
813 struct linux_socketpair_args {
814 int domain;
815 int type;
816 int protocol;
817 int *rsv;
818 };
819
820 static int
821 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
822 {
823 struct linux_socketpair_args linux_args;
824 struct socketpair_args /* {
825 int domain;
826 int type;
827 int protocol;
828 int *rsv;
829 } */ bsd_args;
830 int error;
831
832 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
833 return (error);
834
835 bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
836 if (bsd_args.domain == -1)
837 return (EINVAL);
838
839 bsd_args.type = linux_args.type;
840 bsd_args.protocol = linux_args.protocol;
841 bsd_args.rsv = linux_args.rsv;
842 return (socketpair(td, &bsd_args));
843 }
844
845 struct linux_send_args {
846 int s;
847 void *msg;
848 int len;
849 int flags;
850 };
851
852 static int
853 linux_send(struct thread *td, struct linux_send_args *args)
854 {
855 struct linux_send_args linux_args;
856 struct osend_args /* {
857 int s;
858 caddr_t buf;
859 int len;
860 int flags;
861 } */ bsd_args;
862 int error;
863
864 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
865 return (error);
866
867 bsd_args.s = linux_args.s;
868 bsd_args.buf = linux_args.msg;
869 bsd_args.len = linux_args.len;
870 bsd_args.flags = linux_args.flags;
871 return (osend(td, &bsd_args));
872 }
873
874 struct linux_recv_args {
875 int s;
876 void *msg;
877 int len;
878 int flags;
879 };
880
881 static int
882 linux_recv(struct thread *td, struct linux_recv_args *args)
883 {
884 struct linux_recv_args linux_args;
885 struct orecv_args /* {
886 int s;
887 caddr_t buf;
888 int len;
889 int flags;
890 } */ bsd_args;
891 int error;
892
893 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
894 return (error);
895
896 bsd_args.s = linux_args.s;
897 bsd_args.buf = linux_args.msg;
898 bsd_args.len = linux_args.len;
899 bsd_args.flags = linux_args.flags;
900 return (orecv(td, &bsd_args));
901 }
902
903 static int
904 linux_sendto(struct thread *td, struct linux_sendto_args *args)
905 {
906 struct linux_sendto_args linux_args;
907 struct msghdr msg;
908 struct iovec aiov;
909 caddr_t sg = stackgap_init();
910 int error;
911
912 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
913 return (error);
914
915 if (linux_check_hdrincl(td, &sg, linux_args.s) == 0)
916 /* IP_HDRINCL set, tweak the packet before sending */
917 return (linux_sendto_hdrincl(td, &sg, &linux_args));
918
919 msg.msg_name = linux_args.to;
920 msg.msg_namelen = linux_args.tolen;
921 msg.msg_iov = &aiov;
922 msg.msg_iovlen = 1;
923 msg.msg_control = NULL;
924 msg.msg_flags = 0;
925 aiov.iov_base = linux_args.msg;
926 aiov.iov_len = linux_args.len;
927 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
928 return (error);
929 }
930
931 struct linux_recvfrom_args {
932 int s;
933 void *buf;
934 int len;
935 int flags;
936 caddr_t from;
937 int *fromlen;
938 };
939
940 static int
941 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
942 {
943 struct linux_recvfrom_args linux_args;
944 struct recvfrom_args /* {
945 int s;
946 caddr_t buf;
947 size_t len;
948 int flags;
949 caddr_t from;
950 int *fromlenaddr;
951 } */ bsd_args;
952 int error;
953
954 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
955 return (error);
956
957 bsd_args.s = linux_args.s;
958 bsd_args.buf = linux_args.buf;
959 bsd_args.len = linux_args.len;
960 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
961 bsd_args.from = linux_args.from;
962 bsd_args.fromlenaddr = linux_args.fromlen;
963 error = orecvfrom(td, &bsd_args);
964 if (error)
965 return (error);
966 if (linux_args.from) {
967 error = linux_sa_put((struct osockaddr *) linux_args.from);
968 if (error)
969 return (error);
970 }
971 return (0);
972 }
973
974 struct linux_sendmsg_args {
975 int s;
976 const struct msghdr *msg;
977 int flags;
978 };
979
980 static int
981 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
982 {
983 struct linux_sendmsg_args linux_args;
984 struct msghdr msg;
985 struct iovec aiov[UIO_SMALLIOV], *iov;
986 int error;
987
988 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
989 return (error);
990
991 error = copyin(linux_args.msg, &msg, sizeof(msg));
992 if (error)
993 return (error);
994 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
995 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
996 return (EMSGSIZE);
997 MALLOC(iov, struct iovec *,
998 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
999 M_WAITOK);
1000 } else {
1001 iov = aiov;
1002 }
1003 if (msg.msg_iovlen &&
1004 (error = copyin(msg.msg_iov, iov,
1005 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
1006 goto done;
1007 msg.msg_iov = iov;
1008 msg.msg_flags = 0;
1009
1010 error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
1011 done:
1012 if (iov != aiov)
1013 FREE(iov, M_IOV);
1014 return (error);
1015 }
1016
1017 struct linux_recvmsg_args {
1018 int s;
1019 struct msghdr *msg;
1020 int flags;
1021 };
1022
1023 static int
1024 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1025 {
1026 struct linux_recvmsg_args linux_args;
1027 struct recvmsg_args /* {
1028 int s;
1029 struct msghdr *msg;
1030 int flags;
1031 } */ bsd_args;
1032 struct msghdr msg;
1033 struct cmsghdr *cmsg;
1034 int error;
1035
1036 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1037 return (error);
1038
1039 bsd_args.s = linux_args.s;
1040 bsd_args.msg = linux_args.msg;
1041 bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1042 error = recvmsg(td, &bsd_args);
1043 if (error)
1044 return (error);
1045
1046 if (bsd_args.msg->msg_control != NULL) {
1047 cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
1048 cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
1049 }
1050
1051 error = copyin(linux_args.msg, &msg, sizeof(msg));
1052 if (error)
1053 return (error);
1054 if (msg.msg_name && msg.msg_namelen > 2)
1055 error = linux_sa_put(msg.msg_name);
1056 return (error);
1057 }
1058
1059 struct linux_shutdown_args {
1060 int s;
1061 int how;
1062 };
1063
1064 static int
1065 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1066 {
1067 struct linux_shutdown_args linux_args;
1068 struct shutdown_args /* {
1069 int s;
1070 int how;
1071 } */ bsd_args;
1072 int error;
1073
1074 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1075 return (error);
1076
1077 bsd_args.s = linux_args.s;
1078 bsd_args.how = linux_args.how;
1079 return (shutdown(td, &bsd_args));
1080 }
1081
1082 struct linux_setsockopt_args {
1083 int s;
1084 int level;
1085 int optname;
1086 void *optval;
1087 int optlen;
1088 };
1089
1090 static int
1091 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1092 {
1093 struct linux_setsockopt_args linux_args;
1094 struct setsockopt_args /* {
1095 int s;
1096 int level;
1097 int name;
1098 caddr_t val;
1099 int valsize;
1100 } */ bsd_args;
1101 int error, name;
1102
1103 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1104 return (error);
1105
1106 bsd_args.s = linux_args.s;
1107 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1108 switch (bsd_args.level) {
1109 case SOL_SOCKET:
1110 name = linux_to_bsd_so_sockopt(linux_args.optname);
1111 break;
1112 case IPPROTO_IP:
1113 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1114 break;
1115 case IPPROTO_TCP:
1116 /* Linux TCP option values match BSD's */
1117 name = linux_args.optname;
1118 break;
1119 default:
1120 name = -1;
1121 break;
1122 }
1123 if (name == -1)
1124 return (EINVAL);
1125
1126 bsd_args.name = name;
1127 bsd_args.val = linux_args.optval;
1128 bsd_args.valsize = linux_args.optlen;
1129 return (setsockopt(td, &bsd_args));
1130 }
1131
1132 struct linux_getsockopt_args {
1133 int s;
1134 int level;
1135 int optname;
1136 void *optval;
1137 int *optlen;
1138 };
1139
1140 static int
1141 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1142 {
1143 struct linux_getsockopt_args linux_args;
1144 struct getsockopt_args /* {
1145 int s;
1146 int level;
1147 int name;
1148 caddr_t val;
1149 int *avalsize;
1150 } */ bsd_args;
1151 int error, name;
1152
1153 if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1154 return (error);
1155
1156 bsd_args.s = linux_args.s;
1157 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1158 switch (bsd_args.level) {
1159 case SOL_SOCKET:
1160 name = linux_to_bsd_so_sockopt(linux_args.optname);
1161 break;
1162 case IPPROTO_IP:
1163 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1164 break;
1165 case IPPROTO_TCP:
1166 /* Linux TCP option values match BSD's */
1167 name = linux_args.optname;
1168 break;
1169 default:
1170 name = -1;
1171 break;
1172 }
1173 if (name == -1)
1174 return (EINVAL);
1175
1176 bsd_args.name = name;
1177 bsd_args.val = linux_args.optval;
1178 bsd_args.avalsize = linux_args.optlen;
1179 return (getsockopt(td, &bsd_args));
1180 }
1181
1182 int
1183 linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1184 {
1185 void *arg = (void *)args->args;
1186
1187 switch (args->what) {
1188 case LINUX_SOCKET:
1189 return (linux_socket(td, arg));
1190 case LINUX_BIND:
1191 return (linux_bind(td, arg));
1192 case LINUX_CONNECT:
1193 return (linux_connect(td, arg));
1194 case LINUX_LISTEN:
1195 return (linux_listen(td, arg));
1196 case LINUX_ACCEPT:
1197 return (linux_accept(td, arg));
1198 case LINUX_GETSOCKNAME:
1199 return (linux_getsockname(td, arg));
1200 case LINUX_GETPEERNAME:
1201 return (linux_getpeername(td, arg));
1202 case LINUX_SOCKETPAIR:
1203 return (linux_socketpair(td, arg));
1204 case LINUX_SEND:
1205 return (linux_send(td, arg));
1206 case LINUX_RECV:
1207 return (linux_recv(td, arg));
1208 case LINUX_SENDTO:
1209 return (linux_sendto(td, arg));
1210 case LINUX_RECVFROM:
1211 return (linux_recvfrom(td, arg));
1212 case LINUX_SHUTDOWN:
1213 return (linux_shutdown(td, arg));
1214 case LINUX_SETSOCKOPT:
1215 return (linux_setsockopt(td, arg));
1216 case LINUX_GETSOCKOPT:
1217 return (linux_getsockopt(td, arg));
1218 case LINUX_SENDMSG:
1219 return (linux_sendmsg(td, arg));
1220 case LINUX_RECVMSG:
1221 return (linux_recvmsg(td, arg));
1222 }
1223
1224 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1225 return (ENOSYS);
1226 }
1227 #endif /*!__alpha__*/
Cache object: 4bb8f3d5a2ae778f777b3cac4d25a388
|