kernel - use new td_ucred in numerous places
[dragonfly.git] / sys / emulation / linux / linux_socket.c
CommitLineData
984263bc
MD
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: src/sys/compat/linux/linux_socket.c,v 1.19.2.8 2001/11/07 20:33:55 marcel Exp $
792239df 29 * $DragonFly: src/sys/emulation/linux/linux_socket.c,v 1.28 2008/07/10 00:19:27 aggelos Exp $
984263bc
MD
30 */
31
984263bc
MD
32#include <sys/param.h>
33#include <sys/proc.h>
34#include <sys/systm.h>
35#include <sys/sysproto.h>
36#include <sys/fcntl.h>
37#include <sys/file.h>
5969a6f1 38#include <sys/kern_syscall.h>
984263bc
MD
39#include <sys/socket.h>
40#include <sys/socketvar.h>
41#include <sys/uio.h>
275a5506 42#include <sys/malloc.h>
24b9e9d1 43#include <sys/mbuf.h>
984263bc
MD
44
45#include <netinet/in.h>
46#include <netinet/in_systm.h>
47#include <netinet/ip.h>
48
932f49b9
MD
49#include <arch_linux/linux.h>
50#include <arch_linux/linux_proto.h>
1f2de5d4
MD
51#include "linux_socket.h"
52#include "linux_util.h"
984263bc
MD
53
54/*
275a5506
MD
55 * Copyin a sockaddr structure provided by a Linux binary. Linux uses
56 * the 4.3BSD sockaddr structure which has no sa_len field. We must
57 * pass 4.4BSD sockaddr structures when we call native functions in the
801ebe52 58 * BSD kernel. This function does the conversion for us.
275a5506
MD
59 *
60 * Also, our socket calls require the sockaddr structure length to agree
984263bc 61 * with the address family. Linux does not, so we must force it.
275a5506
MD
62 *
63 * This function should only need to be called from linux_connect()
64 * and linux_bind().
984263bc
MD
65 */
66static int
275a5506 67linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
984263bc 68{
275a5506
MD
69 struct sockaddr *sa;
70 uint16_t family; /* XXX: must match Linux sockaddr */
71 int error;
72 int sa_len;
984263bc 73
275a5506
MD
74 *namp = NULL;
75
76 if (len > SOCK_MAXADDRLEN)
77 return ENAMETOOLONG;
78 error = copyin(uaddr, &family, sizeof(family));
79 if (error)
80 return (error);
984263bc 81
275a5506
MD
82 /*
83 * Force the sa_len field to match the address family.
84 */
984263bc 85 switch (family) {
275a5506
MD
86 case AF_INET:
87 sa_len = sizeof(struct sockaddr_in);
88 break;
89 case AF_INET6:
90 sa_len = sizeof(struct sockaddr_in6);
91 break;
92 default:
93 /*
94 * This is the default behavior of the old
95 * linux_to_bsd_namelen() function. NOTE! The
96 * minimum length we allocate must cover sa->sa_len and
97 * sa->sa_family.
98 */
99 sa_len = offsetof(struct sockaddr, sa_data[0]);
100 if (sa_len < len)
101 sa_len = len;
102 break;
103 }
104
105 MALLOC(sa, struct sockaddr *, sa_len, M_SONAME, M_WAITOK);
106 error = copyin(uaddr, sa, sa_len);
107 if (error) {
108 FREE(sa, M_SONAME);
109 } else {
110 /*
111 * Convert to the 4.4BSD sockaddr structure.
112 */
113 sa->sa_family = *(sa_family_t *)sa;
114 sa->sa_len = sa_len;
115 *namp = sa;
984263bc 116 }
984263bc 117
275a5506
MD
118 return (error);
119}
801ebe52
DRJ
120
121/*
122 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
123 * and copy it out to a user address.
124 */
125static int
24b9e9d1 126linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
801ebe52 127{
24b9e9d1 128 int error;
801ebe52 129
24b9e9d1
DRJ
130 if (sa_len < (int)sizeof(u_short))
131 return (EINVAL);
801ebe52 132
24b9e9d1 133 *(u_short *)sa = sa->sa_family;
801ebe52
DRJ
134 error = copyout(sa, uaddr, sa_len);
135
136 return (error);
137}
275a5506 138
984263bc
MD
139static int
140linux_to_bsd_domain(int domain)
141{
142
143 switch (domain) {
144 case LINUX_AF_UNSPEC:
145 return (AF_UNSPEC);
146 case LINUX_AF_UNIX:
147 return (AF_LOCAL);
148 case LINUX_AF_INET:
149 return (AF_INET);
150 case LINUX_AF_AX25:
151 return (AF_CCITT);
152 case LINUX_AF_IPX:
153 return (AF_IPX);
154 case LINUX_AF_APPLETALK:
155 return (AF_APPLETALK);
156 }
157 return (-1);
158}
159
160static int
161linux_to_bsd_sockopt_level(int level)
162{
163
164 switch (level) {
165 case LINUX_SOL_SOCKET:
166 return (SOL_SOCKET);
167 }
168 return (level);
169}
170
171static int
172linux_to_bsd_ip_sockopt(int opt)
173{
174
175 switch (opt) {
176 case LINUX_IP_TOS:
177 return (IP_TOS);
178 case LINUX_IP_TTL:
179 return (IP_TTL);
180 case LINUX_IP_OPTIONS:
181 return (IP_OPTIONS);
182 case LINUX_IP_MULTICAST_IF:
183 return (IP_MULTICAST_IF);
184 case LINUX_IP_MULTICAST_TTL:
185 return (IP_MULTICAST_TTL);
186 case LINUX_IP_MULTICAST_LOOP:
187 return (IP_MULTICAST_LOOP);
188 case LINUX_IP_ADD_MEMBERSHIP:
189 return (IP_ADD_MEMBERSHIP);
190 case LINUX_IP_DROP_MEMBERSHIP:
191 return (IP_DROP_MEMBERSHIP);
192 case LINUX_IP_HDRINCL:
193 return (IP_HDRINCL);
194 }
195 return (-1);
196}
197
198static int
199linux_to_bsd_so_sockopt(int opt)
200{
201
202 switch (opt) {
203 case LINUX_SO_DEBUG:
204 return (SO_DEBUG);
205 case LINUX_SO_REUSEADDR:
206 return (SO_REUSEADDR);
207 case LINUX_SO_TYPE:
208 return (SO_TYPE);
209 case LINUX_SO_ERROR:
210 return (SO_ERROR);
211 case LINUX_SO_DONTROUTE:
212 return (SO_DONTROUTE);
213 case LINUX_SO_BROADCAST:
214 return (SO_BROADCAST);
215 case LINUX_SO_SNDBUF:
216 return (SO_SNDBUF);
217 case LINUX_SO_RCVBUF:
218 return (SO_RCVBUF);
219 case LINUX_SO_KEEPALIVE:
220 return (SO_KEEPALIVE);
221 case LINUX_SO_OOBINLINE:
222 return (SO_OOBINLINE);
223 case LINUX_SO_LINGER:
224 return (SO_LINGER);
225 }
226 return (-1);
227}
228
229static int
230linux_to_bsd_msg_flags(int flags)
231{
232 int ret_flags = 0;
233
234 if (flags & LINUX_MSG_OOB)
235 ret_flags |= MSG_OOB;
236 if (flags & LINUX_MSG_PEEK)
237 ret_flags |= MSG_PEEK;
238 if (flags & LINUX_MSG_DONTROUTE)
239 ret_flags |= MSG_DONTROUTE;
240 if (flags & LINUX_MSG_CTRUNC)
241 ret_flags |= MSG_CTRUNC;
242 if (flags & LINUX_MSG_TRUNC)
243 ret_flags |= MSG_TRUNC;
244 if (flags & LINUX_MSG_DONTWAIT)
245 ret_flags |= MSG_DONTWAIT;
246 if (flags & LINUX_MSG_EOR)
247 ret_flags |= MSG_EOR;
248 if (flags & LINUX_MSG_WAITALL)
249 ret_flags |= MSG_WAITALL;
250#if 0 /* not handled */
251 if (flags & LINUX_MSG_PROXY)
252 ;
253 if (flags & LINUX_MSG_FIN)
254 ;
255 if (flags & LINUX_MSG_SYN)
256 ;
257 if (flags & LINUX_MSG_CONFIRM)
258 ;
259 if (flags & LINUX_MSG_RST)
260 ;
261 if (flags & LINUX_MSG_ERRQUEUE)
262 ;
263 if (flags & LINUX_MSG_NOSIGNAL)
264 ;
265#endif
266 return ret_flags;
267}
268
984263bc
MD
269struct linux_socket_args {
270 int domain;
271 int type;
272 int protocol;
273};
274
275static int
90b9818c 276linux_socket(struct linux_socket_args *args, int *res)
984263bc
MD
277{
278 struct linux_socket_args linux_args;
9864c666
DRJ
279 struct sockopt sopt;
280 int error, domain, optval;
984263bc 281
9864c666
DRJ
282 error = copyin(args, &linux_args, sizeof(linux_args));
283 if (error)
984263bc
MD
284 return (error);
285
9864c666
DRJ
286 domain = linux_to_bsd_domain(linux_args.domain);
287 if (domain == -1)
984263bc
MD
288 return (EINVAL);
289
9864c666
DRJ
290 error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
291
90b9818c 292 /* Copy back the return value from socket() */
9864c666
DRJ
293 if (error == 0 && linux_args.type == SOCK_RAW &&
294 (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
295 linux_args.domain == AF_INET) {
984263bc 296 /* It's a raw IP socket: set the IP_HDRINCL option. */
9864c666
DRJ
297 optval = 1;
298 sopt.sopt_dir = SOPT_SET;
299 sopt.sopt_level = IPPROTO_IP;
300 sopt.sopt_name = IP_HDRINCL;
301 sopt.sopt_val = &optval;
302 sopt.sopt_valsize = sizeof(optval);
303 sopt.sopt_td = NULL;
304
984263bc 305 /* We ignore any error returned by setsockopt() */
9864c666 306 kern_setsockopt(*res, &sopt);
984263bc
MD
307 }
308
9864c666 309 return (error);
984263bc
MD
310}
311
312struct linux_bind_args {
313 int s;
314 struct sockaddr *name;
315 int namelen;
316};
317
318static int
90b9818c 319linux_bind(struct linux_bind_args *args, int *res)
984263bc
MD
320{
321 struct linux_bind_args linux_args;
275a5506 322 struct sockaddr *sa;
984263bc
MD
323 int error;
324
275a5506
MD
325 error = copyin(args, &linux_args, sizeof(linux_args));
326 if (error)
327 return (error);
328 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
329 if (error)
984263bc
MD
330 return (error);
331
5969a6f1 332 error = kern_bind(linux_args.s, sa);
275a5506
MD
333 FREE(sa, M_SONAME);
334
335 return (error);
984263bc
MD
336}
337
338struct linux_connect_args {
339 int s;
340 struct sockaddr * name;
341 int namelen;
342};
984263bc 343
557e370c 344static int
90b9818c 345linux_connect(struct linux_connect_args *args, int *res)
984263bc 346{
dadab5e9
MD
347 struct thread *td = curthread; /* XXX */
348 struct proc *p = td->td_proc;
984263bc 349 struct linux_connect_args linux_args;
275a5506 350 struct sockaddr *sa;
984263bc
MD
351 struct socket *so;
352 struct file *fp;
353 int error;
354
dadab5e9
MD
355 KKASSERT(p);
356
275a5506
MD
357 error = copyin(args, &linux_args, sizeof(linux_args));
358 if (error)
359 return (error);
360 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
361 if (error)
984263bc 362 return (error);
984263bc 363
358e1f78 364 error = kern_connect(linux_args.s, 0, sa);
275a5506
MD
365 FREE(sa, M_SONAME);
366
984263bc
MD
367 if (error != EISCONN)
368 return (error);
369
370 /*
371 * Linux doesn't return EISCONN the first time it occurs,
372 * when on a non-blocking socket. Instead it returns the
373 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
374 */
375 error = holdsock(p->p_fd, linux_args.s, &fp);
376 if (error)
377 return (error);
378 error = EISCONN;
379 if (fp->f_flag & FNONBLOCK) {
380 so = (struct socket *)fp->f_data;
381 if (so->so_emuldata == 0)
382 error = so->so_error;
383 so->so_emuldata = (void *)1;
384 }
9f87144f 385 fdrop(fp);
984263bc
MD
386 return (error);
387}
388
984263bc
MD
389struct linux_listen_args {
390 int s;
391 int backlog;
392};
393
394static int
90b9818c 395linux_listen(struct linux_listen_args *args, int *res)
984263bc
MD
396{
397 struct linux_listen_args linux_args;
984263bc
MD
398 int error;
399
801ebe52
DRJ
400 error = copyin(args, &linux_args, sizeof(linux_args));
401 if (error)
984263bc
MD
402 return (error);
403
801ebe52
DRJ
404 error = kern_listen(linux_args.s, linux_args.backlog);
405
90b9818c 406 return(error);
984263bc
MD
407}
408
409struct linux_accept_args {
410 int s;
411 struct sockaddr *addr;
412 int *namelen;
413};
414
415static int
90b9818c 416linux_accept(struct linux_accept_args *args, int *res)
984263bc 417{
9910d07b 418 struct thread *td = curthread;
984263bc 419 struct linux_accept_args linux_args;
275a5506 420 struct sockaddr *sa = NULL;
49aca642 421 union fcntl_dat dat = { 0 };
275a5506 422 int error, sa_len;
984263bc 423
275a5506
MD
424 error = copyin(args, &linux_args, sizeof(linux_args));
425 if (error)
984263bc
MD
426 return (error);
427
275a5506
MD
428 if (linux_args.addr) {
429 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
430 if (error)
431 return (error);
432
358e1f78 433 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res);
275a5506
MD
434
435 if (error) {
436 /*
437 * Return a namelen of zero for older code which
438 * might ignore the return value from accept().
439 */
440 sa_len = 0;
441 copyout(&sa_len, linux_args.namelen,
442 sizeof(*linux_args.namelen));
443 } else {
24b9e9d1
DRJ
444 error = linux_copyout_sockaddr(sa, linux_args.addr,
445 sa_len);
275a5506
MD
446 if (error == 0) {
447 error = copyout(&sa_len, linux_args.namelen,
448 sizeof(*linux_args.namelen));
449 }
450 }
451 if (sa)
452 FREE(sa, M_SONAME);
453 } else {
358e1f78 454 error = kern_accept(linux_args.s, 0, NULL, 0, res);
275a5506
MD
455 }
456
984263bc
MD
457 if (error)
458 return (error);
459
460 /*
461 * linux appears not to copy flags from the parent socket to the
462 * accepted one, so we must clear the flags in the new descriptor.
463 * Ignore any errors, because we already have an open fd.
464 */
9910d07b 465 kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
984263bc
MD
466 return (0);
467}
468
469struct linux_getsockname_args {
470 int s;
471 struct sockaddr *addr;
472 int *namelen;
473};
474
475static int
90b9818c 476linux_getsockname(struct linux_getsockname_args *args, int *res)
984263bc
MD
477{
478 struct linux_getsockname_args linux_args;
801ebe52
DRJ
479 struct sockaddr *sa = NULL;
480 int error, sa_len;
49aca642 481
984263bc 482
801ebe52
DRJ
483 error = copyin(args, &linux_args, sizeof(linux_args));
484 if (error)
485 return (error);
486 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
487 if (error)
984263bc
MD
488 return (error);
489
801ebe52
DRJ
490 error = kern_getsockname(linux_args.s, &sa, &sa_len);
491
492 if (error == 0)
24b9e9d1 493 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
801ebe52
DRJ
494 if (error == 0)
495 error = copyout(&sa_len, linux_args.namelen,
496 sizeof(*linux_args.namelen));
497 if (sa)
498 FREE(sa, M_SONAME);
90b9818c 499 return(error);
984263bc
MD
500}
501
502struct linux_getpeername_args {
503 int s;
504 struct sockaddr *addr;
505 int *namelen;
506};
507
508static int
90b9818c 509linux_getpeername(struct linux_getpeername_args *args, int *res)
984263bc
MD
510{
511 struct linux_getpeername_args linux_args;
801ebe52
DRJ
512 struct sockaddr *sa = NULL;
513 int error, sa_len;
984263bc 514
801ebe52
DRJ
515 error = copyin(args, &linux_args, sizeof(linux_args));
516 if (error)
517 return (error);
518 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
519 if (error)
984263bc
MD
520 return (error);
521
801ebe52
DRJ
522 error = kern_getpeername(linux_args.s, &sa, &sa_len);
523
524 if (error == 0)
24b9e9d1 525 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
801ebe52
DRJ
526 if (error == 0)
527 error = copyout(&sa_len, linux_args.namelen,
528 sizeof(*linux_args.namelen));
529 if (sa)
530 FREE(sa, M_SONAME);
90b9818c 531 return(error);
984263bc
MD
532}
533
534struct linux_socketpair_args {
535 int domain;
536 int type;
537 int protocol;
538 int *rsv;
539};
540
541static int
90b9818c 542linux_socketpair(struct linux_socketpair_args *args, int *res)
984263bc
MD
543{
544 struct linux_socketpair_args linux_args;
801ebe52 545 int error, domain, sockv[2];
984263bc 546
801ebe52
DRJ
547 error = copyin(args, &linux_args, sizeof(linux_args));
548 if (error)
984263bc
MD
549 return (error);
550
801ebe52
DRJ
551 domain = linux_to_bsd_domain(linux_args.domain);
552 if (domain == -1)
984263bc 553 return (EINVAL);
801ebe52
DRJ
554 error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
555 sockv);
984263bc 556
801ebe52
DRJ
557 if (error == 0)
558 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
90b9818c 559 return(error);
984263bc
MD
560}
561
562struct linux_send_args {
563 int s;
564 void *msg;
565 int len;
566 int flags;
567};
568
569static int
e54488bb 570linux_send(struct linux_send_args *args, size_t *res)
984263bc
MD
571{
572 struct linux_send_args linux_args;
24b9e9d1
DRJ
573 struct thread *td = curthread;
574 struct uio auio;
575 struct iovec aiov;
984263bc
MD
576 int error;
577
24b9e9d1
DRJ
578 error = copyin(args, &linux_args, sizeof(linux_args));
579 if (error)
984263bc
MD
580 return (error);
581
24b9e9d1
DRJ
582 aiov.iov_base = linux_args.msg;
583 aiov.iov_len = linux_args.len;
584 auio.uio_iov = &aiov;
585 auio.uio_iovcnt = 1;
586 auio.uio_offset = 0;
587 auio.uio_resid = linux_args.len;
588 auio.uio_segflg = UIO_USERSPACE;
589 auio.uio_rw = UIO_WRITE;
590 auio.uio_td = td;
591
592 error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
e54488bb 593 linux_args.flags, res);
24b9e9d1 594
90b9818c 595 return(error);
984263bc
MD
596}
597
598struct linux_recv_args {
599 int s;
600 void *msg;
601 int len;
602 int flags;
603};
604
605static int
e54488bb 606linux_recv(struct linux_recv_args *args, size_t *res)
984263bc
MD
607{
608 struct linux_recv_args linux_args;
24b9e9d1
DRJ
609 struct thread *td = curthread;
610 struct uio auio;
611 struct iovec aiov;
984263bc
MD
612 int error;
613
24b9e9d1
DRJ
614 error = copyin(args, &linux_args, sizeof(linux_args));
615 if (error)
984263bc
MD
616 return (error);
617
24b9e9d1
DRJ
618 aiov.iov_base = linux_args.msg;
619 aiov.iov_len = linux_args.len;
620 auio.uio_iov = &aiov;
621 auio.uio_iovcnt = 1;
622 auio.uio_offset = 0;
623 auio.uio_resid = linux_args.len;
624 auio.uio_segflg = UIO_USERSPACE;
625 auio.uio_rw = UIO_READ;
626 auio.uio_td = td;
627
628 error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
e54488bb 629 &linux_args.flags, res);
24b9e9d1 630
90b9818c 631 return(error);
984263bc
MD
632}
633
634struct linux_sendto_args {
635 int s;
636 void *msg;
637 int len;
638 int flags;
24b9e9d1 639 struct sockaddr *to;
984263bc
MD
640 int tolen;
641};
642
643static int
e54488bb 644linux_sendto(struct linux_sendto_args *args, size_t *res)
984263bc
MD
645{
646 struct linux_sendto_args linux_args;
24b9e9d1
DRJ
647 struct thread *td = curthread;
648 struct uio auio;
649 struct iovec aiov;
650 struct sockopt sopt;
651 struct sockaddr *sa = NULL;
652 caddr_t msg = NULL;
653 int error, optval;
984263bc 654
24b9e9d1
DRJ
655 error = copyin(args, &linux_args, sizeof(linux_args));
656 if (error)
984263bc
MD
657 return (error);
658
24b9e9d1
DRJ
659 if (linux_args.to) {
660 error = linux_getsockaddr(&sa, linux_args.to,
661 linux_args.tolen);
662 if (error)
663 return (error);
664 }
984263bc 665
24b9e9d1
DRJ
666 /*
667 * Check to see if the IP_HDRINCL option is set.
668 */
669 sopt.sopt_dir = SOPT_GET;
670 sopt.sopt_level = IPPROTO_IP;
671 sopt.sopt_name = IP_HDRINCL;
672 sopt.sopt_val = &optval;
673 sopt.sopt_valsize = sizeof(optval);
674 sopt.sopt_td = NULL;
675
2e866b9a
MD
676 if (kern_getsockopt(linux_args.s, &sopt) != 0)
677 optval = 0;
984263bc 678
24b9e9d1
DRJ
679 if (optval == 0) {
680 /*
681 * IP_HDRINCL is not set. Package the message as usual.
682 */
683 aiov.iov_base = linux_args.msg;
684 aiov.iov_len = linux_args.len;
685 auio.uio_iov = &aiov;
686 auio.uio_iovcnt = 1;
687 auio.uio_offset = 0;
688 auio.uio_resid = linux_args.len;
689 auio.uio_segflg = UIO_USERSPACE;
690 auio.uio_rw = UIO_WRITE;
691 auio.uio_td = td;
692 } else {
693 /*
694 * IP_HDRINCL is set. We must convert the beginning of
695 * the packet header so we can feed it to the BSD kernel.
696 */
697
698 /*
699 * Check that the packet header is long enough to contain
700 * the fields of interest. This relies on the fact that
701 * the fragment offset field comes after the length field.
702 */
703 if (linux_args.len < offsetof(struct ip, ip_off))
704 return (EINVAL);
705
706 MALLOC(msg, caddr_t, linux_args.len, M_LINUX, M_WAITOK);
707 error = copyin(linux_args.msg, msg, linux_args.len);
708 if (error)
709 goto cleanup;
710
711 /* Fix the ip_len and ip_off fields. */
712 ((struct ip *)msg)->ip_len = linux_args.len;
713 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
714
715 aiov.iov_base = msg;
716 aiov.iov_len = linux_args.len;
717 auio.uio_iov = &aiov;
718 auio.uio_iovcnt = 1;
719 auio.uio_offset = 0;
720 auio.uio_resid = linux_args.len;
721 auio.uio_segflg = UIO_SYSSPACE;
722 auio.uio_rw = UIO_WRITE;
723 auio.uio_td = td;
724 }
725
e54488bb
MD
726 error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
727 linux_args.flags, res);
24b9e9d1
DRJ
728
729cleanup:
730 if (sa)
731 FREE(sa, M_SONAME);
732 if (msg)
733 FREE(msg, M_LINUX);
90b9818c 734 return(error);
984263bc
MD
735}
736
737struct linux_recvfrom_args {
738 int s;
739 void *buf;
740 int len;
741 int flags;
24b9e9d1 742 struct sockaddr *from;
984263bc
MD
743 int *fromlen;
744};
745
746static int
e54488bb 747linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
984263bc
MD
748{
749 struct linux_recvfrom_args linux_args;
24b9e9d1
DRJ
750 struct thread *td = curthread;
751 struct uio auio;
752 struct iovec aiov;
753 struct sockaddr *sa = NULL;
754 int error, fromlen, flags;
984263bc 755
24b9e9d1
DRJ
756 error = copyin(args, &linux_args, sizeof(linux_args));
757 if (error)
984263bc
MD
758 return (error);
759
24b9e9d1
DRJ
760 if (linux_args.from && linux_args.fromlen) {
761 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
762 if (error)
763 return (error);
764 if (fromlen < 0)
765 return (EINVAL);
766 } else {
767 fromlen = 0;
768 }
769 aiov.iov_base = linux_args.buf;
770 aiov.iov_len = linux_args.len;
771 auio.uio_iov = &aiov;
772 auio.uio_iovcnt = 1;
773 auio.uio_offset = 0;
774 auio.uio_resid = linux_args.len;
775 auio.uio_segflg = UIO_USERSPACE;
776 auio.uio_rw = UIO_READ;
777 auio.uio_td = td;
778
779 flags = linux_to_bsd_msg_flags(linux_args.flags);
780
781 error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
e54488bb 782 NULL, &flags, res);
24b9e9d1
DRJ
783
784 if (error == 0 && linux_args.from) {
b9cd15b9
YT
785 if (sa != NULL) {
786 fromlen = MIN(fromlen, sa->sa_len);
787 error = linux_copyout_sockaddr(sa, linux_args.from,
788 fromlen);
789 } else
790 fromlen = 0;
24b9e9d1
DRJ
791 if (error == 0)
792 copyout(&fromlen, linux_args.fromlen,
793 sizeof(fromlen));
794 }
795 if (sa)
796 FREE(sa, M_SONAME);
797
90b9818c 798 return(error);
984263bc
MD
799}
800
24b9e9d1
DRJ
801struct linux_sendmsg_args {
802 int s;
803 struct msghdr *msg;
804 int flags;
805};
806
807static int
e54488bb 808linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
24b9e9d1
DRJ
809{
810 struct linux_sendmsg_args linux_args;
811 struct thread *td = curthread;
812 struct msghdr msg;
813 struct uio auio;
75a872f8 814 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
24b9e9d1
DRJ
815 struct sockaddr *sa = NULL;
816 struct mbuf *control = NULL;
75a872f8 817 int error;
24b9e9d1
DRJ
818
819 error = copyin(args, &linux_args, sizeof(linux_args));
820 if (error)
821 return (error);
822
823 error = copyin(linux_args.msg, &msg, sizeof(msg));
824 if (error)
825 return (error);
826
827 /*
828 * Conditionally copyin msg.msg_name.
829 */
830 if (msg.msg_name) {
831 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
832 if (error)
833 return (error);
834 }
835
836 /*
837 * Populate auio.
838 */
75a872f8 839 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
ef5c76d7 840 &auio.uio_resid);
24b9e9d1 841 if (error)
8130f673 842 goto cleanup2;
24b9e9d1
DRJ
843 auio.uio_iov = iov;
844 auio.uio_iovcnt = msg.msg_iovlen;
845 auio.uio_offset = 0;
24b9e9d1
DRJ
846 auio.uio_segflg = UIO_USERSPACE;
847 auio.uio_rw = UIO_WRITE;
848 auio.uio_td = td;
849
850 /*
851 * Conditionally copyin msg.msg_control.
852 */
853 if (msg.msg_control) {
854 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
855 msg.msg_controllen > MLEN) {
856 error = EINVAL;
857 goto cleanup;
858 }
74f1caca 859 control = m_get(MB_WAIT, MT_CONTROL);
24b9e9d1
DRJ
860 if (control == NULL) {
861 error = ENOBUFS;
862 goto cleanup;
863 }
864 control->m_len = msg.msg_controllen;
865 error = copyin(msg.msg_control, mtod(control, caddr_t),
866 msg.msg_controllen);
867 if (error) {
868 m_free(control);
869 goto cleanup;
870 }
871 /*
872 * Linux and BSD both support SCM_RIGHTS. If a linux binary
873 * wants anything else with an option level of SOL_SOCKET,
874 * we don't support it.
875 */
876 if (mtod(control, struct cmsghdr *)->cmsg_level ==
877 SOL_SOCKET &&
878 mtod(control, struct cmsghdr *)->cmsg_type !=
879 SCM_RIGHTS) {
880 m_free(control);
881 error = EINVAL;
882 goto cleanup;
883 }
884 }
885
886 error = kern_sendmsg(linux_args.s, sa, &auio, control,
e54488bb 887 linux_args.flags, res);
24b9e9d1
DRJ
888
889cleanup:
8130f673
MD
890 iovec_free(&iov, aiov);
891cleanup2:
24b9e9d1
DRJ
892 if (sa)
893 FREE(sa, M_SONAME);
24b9e9d1
DRJ
894 return (error);
895}
896
984263bc
MD
897struct linux_recvmsg_args {
898 int s;
899 struct msghdr *msg;
900 int flags;
901};
902
903static int
e54488bb 904linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
984263bc
MD
905{
906 struct linux_recvmsg_args linux_args;
24b9e9d1
DRJ
907 struct thread *td = curthread;
908 struct msghdr msg;
909 struct uio auio;
75a872f8
DRJ
910 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
911 struct mbuf *m, *control = NULL;
24b9e9d1
DRJ
912 struct sockaddr *sa = NULL;
913 caddr_t ctlbuf;
914 socklen_t *ufromlenp, *ucontrollenp;
75a872f8 915 int error, fromlen, controllen, len, flags, *uflagsp;
984263bc 916
24b9e9d1
DRJ
917 error = copyin(args, &linux_args, sizeof(linux_args));
918 if (error)
984263bc
MD
919 return (error);
920
24b9e9d1
DRJ
921 error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
922 if (error)
923 return (error);
924
925 if (msg.msg_name && msg.msg_namelen < 0)
926 return (EINVAL);
927 if (msg.msg_control && msg.msg_controllen < 0)
928 return (EINVAL);
929
930 ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
931 offsetof(struct msghdr, msg_namelen));
932 ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
933 offsetof(struct msghdr, msg_controllen));
934 uflagsp = (int *)((caddr_t)linux_args.msg +
935 offsetof(struct msghdr, msg_flags));
936
937 /*
938 * Populate auio.
939 */
75a872f8 940 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
ef5c76d7 941 &auio.uio_resid);
24b9e9d1 942 if (error)
75a872f8 943 return (error);
24b9e9d1
DRJ
944 auio.uio_iov = iov;
945 auio.uio_iovcnt = msg.msg_iovlen;
946 auio.uio_offset = 0;
24b9e9d1
DRJ
947 auio.uio_segflg = UIO_USERSPACE;
948 auio.uio_rw = UIO_READ;
949 auio.uio_td = td;
950
951 flags = linux_to_bsd_msg_flags(linux_args.flags);
952
953 error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
e54488bb 954 msg.msg_control ? &control : NULL, &flags, res);
24b9e9d1
DRJ
955
956 /*
957 * Copyout msg.msg_name and msg.msg_namelen.
958 */
959 if (error == 0 && msg.msg_name) {
b9cd15b9
YT
960 if (sa != NULL) {
961 fromlen = MIN(msg.msg_namelen, sa->sa_len);
962 error = linux_copyout_sockaddr(sa, msg.msg_name,
963 fromlen);
964 } else
965 fromlen = 0;
24b9e9d1
DRJ
966 if (error == 0)
967 error = copyout(&fromlen, ufromlenp,
968 sizeof(*ufromlenp));
969 }
970
971 /*
972 * Copyout msg.msg_control and msg.msg_controllen.
973 */
974 if (error == 0 && msg.msg_control) {
975 /*
976 * Linux and BSD both support SCM_RIGHTS. If a linux binary
977 * wants anything else with an option level of SOL_SOCKET,
978 * we don't support it.
979 */
980 if (mtod((struct mbuf *)msg.msg_control,
981 struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
982 mtod((struct mbuf *)msg.msg_control,
983 struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
984 error = EINVAL;
985 goto cleanup;
986 }
987
988 len = msg.msg_controllen;
989 m = control;
990 ctlbuf = (caddr_t)msg.msg_control;
991
992 while (m && len > 0) {
993 unsigned int tocopy;
994
995 if (len >= m->m_len) {
996 tocopy = m->m_len;
997 } else {
998 msg.msg_flags |= MSG_CTRUNC;
999 tocopy = len;
1000 }
1001
1002 error = copyout(mtod(m, caddr_t), ctlbuf,
1003 tocopy);
1004 if (error)
1005 goto cleanup;
1006
1007 ctlbuf += tocopy;
1008 len -= tocopy;
1009 m = m->m_next;
1010 }
1011 controllen = ctlbuf - (caddr_t)msg.msg_control;
1012 error = copyout(&controllen, ucontrollenp,
1013 sizeof(*ucontrollenp));
1014 }
1015
1016 if (error == 0)
1017 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1018
1019cleanup:
1020 if (sa)
1021 FREE(sa, M_SONAME);
75a872f8 1022 iovec_free(&iov, aiov);
24b9e9d1
DRJ
1023 if (control)
1024 m_freem(control);
1025 return (error);
984263bc
MD
1026}
1027
1028struct linux_shutdown_args {
1029 int s;
1030 int how;
1031};
1032
1033static int
90b9818c 1034linux_shutdown(struct linux_shutdown_args *args, int *res)
984263bc
MD
1035{
1036 struct linux_shutdown_args linux_args;
984263bc
MD
1037 int error;
1038
9864c666
DRJ
1039 error = copyin(args, &linux_args, sizeof(linux_args));
1040 if (error)
984263bc
MD
1041 return (error);
1042
9864c666
DRJ
1043 error = kern_shutdown(linux_args.s, linux_args.how);
1044
1045 return (error);
984263bc
MD
1046}
1047
1048struct linux_setsockopt_args {
1049 int s;
1050 int level;
1051 int optname;
1052 void *optval;
1053 int optlen;
1054};
1055
1056static int
90b9818c 1057linux_setsockopt(struct linux_setsockopt_args *args, int *res)
984263bc
MD
1058{
1059 struct linux_setsockopt_args linux_args;
24b9e9d1
DRJ
1060 struct thread *td = curthread;
1061 struct sockopt sopt;
1062 int error, name, level;
984263bc 1063
24b9e9d1
DRJ
1064 error = copyin(args, &linux_args, sizeof(linux_args));
1065 if (error)
984263bc
MD
1066 return (error);
1067
24b9e9d1
DRJ
1068 level = linux_to_bsd_sockopt_level(linux_args.level);
1069 switch (level) {
984263bc
MD
1070 case SOL_SOCKET:
1071 name = linux_to_bsd_so_sockopt(linux_args.optname);
1072 break;
1073 case IPPROTO_IP:
1074 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1075 break;
1076 case IPPROTO_TCP:
1077 /* Linux TCP option values match BSD's */
1078 name = linux_args.optname;
1079 break;
1080 default:
1081 name = -1;
1082 break;
1083 }
1084 if (name == -1)
1085 return (EINVAL);
1086
24b9e9d1
DRJ
1087 sopt.sopt_dir = SOPT_SET;
1088 sopt.sopt_level = level;
1089 sopt.sopt_name = name;
24b9e9d1
DRJ
1090 sopt.sopt_valsize = linux_args.optlen;
1091 sopt.sopt_td = td;
1092
c2b0a86c
MD
1093 if (sopt.sopt_valsize < 0 || sopt.sopt_valsize > SOMAXOPT_SIZE)
1094 return (EINVAL);
1095
792239df
AE
1096 if (linux_args.optval) {
1097 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1098 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1099 if (error)
1100 goto out;
1101 } else {
1102 sopt.sopt_val = NULL;
1103 }
24b9e9d1 1104 error = kern_setsockopt(linux_args.s, &sopt);
792239df
AE
1105 if (error)
1106 goto out;
1107 if (linux_args.optval)
1108 error = copyout(sopt.sopt_val, linux_args.optval,
1109 sopt.sopt_valsize);
1110out:
1111 if (linux_args.optval)
1112 kfree(sopt.sopt_val, M_TEMP);
90b9818c 1113 return(error);
984263bc
MD
1114}
1115
1116struct linux_getsockopt_args {
1117 int s;
1118 int level;
1119 int optname;
1120 void *optval;
1121 int *optlen;
1122};
1123
1124static int
90b9818c 1125linux_getsockopt(struct linux_getsockopt_args *args, int *res)
984263bc
MD
1126{
1127 struct linux_getsockopt_args linux_args;
24b9e9d1
DRJ
1128 struct thread *td = curthread;
1129 struct sockopt sopt;
1130 int error, name, valsize, level;
984263bc 1131
24b9e9d1
DRJ
1132 error = copyin(args, &linux_args, sizeof(linux_args));
1133 if (error)
984263bc
MD
1134 return (error);
1135
24b9e9d1
DRJ
1136 if (linux_args.optval) {
1137 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1138 if (error)
1139 return (error);
c2b0a86c 1140 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
24b9e9d1
DRJ
1141 return (EINVAL);
1142 } else {
1143 valsize = 0;
1144 }
1145
1146 level = linux_to_bsd_sockopt_level(linux_args.level);
1147 switch (level) {
984263bc
MD
1148 case SOL_SOCKET:
1149 name = linux_to_bsd_so_sockopt(linux_args.optname);
1150 break;
1151 case IPPROTO_IP:
1152 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1153 break;
1154 case IPPROTO_TCP:
1155 /* Linux TCP option values match BSD's */
1156 name = linux_args.optname;
1157 break;
1158 default:
1159 name = -1;
1160 break;
1161 }
1162 if (name == -1)
1163 return (EINVAL);
1164
24b9e9d1
DRJ
1165 sopt.sopt_dir = SOPT_GET;
1166 sopt.sopt_level = level;
1167 sopt.sopt_name = name;
24b9e9d1
DRJ
1168 sopt.sopt_valsize = valsize;
1169 sopt.sopt_td = td;
1170
792239df
AE
1171 if (linux_args.optval) {
1172 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1173 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1174 if (error)
1175 goto out;
1176 } else {
1177 sopt.sopt_val = NULL;
24b9e9d1 1178 }
792239df
AE
1179 error = kern_getsockopt(linux_args.s, &sopt);
1180 if (error)
1181 goto out;
1182 valsize = sopt.sopt_valsize;
1183 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1184 if (error)
1185 goto out;
1186 if (linux_args.optval)
1187 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1188out:
1189 if (linux_args.optval)
1190 kfree(sopt.sopt_val, M_TEMP);
90b9818c 1191 return(error);
984263bc
MD
1192}
1193
3919ced0
MD
1194/*
1195 * MPALMOSTSAFE
1196 */
984263bc 1197int
753fd850 1198sys_linux_socketcall(struct linux_socketcall_args *args)
984263bc
MD
1199{
1200 void *arg = (void *)args->args;
1201
3919ced0
MD
1202 get_mplock();
1203
984263bc
MD
1204 switch (args->what) {
1205 case LINUX_SOCKET:
c7114eea 1206 return (linux_socket(arg, &args->sysmsg_result));
984263bc 1207 case LINUX_BIND:
c7114eea 1208 return (linux_bind(arg, &args->sysmsg_result));
984263bc 1209 case LINUX_CONNECT:
c7114eea 1210 return (linux_connect(arg, &args->sysmsg_result));
984263bc 1211 case LINUX_LISTEN:
c7114eea 1212 return (linux_listen(arg, &args->sysmsg_result));
984263bc 1213 case LINUX_ACCEPT:
c7114eea 1214 return (linux_accept(arg, &args->sysmsg_result));
984263bc 1215 case LINUX_GETSOCKNAME:
c7114eea 1216 return (linux_getsockname(arg, &args->sysmsg_result));
984263bc 1217 case LINUX_GETPEERNAME:
c7114eea 1218 return (linux_getpeername(arg, &args->sysmsg_result));
984263bc 1219 case LINUX_SOCKETPAIR:
c7114eea 1220 return (linux_socketpair(arg, &args->sysmsg_result));
984263bc 1221 case LINUX_SEND:
e54488bb 1222 return (linux_send(arg, &args->sysmsg_szresult));
984263bc 1223 case LINUX_RECV:
e54488bb 1224 return (linux_recv(arg, &args->sysmsg_szresult));
984263bc 1225 case LINUX_SENDTO:
e54488bb 1226 return (linux_sendto(arg, &args->sysmsg_szresult));
984263bc 1227 case LINUX_RECVFROM:
e54488bb 1228 return (linux_recvfrom(arg, &args->sysmsg_szresult));
984263bc 1229 case LINUX_SHUTDOWN:
c7114eea 1230 return (linux_shutdown(arg, &args->sysmsg_result));
984263bc 1231 case LINUX_SETSOCKOPT:
c7114eea 1232 return (linux_setsockopt(arg, &args->sysmsg_result));
984263bc 1233 case LINUX_GETSOCKOPT:
c7114eea 1234 return (linux_getsockopt(arg, &args->sysmsg_result));
984263bc 1235 case LINUX_SENDMSG:
e54488bb 1236 return (linux_sendmsg(arg, &args->sysmsg_szresult));
984263bc 1237 case LINUX_RECVMSG:
e54488bb 1238 return (linux_recvmsg(arg, &args->sysmsg_szresult));
984263bc 1239 }
3919ced0 1240 rel_mplock();
984263bc
MD
1241
1242 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1243 return (ENOSYS);
1244}