Annotation of sys/compat/linux/linux_socket.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: linux_socket.c,v 1.36 2007/06/06 09:59:21 henning Exp $ */
! 2: /* $NetBSD: linux_socket.c,v 1.14 1996/04/05 00:01:50 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995 Frank van der Linden
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed for the NetBSD Project
! 19: * by Frank van der Linden
! 20: * 4. The name of the author may not be used to endorse or promote products
! 21: * derived from this software without specific prior written permission
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/buf.h>
! 39: #include <sys/malloc.h>
! 40: #include <sys/ioctl.h>
! 41: #include <sys/tty.h>
! 42: #include <sys/file.h>
! 43: #include <sys/filedesc.h>
! 44: #include <sys/selinfo.h>
! 45: #include <sys/socket.h>
! 46: #include <sys/socketvar.h>
! 47: #include <net/if.h>
! 48: #include <net/if_types.h>
! 49: #include <net/if_dl.h>
! 50: #include <netinet/in.h>
! 51: #include <netinet/in_systm.h>
! 52: #include <netinet/ip.h>
! 53: #include <netinet/tcp.h>
! 54: #include <sys/mount.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/vnode.h>
! 57: #include <sys/device.h>
! 58:
! 59: #include <sys/syscallargs.h>
! 60:
! 61: #include <compat/linux/linux_types.h>
! 62: #include <compat/linux/linux_util.h>
! 63: #include <compat/linux/linux_signal.h>
! 64: #include <compat/linux/linux_syscallargs.h>
! 65: #include <compat/linux/linux_ioctl.h>
! 66: #include <compat/linux/linux_socket.h>
! 67: #include <compat/linux/linux_socketcall.h>
! 68: #include <compat/linux/linux_sockio.h>
! 69:
! 70: /*
! 71: * All the calls in this file are entered via one common system
! 72: * call in Linux, represented here by linux_socketcall()
! 73: * Arguments for the various calls are on the user stack. A pointer
! 74: * to them is the only thing that is passed. It is up to the various
! 75: * calls to copy them in themselves. To make it look better, they
! 76: * are copied to structures.
! 77: */
! 78:
! 79: static int linux_to_bsd_domain (int);
! 80: static int bsd_to_linux_domain(int);
! 81:
! 82: int linux_socket(struct proc *, void *, register_t *);
! 83: int linux_bind(struct proc *, void *, register_t *);
! 84: int linux_connect(struct proc *, void *, register_t *);
! 85: int linux_listen(struct proc *, void *, register_t *);
! 86: int linux_accept(struct proc *, void *, register_t *);
! 87: int linux_getsockname(struct proc *, void *, register_t *);
! 88: int linux_getpeername(struct proc *, void *, register_t *);
! 89: int linux_socketpair(struct proc *, void *, register_t *);
! 90: int linux_send(struct proc *, void *, register_t *);
! 91: int linux_recv(struct proc *, void *, register_t *);
! 92: int linux_sendto(struct proc *, void *, register_t *);
! 93: int linux_recvfrom(struct proc *, void *, register_t *);
! 94: int linux_shutdown(struct proc *, void *, register_t *);
! 95: int linux_to_bsd_sopt_level(int);
! 96: int linux_to_bsd_so_sockopt(int);
! 97: int linux_to_bsd_ip_sockopt(int);
! 98: int linux_to_bsd_tcp_sockopt(int);
! 99: int linux_to_bsd_udp_sockopt(int);
! 100: int linux_setsockopt(struct proc *, void *, register_t *);
! 101: int linux_getsockopt(struct proc *, void *, register_t *);
! 102: int linux_recvmsg(struct proc *, void *, register_t *);
! 103: int linux_sendmsg(struct proc *, void *, register_t *);
! 104:
! 105: int linux_check_hdrincl(struct proc *, int, register_t *, caddr_t *);
! 106: int linux_sendto_hdrincl(struct proc *, struct sys_sendto_args *,
! 107: register_t *, caddr_t *);
! 108:
! 109: int linux_sa_get(struct proc *, caddr_t *, struct sockaddr **,
! 110: const struct osockaddr *, int *);
! 111: int linux_sa_put(struct osockaddr *);
! 112:
! 113: static const int linux_to_bsd_domain_[LINUX_AF_MAX] = {
! 114: AF_UNSPEC,
! 115: AF_UNIX,
! 116: AF_INET,
! 117: -1, /* LINUX_AF_AX25 */
! 118: -1, /* IPX */
! 119: AF_APPLETALK,
! 120: -1, /* LINUX_AF_NETROM */
! 121: -1, /* LINUX_AF_BRIDGE */
! 122: -1, /* LINUX_AF_ATMPVC */
! 123: -1, /* LINUX_AF_X25 */
! 124: AF_INET6,
! 125: -1, /* LINUX_AF_ROSE */
! 126: AF_DECnet,
! 127: -1, /* LINUX_AF_NETBEUI */
! 128: -1, /* LINUX_AF_SECURITY */
! 129: -1, /* pseudo_AF_KEY */
! 130: AF_ROUTE, /* LINUX_AF_NETLINK */
! 131: -1, /* LINUX_AF_PACKET */
! 132: -1, /* LINUX_AF_ASH */
! 133: -1, /* LINUX_AF_ECONET */
! 134: -1, /* LINUX_AF_ATMSVC */
! 135: AF_SNA,
! 136: /* rest up to LINUX_AF_MAX-1 is not allocated */
! 137: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
! 138: };
! 139:
! 140: static const int bsd_to_linux_domain_[AF_MAX] = {
! 141: LINUX_AF_UNSPEC,
! 142: LINUX_AF_UNIX,
! 143: LINUX_AF_INET,
! 144: -1, /* AF_IMPLINK */
! 145: -1, /* AF_PUP */
! 146: -1, /* AF_CHAOS */
! 147: -1, /* AF_NS */
! 148: -1, /* AF_ISO */
! 149: -1, /* AF_ECMA */
! 150: -1, /* AF_DATAKIT */
! 151: -1, /* AF_CCITT */
! 152: -1, /* LINUX_AF_SNA */
! 153: -1, /* LINUX_AF_DECnet */
! 154: -1, /* AF_DLI */
! 155: -1, /* AF_LAT */
! 156: -1, /* AF_HYLINK */
! 157: LINUX_AF_APPLETALK,
! 158: -1, /* LINUX_AF_NETLINK */
! 159: -1, /* AF_LINK */
! 160: -1, /* AF_XTP */
! 161: -1, /* AF_COIP */
! 162: -1, /* AF_CNT */
! 163: -1, /* pseudo_AF_RTIP */
! 164: LINUX_AF_IPX,
! 165: LINUX_AF_INET6,
! 166: -1, /* pseudo_AF_PIP */
! 167: -1, /* AF_ISDN */
! 168: -1, /* AF_NATM */
! 169: -1, /* AF_ARP */
! 170: -1, /* LINUX_pseudo_AF_KEY */
! 171: -1, /* pseudo_AF_HDRCMPLT */
! 172: };
! 173:
! 174: /*
! 175: * Convert between Linux and BSD socket domain values
! 176: */
! 177: static int
! 178: linux_to_bsd_domain(ldom)
! 179: int ldom;
! 180: {
! 181: if (ldom < 0 || ldom >= LINUX_AF_MAX)
! 182: return (-1);
! 183:
! 184: return linux_to_bsd_domain_[ldom];
! 185: }
! 186:
! 187: /*
! 188: * Convert between BSD and Linux socket domain values
! 189: */
! 190: static int
! 191: bsd_to_linux_domain(bdom)
! 192: int bdom;
! 193: {
! 194: if (bdom < 0 || bdom >= AF_MAX)
! 195: return (-1);
! 196:
! 197: return bsd_to_linux_domain_[bdom];
! 198: }
! 199:
! 200: int
! 201: linux_socket(p, v, retval)
! 202: struct proc *p;
! 203: void *v;
! 204: register_t *retval;
! 205: {
! 206: struct linux_socket_args /* {
! 207: syscallarg(int) domain;
! 208: syscallarg(int) type;
! 209: syscallarg(int) protocol;
! 210: } */ *uap = v;
! 211: struct linux_socket_args lsa;
! 212: struct sys_socket_args bsa;
! 213: int error;
! 214:
! 215: if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
! 216: return error;
! 217:
! 218: SCARG(&bsa, protocol) = lsa.protocol;
! 219: SCARG(&bsa, type) = lsa.type;
! 220: SCARG(&bsa, domain) = linux_to_bsd_domain(lsa.domain);
! 221: if (SCARG(&bsa, domain) == -1)
! 222: return EINVAL;
! 223: return sys_socket(p, &bsa, retval);
! 224: }
! 225:
! 226: int
! 227: linux_bind(p, v, retval)
! 228: struct proc *p;
! 229: void *v;
! 230: register_t *retval;
! 231: {
! 232: struct linux_bind_args /* {
! 233: syscallarg(int) s;
! 234: syscallarg(struct sockaddr *) name;
! 235: syscallarg(int) namelen;
! 236: } */ *uap = v;
! 237: struct linux_bind_args lba;
! 238: struct sys_bind_args bba;
! 239: int error;
! 240: int namlen;
! 241:
! 242: if ((error = copyin((caddr_t) uap, (caddr_t) &lba, sizeof lba)))
! 243: return error;
! 244:
! 245: SCARG(&bba, s) = lba.s;
! 246: namlen = lba.namelen;
! 247: if (lba.name) {
! 248: struct sockaddr *sa;
! 249: caddr_t sg = stackgap_init(p->p_emul);
! 250:
! 251: error = linux_sa_get(p, &sg, &sa, lba.name, &namlen);
! 252: if (error)
! 253: return (error);
! 254: SCARG(&bba, name) = sa;
! 255: } else
! 256: SCARG(&bba, name) = NULL;
! 257: SCARG(&bba, namelen) = namlen;
! 258:
! 259: return sys_bind(p, &bba, retval);
! 260: }
! 261:
! 262: int
! 263: linux_connect(p, v, retval)
! 264: struct proc *p;
! 265: void *v;
! 266: register_t *retval;
! 267: {
! 268: struct linux_connect_args /* {
! 269: syscallarg(int) s;
! 270: syscallarg(struct osockaddr *) name;
! 271: syscallarg(int) namelen;
! 272: } */ *uap = v;
! 273: struct linux_connect_args lca;
! 274: struct sys_connect_args bca;
! 275: struct sockaddr *sa;
! 276: caddr_t sg = stackgap_init(p->p_emul);
! 277: int namlen;
! 278: int error;
! 279:
! 280: if ((error = copyin((caddr_t) uap, (caddr_t) &lca, sizeof lca)))
! 281: return error;
! 282:
! 283: namlen = lca.namelen;
! 284: error = linux_sa_get(p, &sg, &sa, lca.name, &namlen);
! 285: if (error)
! 286: return (error);
! 287:
! 288: SCARG(&bca, s) = lca.s;
! 289: SCARG(&bca, name) = sa;
! 290: SCARG(&bca, namelen) = (unsigned int)namlen;
! 291:
! 292: error = sys_connect(p, &bca, retval);
! 293:
! 294: if (error == EISCONN) {
! 295: struct sys_getsockopt_args bga;
! 296: #if 0
! 297: struct sys_fcntl_args fca;
! 298: #endif
! 299: void *status, *statusl;
! 300: int stat, statl = sizeof stat;
! 301:
! 302: #if 0
! 303: SCARG(&fca, fd) = lca.s;
! 304: SCARG(&fca, cmd) = F_GETFL;
! 305: SCARG(&fca, arg) = 0;
! 306: if (sys_fcntl(p, &fca, retval) == -1 ||
! 307: (*retval & O_NONBLOCK) == 0)
! 308: return error;
! 309: #endif
! 310:
! 311: status = stackgap_alloc(&sg, sizeof stat);
! 312: statusl = stackgap_alloc(&sg, sizeof statusl);
! 313:
! 314: if ((error = copyout(&statl, statusl, sizeof statl)))
! 315: return error;
! 316:
! 317: SCARG(&bga, s) = lca.s;
! 318: SCARG(&bga, level) = SOL_SOCKET;
! 319: SCARG(&bga, name) = SO_ERROR;
! 320: SCARG(&bga, val) = status;
! 321: SCARG(&bga, avalsize) = statusl;
! 322:
! 323: error = sys_getsockopt(p, &bga, retval);
! 324: if (error)
! 325: return error;
! 326: if ((error = copyin(status, &stat, sizeof stat)))
! 327: return error;
! 328: return stat;
! 329: }
! 330: return error;
! 331: }
! 332:
! 333: int
! 334: linux_listen(p, v, retval)
! 335: struct proc *p;
! 336: void *v;
! 337: register_t *retval;
! 338: {
! 339: struct linux_listen_args /* {
! 340: syscallarg(int) s;
! 341: syscallarg(int) backlog;
! 342: } */ *uap = v;
! 343: struct linux_listen_args lla;
! 344: struct sys_listen_args bla;
! 345: int error;
! 346:
! 347: if ((error = copyin((caddr_t) uap, (caddr_t) &lla, sizeof lla)))
! 348: return error;
! 349:
! 350: SCARG(&bla, s) = lla.s;
! 351: SCARG(&bla, backlog) = lla.backlog;
! 352:
! 353: return sys_listen(p, &bla, retval);
! 354: }
! 355:
! 356: int
! 357: linux_accept(p, v, retval)
! 358: struct proc *p;
! 359: void *v;
! 360: register_t *retval;
! 361: {
! 362: struct linux_accept_args /* {
! 363: syscallarg(int) s;
! 364: syscallarg(struct sockaddr *) addr;
! 365: syscallarg(int *) namelen;
! 366: } */ *uap = v;
! 367: struct linux_accept_args laa;
! 368: struct compat_43_sys_accept_args baa;
! 369: struct sys_fcntl_args fca;
! 370: int error;
! 371:
! 372: if ((error = copyin((caddr_t) uap, (caddr_t) &laa, sizeof laa)))
! 373: return error;
! 374:
! 375: SCARG(&baa, s) = laa.s;
! 376: SCARG(&baa, name) = (caddr_t) laa.addr;
! 377: SCARG(&baa, anamelen) = laa.namelen;
! 378:
! 379: error = compat_43_sys_accept(p, &baa, retval);
! 380: if (error)
! 381: return (error);
! 382:
! 383: /*
! 384: * linux appears not to copy flags from the parent socket to the
! 385: * accepted one, so we must clear the flags in the new descriptor.
! 386: * Ignore any errors, because we already have an open fd.
! 387: */
! 388: SCARG(&fca, fd) = *retval;
! 389: SCARG(&fca, cmd) = F_SETFL;
! 390: SCARG(&fca, arg) = 0;
! 391: (void)sys_fcntl(p, &fca, retval);
! 392: *retval = SCARG(&fca, fd);
! 393: return (0);
! 394: }
! 395:
! 396: int
! 397: linux_getsockname(p, v, retval)
! 398: struct proc *p;
! 399: void *v;
! 400: register_t *retval;
! 401: {
! 402: struct linux_getsockname_args /* {
! 403: syscallarg(int) s;
! 404: syscallarg(caddr_t) addr;
! 405: syscallarg(int *) namelen;
! 406: } */ *uap = v;
! 407: struct linux_getsockname_args lga;
! 408: struct sys_getsockname_args bga;
! 409: int error;
! 410:
! 411: if ((error = copyin((caddr_t) uap, (caddr_t) &lga, sizeof lga)))
! 412: return error;
! 413:
! 414: SCARG(&bga, fdes) = lga.s;
! 415: SCARG(&bga, asa) = (struct sockaddr *) lga.addr;
! 416: SCARG(&bga, alen) = lga.namelen;
! 417:
! 418: error = sys_getsockname(p, &bga, retval);
! 419: if (error)
! 420: return (error);
! 421:
! 422: if ((error = linux_sa_put((struct osockaddr *)lga.addr)))
! 423: return (error);
! 424:
! 425: return (0);
! 426: }
! 427:
! 428: int
! 429: linux_getpeername(p, v, retval)
! 430: struct proc *p;
! 431: void *v;
! 432: register_t *retval;
! 433: {
! 434: struct linux_getpeername_args /* {
! 435: syscallarg(int) s;
! 436: syscallarg(struct sockaddr *) addr;
! 437: syscallarg(int *) namelen;
! 438: } */ *uap = v;
! 439: struct linux_getpeername_args lga;
! 440: struct sys_getpeername_args bga;
! 441: int error;
! 442:
! 443: if ((error = copyin((caddr_t) uap, (caddr_t) &lga, sizeof lga)))
! 444: return error;
! 445:
! 446: SCARG(&bga, fdes) = lga.s;
! 447: SCARG(&bga, asa) = (struct sockaddr *) lga.addr;
! 448: SCARG(&bga, alen) = lga.namelen;
! 449:
! 450: error = sys_getpeername(p, &bga, retval);
! 451: if (error)
! 452: return (error);
! 453:
! 454: if ((error = linux_sa_put((struct osockaddr *)lga.addr)))
! 455: return (error);
! 456:
! 457: return (0);
! 458: }
! 459:
! 460: int
! 461: linux_socketpair(p, v, retval)
! 462: struct proc *p;
! 463: void *v;
! 464: register_t *retval;
! 465: {
! 466: struct linux_socketpair_args /* {
! 467: syscallarg(int) domain;
! 468: syscallarg(int) type;
! 469: syscallarg(int) protocol;
! 470: syscallarg(int *) rsv;
! 471: } */ *uap = v;
! 472: struct linux_socketpair_args lsa;
! 473: struct sys_socketpair_args bsa;
! 474: int error;
! 475:
! 476: if ((error = copyin((caddr_t) uap, &lsa, sizeof lsa)))
! 477: return error;
! 478:
! 479: SCARG(&bsa, domain) = linux_to_bsd_domain(lsa.domain);
! 480: if (SCARG(&bsa, domain) == -1)
! 481: return EINVAL;
! 482: SCARG(&bsa, type) = lsa.type;
! 483: SCARG(&bsa, protocol) = lsa.protocol;
! 484: SCARG(&bsa, rsv) = lsa.rsv;
! 485:
! 486: return sys_socketpair(p, &bsa, retval);
! 487: }
! 488:
! 489: int
! 490: linux_send(p, v, retval)
! 491: struct proc *p;
! 492: void *v;
! 493: register_t *retval;
! 494: {
! 495: struct linux_send_args /* {
! 496: syscallarg(int) s;
! 497: syscallarg(void *) msg;
! 498: syscallarg(int) len;
! 499: syscallarg(int) flags;
! 500: } */ *uap = v;
! 501: struct linux_send_args lsa;
! 502: struct compat_43_sys_send_args bsa;
! 503: int error;
! 504:
! 505: if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
! 506: return error;
! 507:
! 508: SCARG(&bsa, s) = lsa.s;
! 509: SCARG(&bsa, buf) = lsa.msg;
! 510: SCARG(&bsa, len) = lsa.len;
! 511: SCARG(&bsa, flags) = lsa.flags;
! 512:
! 513: return compat_43_sys_send(p, &bsa, retval);
! 514: }
! 515:
! 516: int
! 517: linux_recv(p, v, retval)
! 518: struct proc *p;
! 519: void *v;
! 520: register_t *retval;
! 521: {
! 522: struct linux_recv_args /* {
! 523: syscallarg(int) s;
! 524: syscallarg(void *) msg;
! 525: syscallarg(int) len;
! 526: syscallarg(int) flags;
! 527: } */ *uap = v;
! 528: struct linux_recv_args lra;
! 529: struct compat_43_sys_recv_args bra;
! 530: int error;
! 531:
! 532: if ((error = copyin((caddr_t) uap, (caddr_t) &lra, sizeof lra)))
! 533: return error;
! 534:
! 535: SCARG(&bra, s) = lra.s;
! 536: SCARG(&bra, buf) = lra.msg;
! 537: SCARG(&bra, len) = lra.len;
! 538: SCARG(&bra, flags) = lra.flags;
! 539:
! 540: return compat_43_sys_recv(p, &bra, retval);
! 541: }
! 542:
! 543: int
! 544: linux_check_hdrincl(p, fd, retval, sgp)
! 545: struct proc *p;
! 546: int fd;
! 547: register_t *retval;
! 548: caddr_t *sgp;
! 549: {
! 550: struct sys_getsockopt_args /* {
! 551: int s;
! 552: int level;
! 553: int name;
! 554: caddr_t val;
! 555: int *avalsize;
! 556: } */ gsa;
! 557: int error;
! 558: caddr_t val;
! 559: int *valsize;
! 560: int size_val = sizeof val;
! 561: int optval;
! 562:
! 563: val = stackgap_alloc(sgp, sizeof(optval));
! 564: valsize = stackgap_alloc(sgp, sizeof(size_val));
! 565:
! 566: if ((error = copyout(&size_val, valsize, sizeof(size_val))))
! 567: return (error);
! 568: SCARG(&gsa, s) = fd;
! 569: SCARG(&gsa, level) = IPPROTO_IP;
! 570: SCARG(&gsa, name) = IP_HDRINCL;
! 571: SCARG(&gsa, val) = val;
! 572: SCARG(&gsa, avalsize) = valsize;
! 573:
! 574: if ((error = sys_getsockopt(p, &gsa, retval)))
! 575: return (error);
! 576: if ((error = copyin(val, &optval, sizeof(optval))))
! 577: return (error);
! 578: return (optval == 0);
! 579: }
! 580:
! 581: /*
! 582: * linux_ip_copysize defines how many bytes we should copy
! 583: * from the beginning of the IP packet before we customize it for BSD.
! 584: * It should include all the fields we modify (ip_len and ip_off)
! 585: * and be as small as possible to minimize copying overhead.
! 586: */
! 587: #define linux_ip_copysize 8
! 588:
! 589: int
! 590: linux_sendto_hdrincl(p, bsa, retval, sgp)
! 591: struct proc *p;
! 592: struct sys_sendto_args *bsa;
! 593: register_t *retval;
! 594: caddr_t *sgp;
! 595: {
! 596: struct sys_sendmsg_args ssa;
! 597: struct ip *packet, rpacket;
! 598: struct msghdr *msg, rmsg;
! 599: struct iovec *iov, riov[2];
! 600: int error;
! 601:
! 602: /* Check the packet isn't too small before we mess with it */
! 603: if (SCARG(bsa, len) < linux_ip_copysize)
! 604: return EINVAL;
! 605:
! 606: /*
! 607: * Tweaking the user buffer in place would be bad manners.
! 608: * We create a corrected IP header with just the needed length,
! 609: * then use an iovec to glue it to the rest of the user packet
! 610: * when calling sendmsg().
! 611: */
! 612: packet = (struct ip *)stackgap_alloc(sgp, linux_ip_copysize);
! 613: msg = (struct msghdr *)stackgap_alloc(sgp, sizeof(*msg));
! 614: iov = (struct iovec *)stackgap_alloc(sgp, sizeof(*iov)*2);
! 615:
! 616: /* Make a copy of the beginning of the packet to be sent */
! 617: if ((error = copyin(SCARG(bsa, buf), (caddr_t)&rpacket,
! 618: linux_ip_copysize)))
! 619: return error;
! 620:
! 621: /* Convert fields from Linux to BSD raw IP socket format */
! 622: rpacket.ip_len = SCARG(bsa, len);
! 623: error = copyout(&rpacket, packet, linux_ip_copysize);
! 624: if (error)
! 625: return (error);
! 626:
! 627: riov[0].iov_base = (char *)packet;
! 628: riov[0].iov_len = linux_ip_copysize;
! 629: riov[1].iov_base = (caddr_t)SCARG(bsa, buf) + linux_ip_copysize;
! 630: riov[1].iov_len = SCARG(bsa, len) - linux_ip_copysize;
! 631:
! 632: error = copyout(&riov[0], iov, sizeof(riov));
! 633: if (error)
! 634: return (error);
! 635:
! 636: /* Prepare the msghdr and iovec structures describing the new packet */
! 637: rmsg.msg_name = (void *)SCARG(bsa, to);
! 638: rmsg.msg_namelen = SCARG(bsa, tolen);
! 639: rmsg.msg_iov = iov;
! 640: rmsg.msg_iovlen = 2;
! 641: rmsg.msg_control = NULL;
! 642: rmsg.msg_controllen = 0;
! 643: rmsg.msg_flags = 0;
! 644:
! 645: error = copyout(&riov[0], iov, sizeof(riov));
! 646: if (error)
! 647: return (error);
! 648:
! 649: SCARG(&ssa, s) = SCARG(bsa, s);
! 650: SCARG(&ssa, msg) = msg;
! 651: SCARG(&ssa, flags) = SCARG(bsa, flags);
! 652: return sys_sendmsg(p, &ssa, retval);
! 653: }
! 654:
! 655: int
! 656: linux_sendto(p, v, retval)
! 657: struct proc *p;
! 658: void *v;
! 659: register_t *retval;
! 660: {
! 661: struct linux_sendto_args /* {
! 662: syscallarg(int) s;
! 663: syscallarg(void *) msg;
! 664: syscallarg(int) len;
! 665: syscallarg(int) flags;
! 666: syscallarg(osockaddr *) to;
! 667: syscallarg(int) tolen;
! 668: } */ *uap = v;
! 669: struct linux_sendto_args lsa;
! 670: struct sys_sendto_args bsa;
! 671: int error;
! 672: int tolen;
! 673: caddr_t sg = stackgap_init(p->p_emul);
! 674:
! 675: if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
! 676: return error;
! 677:
! 678: SCARG(&bsa, s) = lsa.s;
! 679: SCARG(&bsa, buf) = lsa.msg;
! 680: SCARG(&bsa, len) = lsa.len;
! 681: SCARG(&bsa, flags) = lsa.flags;
! 682: tolen = lsa.tolen;
! 683: if (lsa.to) {
! 684: struct sockaddr *sa;
! 685:
! 686: if ((error = linux_sa_get(p, &sg, &sa, lsa.to, &tolen)))
! 687: return (error);
! 688: SCARG(&bsa, to) = sa;
! 689: } else
! 690: SCARG(&bsa, to) = NULL;
! 691: SCARG(&bsa, tolen) = tolen;
! 692:
! 693: if (linux_check_hdrincl(p, lsa.s, retval, &sg) == 0)
! 694: return linux_sendto_hdrincl(p, &bsa, retval, &sg);
! 695: return sys_sendto(p, &bsa, retval);
! 696: }
! 697:
! 698: int
! 699: linux_recvfrom(p, v, retval)
! 700: struct proc *p;
! 701: void *v;
! 702: register_t *retval;
! 703: {
! 704: struct linux_recvfrom_args /* {
! 705: syscallarg(int) s;
! 706: syscallarg(void *) buf;
! 707: syscallarg(int) len;
! 708: syscallarg(int) flags;
! 709: syscallarg(struct osockaddr *) from;
! 710: syscallarg(int *) fromlen;
! 711: } */ *uap = v;
! 712: struct linux_recvfrom_args lra;
! 713: struct sys_recvfrom_args bra;
! 714: int error;
! 715:
! 716: if ((error = copyin((caddr_t) uap, (caddr_t) &lra, sizeof lra)))
! 717: return error;
! 718:
! 719: SCARG(&bra, s) = lra.s;
! 720: SCARG(&bra, buf) = lra.buf;
! 721: SCARG(&bra, len) = lra.len;
! 722: SCARG(&bra, flags) = lra.flags;
! 723: SCARG(&bra, from) = (struct sockaddr *) lra.from;
! 724: SCARG(&bra, fromlenaddr) = lra.fromlen;
! 725:
! 726: if ((error = sys_recvfrom(p, &bra, retval)))
! 727: return (error);
! 728:
! 729: if (lra.from && (error = linux_sa_put(lra.from)))
! 730: return (error);
! 731:
! 732: return (0);
! 733: }
! 734:
! 735: int
! 736: linux_shutdown(p, v, retval)
! 737: struct proc *p;
! 738: void *v;
! 739: register_t *retval;
! 740: {
! 741: struct linux_shutdown_args /* {
! 742: syscallarg(int) s;
! 743: syscallarg(int) how;
! 744: } */ *uap = v;
! 745: struct linux_shutdown_args lsa;
! 746: struct sys_shutdown_args bsa;
! 747: int error;
! 748:
! 749: if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
! 750: return error;
! 751:
! 752: SCARG(&bsa, s) = lsa.s;
! 753: SCARG(&bsa, how) = lsa.how;
! 754:
! 755: return sys_shutdown(p, &bsa, retval);
! 756: }
! 757:
! 758: /*
! 759: * Convert socket option level from Linux to OpenBSD value. Only SOL_SOCKET
! 760: * is different, the rest matches IPPROTO_* on both systems.
! 761: */
! 762: int
! 763: linux_to_bsd_sopt_level(llevel)
! 764: int llevel;
! 765: {
! 766:
! 767: switch (llevel) {
! 768: case LINUX_SOL_SOCKET:
! 769: return SOL_SOCKET;
! 770: case LINUX_SOL_IP:
! 771: return IPPROTO_IP;
! 772: case LINUX_SOL_TCP:
! 773: return IPPROTO_TCP;
! 774: case LINUX_SOL_UDP:
! 775: return IPPROTO_UDP;
! 776: default:
! 777: return -1;
! 778: }
! 779: }
! 780:
! 781: /*
! 782: * Convert Linux socket level socket option numbers to OpenBSD values.
! 783: */
! 784: int
! 785: linux_to_bsd_so_sockopt(lopt)
! 786: int lopt;
! 787: {
! 788:
! 789: switch (lopt) {
! 790: case LINUX_SO_DEBUG:
! 791: return SO_DEBUG;
! 792: case LINUX_SO_REUSEADDR:
! 793: /*
! 794: * Linux does not implement SO_REUSEPORT, but allows reuse
! 795: * of a host:port pair through SO_REUSEADDR even if the
! 796: * address is not a multicast-address. Effectively, this
! 797: * means that we should use SO_REUSEPORT to allow Linux
! 798: * applications to not exit with EADDRINUSE.
! 799: */
! 800: return SO_REUSEPORT;
! 801: case LINUX_SO_TYPE:
! 802: return SO_TYPE;
! 803: case LINUX_SO_ERROR:
! 804: return SO_ERROR;
! 805: case LINUX_SO_DONTROUTE:
! 806: return SO_DONTROUTE;
! 807: case LINUX_SO_BROADCAST:
! 808: return SO_BROADCAST;
! 809: case LINUX_SO_SNDBUF:
! 810: return SO_SNDBUF;
! 811: case LINUX_SO_RCVBUF:
! 812: return SO_RCVBUF;
! 813: case LINUX_SO_KEEPALIVE:
! 814: return SO_KEEPALIVE;
! 815: case LINUX_SO_OOBINLINE:
! 816: return SO_OOBINLINE;
! 817: case LINUX_SO_LINGER:
! 818: return SO_LINGER;
! 819: case LINUX_SO_PRIORITY:
! 820: case LINUX_SO_NO_CHECK:
! 821: default:
! 822: return -1;
! 823: }
! 824: }
! 825:
! 826: /*
! 827: * Convert Linux IP level socket option number to OpenBSD values.
! 828: */
! 829: int
! 830: linux_to_bsd_ip_sockopt(lopt)
! 831: int lopt;
! 832: {
! 833:
! 834: switch (lopt) {
! 835: case LINUX_IP_TOS:
! 836: return IP_TOS;
! 837: case LINUX_IP_TTL:
! 838: return IP_TTL;
! 839: case LINUX_IP_MULTICAST_TTL:
! 840: return IP_MULTICAST_TTL;
! 841: case LINUX_IP_MULTICAST_LOOP:
! 842: return IP_MULTICAST_LOOP;
! 843: case LINUX_IP_MULTICAST_IF:
! 844: return IP_MULTICAST_IF;
! 845: case LINUX_IP_ADD_MEMBERSHIP:
! 846: return IP_ADD_MEMBERSHIP;
! 847: case LINUX_IP_DROP_MEMBERSHIP:
! 848: return IP_DROP_MEMBERSHIP;
! 849: case LINUX_IP_HDRINCL:
! 850: return IP_HDRINCL;
! 851: default:
! 852: return -1;
! 853: }
! 854: }
! 855:
! 856: /*
! 857: * Convert Linux TCP level socket option number to OpenBSD values.
! 858: */
! 859: int
! 860: linux_to_bsd_tcp_sockopt(lopt)
! 861: int lopt;
! 862: {
! 863:
! 864: switch (lopt) {
! 865: case LINUX_TCP_NODELAY:
! 866: return TCP_NODELAY;
! 867: case LINUX_TCP_MAXSEG:
! 868: return TCP_MAXSEG;
! 869: default:
! 870: return -1;
! 871: }
! 872: }
! 873:
! 874: /*
! 875: * Convert Linux UDP level socket option number to OpenBSD values.
! 876: */
! 877: int
! 878: linux_to_bsd_udp_sockopt(lopt)
! 879: int lopt;
! 880: {
! 881:
! 882: switch (lopt) {
! 883: default:
! 884: return -1;
! 885: }
! 886: }
! 887:
! 888: /*
! 889: * Another reasonably straightforward function: setsockopt(2).
! 890: * The level and option numbers are converted; the values passed
! 891: * are not (yet) converted, the ones currently implemented don't
! 892: * need conversion, as they are the same on both systems.
! 893: */
! 894: int
! 895: linux_setsockopt(p, v, retval)
! 896: struct proc *p;
! 897: void *v;
! 898: register_t *retval;
! 899: {
! 900: struct linux_setsockopt_args /* {
! 901: syscallarg(int) s;
! 902: syscallarg(int) level;
! 903: syscallarg(int) optname;
! 904: syscallarg(void *) optval;
! 905: syscallarg(int) optlen;
! 906: } */ *uap = v;
! 907: struct linux_setsockopt_args lsa;
! 908: struct sys_setsockopt_args bsa;
! 909: int error, name;
! 910:
! 911: if ((error = copyin((caddr_t) uap, (caddr_t) &lsa, sizeof lsa)))
! 912: return error;
! 913:
! 914: SCARG(&bsa, s) = lsa.s;
! 915: SCARG(&bsa, level) = linux_to_bsd_sopt_level(lsa.level);
! 916: SCARG(&bsa, val) = lsa.optval;
! 917: SCARG(&bsa, valsize) = lsa.optlen;
! 918:
! 919: switch (SCARG(&bsa, level)) {
! 920: case SOL_SOCKET:
! 921: name = linux_to_bsd_so_sockopt(lsa.optname);
! 922: break;
! 923: case IPPROTO_IP:
! 924: name = linux_to_bsd_ip_sockopt(lsa.optname);
! 925: break;
! 926: case IPPROTO_TCP:
! 927: name = linux_to_bsd_tcp_sockopt(lsa.optname);
! 928: break;
! 929: case IPPROTO_UDP:
! 930: name = linux_to_bsd_udp_sockopt(lsa.optname);
! 931: break;
! 932: default:
! 933: return EINVAL;
! 934: }
! 935:
! 936: if (name == -1)
! 937: return EINVAL;
! 938: SCARG(&bsa, name) = name;
! 939:
! 940: return sys_setsockopt(p, &bsa, retval);
! 941: }
! 942:
! 943: /*
! 944: * getsockopt(2) is very much the same as setsockopt(2) (see above)
! 945: */
! 946: int
! 947: linux_getsockopt(p, v, retval)
! 948: struct proc *p;
! 949: void *v;
! 950: register_t *retval;
! 951: {
! 952: struct linux_getsockopt_args /* {
! 953: syscallarg(int) s;
! 954: syscallarg(int) level;
! 955: syscallarg(int) optname;
! 956: syscallarg(void *) optval;
! 957: syscallarg(int) *optlen;
! 958: } */ *uap = v;
! 959: struct linux_getsockopt_args lga;
! 960: struct sys_getsockopt_args bga;
! 961: int error, name;
! 962:
! 963: if ((error = copyin((caddr_t) uap, (caddr_t) &lga, sizeof lga)))
! 964: return error;
! 965:
! 966: SCARG(&bga, s) = lga.s;
! 967: SCARG(&bga, level) = linux_to_bsd_sopt_level(lga.level);
! 968: SCARG(&bga, val) = lga.optval;
! 969: SCARG(&bga, avalsize) = lga.optlen;
! 970:
! 971: switch (SCARG(&bga, level)) {
! 972: case SOL_SOCKET:
! 973: name = linux_to_bsd_so_sockopt(lga.optname);
! 974: break;
! 975: case IPPROTO_IP:
! 976: name = linux_to_bsd_ip_sockopt(lga.optname);
! 977: break;
! 978: case IPPROTO_TCP:
! 979: name = linux_to_bsd_tcp_sockopt(lga.optname);
! 980: break;
! 981: case IPPROTO_UDP:
! 982: name = linux_to_bsd_udp_sockopt(lga.optname);
! 983: break;
! 984: default:
! 985: return EINVAL;
! 986: }
! 987:
! 988: if (name == -1)
! 989: return EINVAL;
! 990: SCARG(&bga, name) = name;
! 991:
! 992: return sys_getsockopt(p, &bga, retval);
! 993: }
! 994:
! 995: int
! 996: linux_recvmsg(p, v, retval)
! 997: struct proc *p;
! 998: void *v;
! 999: register_t *retval;
! 1000: {
! 1001: struct linux_recvmsg_args /* {
! 1002: syscallarg(int) s;
! 1003: syscallarg(caddr_t) msg;
! 1004: syscallarg(int) flags;
! 1005: } */ *uap = v;
! 1006: struct linux_recvmsg_args lla;
! 1007: struct sys_recvmsg_args bla;
! 1008: struct msghdr msg;
! 1009: int error;
! 1010:
! 1011: if ((error = copyin((caddr_t) uap, (caddr_t) &lla, sizeof lla)))
! 1012: return error;
! 1013:
! 1014: SCARG(&bla, s) = lla.s;
! 1015: SCARG(&bla, msg) = (struct msghdr *)lla.msg;
! 1016: SCARG(&bla, flags) = lla.flags;
! 1017:
! 1018: error = sys_recvmsg(p, &bla, retval);
! 1019: if (error)
! 1020: return (error);
! 1021:
! 1022: error = copyin(lla.msg, (caddr_t)&msg, sizeof(msg));
! 1023:
! 1024: if (!error && msg.msg_name && msg.msg_namelen > 2)
! 1025: error = linux_sa_put(msg.msg_name);
! 1026:
! 1027: return (error);
! 1028: }
! 1029:
! 1030: int
! 1031: linux_sendmsg(p, v, retval)
! 1032: struct proc *p;
! 1033: void *v;
! 1034: register_t *retval;
! 1035: {
! 1036: struct linux_sendmsg_args /* {
! 1037: syscallarg(int) s;
! 1038: syscallarg(struct msghdr *) msg;
! 1039: syscallarg(int) flags;
! 1040: } */ *uap = v;
! 1041: struct linux_sendmsg_args lla;
! 1042: struct sys_sendmsg_args bla;
! 1043: struct msghdr msg, *nmsg = NULL;
! 1044: int error;
! 1045: caddr_t control;
! 1046: int level;
! 1047:
! 1048: if ((error = copyin((caddr_t) uap, (caddr_t) &lla, sizeof lla)))
! 1049: return error;
! 1050:
! 1051: if ((error = copyin(lla.msg, (caddr_t) &msg, sizeof(msg))))
! 1052: return (error);
! 1053:
! 1054: if (msg.msg_name) {
! 1055: struct sockaddr *sa;
! 1056: caddr_t sg = stackgap_init(p->p_emul);
! 1057:
! 1058: nmsg = (struct msghdr *)stackgap_alloc(&sg,
! 1059: sizeof(struct msghdr));
! 1060: if (!nmsg)
! 1061: return (ENOMEM);
! 1062:
! 1063: error = linux_sa_get(p, &sg, &sa,
! 1064: (struct osockaddr *)msg.msg_name, &msg.msg_namelen);
! 1065: if (error)
! 1066: return (error);
! 1067:
! 1068: msg.msg_name = (struct sockaddr *)sa;
! 1069: if ((error = copyout(&msg, nmsg, sizeof(struct msghdr))))
! 1070: return (error);
! 1071: lla.msg = nmsg;
! 1072: }
! 1073:
! 1074: SCARG(&bla, s) = lla.s;
! 1075: SCARG(&bla, msg) = lla.msg;
! 1076: SCARG(&bla, flags) = lla.flags;
! 1077:
! 1078: error = copyin(lla.msg->msg_control, &control, sizeof(caddr_t));
! 1079: if (error)
! 1080: return error;
! 1081: if (control == NULL)
! 1082: goto done;
! 1083: error = copyin(&((struct cmsghdr *)control)->cmsg_level,
! 1084: &level, sizeof(int));
! 1085: if (error)
! 1086: return error;
! 1087: if (level == 1) {
! 1088: /*
! 1089: * Linux thinks that SOL_SOCKET is 1; we know that it's really
! 1090: * 0xffff, of course.
! 1091: */
! 1092: level = SOL_SOCKET;
! 1093: /*
! 1094: * XXX should use stack gap!
! 1095: * We don't because the control header is variable length
! 1096: * up to 2048 bytes, and there's only 512 bytes of gap.
! 1097: */
! 1098: error = copyout(&level, &((struct cmsghdr *)control)->
! 1099: cmsg_level, sizeof(int));
! 1100: if (error)
! 1101: return error;
! 1102: }
! 1103: done:
! 1104: error = sys_sendmsg(p, &bla, retval);
! 1105: /* replace level, just in case somebody cares. */
! 1106: if (level == SOL_SOCKET) {
! 1107: level = 1;
! 1108: /* don't worry about the error */
! 1109: copyout(&level, &((struct cmsghdr *)control)->cmsg_level,
! 1110: sizeof(int));
! 1111: }
! 1112: return (error);
! 1113: }
! 1114:
! 1115: /*
! 1116: * Copy the osockaddr structure pointed to by osa to kernel, adjust
! 1117: * family and convert to sockaddr, allocate stackgap and put the
! 1118: * the converted structure there, address on stackgap returned in sap.
! 1119: */
! 1120: int
! 1121: linux_sa_get(p, sgp, sap, osa, osalen)
! 1122: struct proc *p;
! 1123: caddr_t *sgp;
! 1124: struct sockaddr **sap;
! 1125: const struct osockaddr *osa;
! 1126: int *osalen;
! 1127: {
! 1128: int error=0, bdom;
! 1129: struct sockaddr *sa, *usa;
! 1130: struct osockaddr *kosa;
! 1131: int alloclen;
! 1132: #ifdef INET6
! 1133: int oldv6size;
! 1134: struct sockaddr_in6 *sin6;
! 1135: #endif
! 1136:
! 1137: if (*osalen < 2 || *osalen > UCHAR_MAX || !osa) {
! 1138: return (EINVAL);
! 1139: }
! 1140:
! 1141: alloclen = *osalen;
! 1142: #ifdef INET6
! 1143: oldv6size = 0;
! 1144: /*
! 1145: * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
! 1146: * if it's a v4-mapped address, so reserve the proper space
! 1147: * for it.
! 1148: */
! 1149: if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
! 1150: alloclen = sizeof (struct sockaddr_in6);
! 1151: oldv6size = 1;
! 1152: }
! 1153: #endif
! 1154:
! 1155: kosa = (struct osockaddr *) malloc(alloclen, M_TEMP, M_WAITOK);
! 1156:
! 1157: if ((error = copyin(osa, (caddr_t) kosa, *osalen))) {
! 1158: goto out;
! 1159: }
! 1160:
! 1161: bdom = linux_to_bsd_domain(kosa->sa_family);
! 1162: if (bdom == -1) {
! 1163: error = EINVAL;
! 1164: goto out;
! 1165: }
! 1166:
! 1167: #ifdef INET6
! 1168: /*
! 1169: * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
! 1170: * which lacks the scope id compared with RFC2553 one. If we detect
! 1171: * the situation, reject the address.
! 1172: *
! 1173: * Still accept addresses for which the scope id is not used.
! 1174: */
! 1175: if (oldv6size && bdom == AF_INET6) {
! 1176: sin6 = (struct sockaddr_in6 *)kosa;
! 1177: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
! 1178: (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
! 1179: !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
! 1180: !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
! 1181: !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
! 1182: !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
! 1183: sin6->sin6_scope_id = 0;
! 1184: } else {
! 1185: error = EINVAL;
! 1186: goto out;
! 1187: }
! 1188: } else
! 1189: #endif
! 1190: if (bdom == AF_INET) {
! 1191: alloclen = sizeof(struct sockaddr_in);
! 1192: }
! 1193:
! 1194: sa = (struct sockaddr *) kosa;
! 1195: sa->sa_family = bdom;
! 1196: sa->sa_len = alloclen;
! 1197:
! 1198: usa = (struct sockaddr *) stackgap_alloc(sgp, alloclen);
! 1199: if (!usa) {
! 1200: error = ENOMEM;
! 1201: goto out;
! 1202: }
! 1203:
! 1204: if ((error = copyout(sa, usa, alloclen))) {
! 1205: goto out;
! 1206: }
! 1207:
! 1208: *sap = usa;
! 1209:
! 1210: out:
! 1211: *osalen = alloclen;
! 1212: free(kosa, M_TEMP);
! 1213: return (error);
! 1214: }
! 1215:
! 1216: int
! 1217: linux_sa_put(osa)
! 1218: struct osockaddr *osa;
! 1219: {
! 1220: struct sockaddr sa;
! 1221: struct osockaddr *kosa;
! 1222: int error, bdom, len;
! 1223:
! 1224: /*
! 1225: * Only read/write the sockaddr family and length part, the rest is
! 1226: * not changed.
! 1227: */
! 1228: len = sizeof(sa.sa_len) + sizeof(sa.sa_family);
! 1229:
! 1230: error = copyin((caddr_t) osa, (caddr_t) &sa, len);
! 1231: if (error)
! 1232: return (error);
! 1233:
! 1234: bdom = bsd_to_linux_domain(sa.sa_family);
! 1235: if (bdom == -1)
! 1236: return (EINVAL);
! 1237:
! 1238: /* Note: we convert from sockaddr to osockaddr here, too */
! 1239: kosa = (struct osockaddr *) &sa;
! 1240: kosa->sa_family = bdom;
! 1241: error = copyout(kosa, osa, len);
! 1242: if (error)
! 1243: return (error);
! 1244:
! 1245: return (0);
! 1246: }
! 1247:
! 1248: /*
! 1249: * Entry point to all Linux socket calls. Just check which call to
! 1250: * make and take appropriate action.
! 1251: */
! 1252: int
! 1253: linux_sys_socketcall(p, v, retval)
! 1254: struct proc *p;
! 1255: void *v;
! 1256: register_t *retval;
! 1257: {
! 1258: struct linux_sys_socketcall_args /* {
! 1259: syscallarg(int) what;
! 1260: syscallarg(void *) args;
! 1261: } */ *uap = v;
! 1262:
! 1263: switch (SCARG(uap, what)) {
! 1264: case LINUX_SYS_socket:
! 1265: return linux_socket(p, SCARG(uap, args), retval);
! 1266: case LINUX_SYS_bind:
! 1267: return linux_bind(p, SCARG(uap, args), retval);
! 1268: case LINUX_SYS_connect:
! 1269: return linux_connect(p, SCARG(uap, args), retval);
! 1270: case LINUX_SYS_listen:
! 1271: return linux_listen(p, SCARG(uap, args), retval);
! 1272: case LINUX_SYS_accept:
! 1273: return linux_accept(p, SCARG(uap, args), retval);
! 1274: case LINUX_SYS_getsockname:
! 1275: return linux_getsockname(p, SCARG(uap, args), retval);
! 1276: case LINUX_SYS_getpeername:
! 1277: return linux_getpeername(p, SCARG(uap, args), retval);
! 1278: case LINUX_SYS_socketpair:
! 1279: return linux_socketpair(p, SCARG(uap, args), retval);
! 1280: case LINUX_SYS_send:
! 1281: return linux_send(p, SCARG(uap, args), retval);
! 1282: case LINUX_SYS_recv:
! 1283: return linux_recv(p, SCARG(uap, args), retval);
! 1284: case LINUX_SYS_sendto:
! 1285: return linux_sendto(p, SCARG(uap, args), retval);
! 1286: case LINUX_SYS_recvfrom:
! 1287: return linux_recvfrom(p, SCARG(uap, args), retval);
! 1288: case LINUX_SYS_shutdown:
! 1289: return linux_shutdown(p, SCARG(uap, args), retval);
! 1290: case LINUX_SYS_setsockopt:
! 1291: return linux_setsockopt(p, SCARG(uap, args), retval);
! 1292: case LINUX_SYS_getsockopt:
! 1293: return linux_getsockopt(p, SCARG(uap, args), retval);
! 1294: case LINUX_SYS_sendmsg:
! 1295: return linux_sendmsg(p, SCARG(uap, args), retval);
! 1296: case LINUX_SYS_recvmsg:
! 1297: return linux_recvmsg(p, SCARG(uap, args), retval);
! 1298: default:
! 1299: return ENOSYS;
! 1300: }
! 1301: }
! 1302:
! 1303: int
! 1304: linux_ioctl_socket(p, v, retval)
! 1305: register struct proc *p;
! 1306: void *v;
! 1307: register_t *retval;
! 1308: {
! 1309: struct linux_sys_ioctl_args /* {
! 1310: syscallarg(int) fd;
! 1311: syscallarg(u_long) com;
! 1312: syscallarg(caddr_t) data;
! 1313: } */ *uap = v;
! 1314: u_long com;
! 1315: struct sys_ioctl_args ia;
! 1316: struct file *fp;
! 1317: struct filedesc *fdp;
! 1318: struct vnode *vp;
! 1319: int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
! 1320: struct ioctl_pt pt;
! 1321: int error = 0, isdev = 0, dosys = 1;
! 1322:
! 1323: fdp = p->p_fd;
! 1324: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
! 1325: return (EBADF);
! 1326: FREF(fp);
! 1327:
! 1328: if (fp->f_type == DTYPE_VNODE) {
! 1329: vp = (struct vnode *)fp->f_data;
! 1330: isdev = vp->v_type == VCHR;
! 1331: }
! 1332:
! 1333: /*
! 1334: * Don't try to interpret socket ioctl calls that are done
! 1335: * on a device filedescriptor, just pass them through, to
! 1336: * emulate Linux behaviour. Use PTIOCLINUX so that the
! 1337: * device will only handle these if it's prepared to do
! 1338: * so, to avoid unexpected things from happening.
! 1339: */
! 1340: if (isdev) {
! 1341: dosys = 0;
! 1342: ioctlf = fp->f_ops->fo_ioctl;
! 1343: pt.com = SCARG(uap, com);
! 1344: pt.data = SCARG(uap, data);
! 1345: error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
! 1346: /*
! 1347: * XXX hack: if the function returns EJUSTRETURN,
! 1348: * it has stuffed a sysctl return value in pt.data.
! 1349: */
! 1350: if (error == EJUSTRETURN) {
! 1351: retval[0] = (register_t)pt.data;
! 1352: error = 0;
! 1353: }
! 1354: goto out;
! 1355: }
! 1356:
! 1357: com = SCARG(uap, com);
! 1358: retval[0] = 0;
! 1359:
! 1360: switch (com) {
! 1361: case LINUX_FIOSETOWN:
! 1362: SCARG(&ia, com) = FIOSETOWN;
! 1363: break;
! 1364: case LINUX_SIOCSPGRP:
! 1365: SCARG(&ia, com) = SIOCSPGRP;
! 1366: break;
! 1367: case LINUX_FIOGETOWN:
! 1368: SCARG(&ia, com) = FIOGETOWN;
! 1369: break;
! 1370: case LINUX_SIOCGPGRP:
! 1371: SCARG(&ia, com) = SIOCGPGRP;
! 1372: break;
! 1373: case LINUX_SIOCATMARK:
! 1374: SCARG(&ia, com) = SIOCATMARK;
! 1375: break;
! 1376: #if 0
! 1377: case LINUX_SIOCGSTAMP:
! 1378: SCARG(&ia, com) = SIOCGSTAMP;
! 1379: break;
! 1380: #endif
! 1381: case LINUX_SIOCGIFCONF:
! 1382: SCARG(&ia, com) = OSIOCGIFCONF;
! 1383: break;
! 1384: case LINUX_SIOCGIFFLAGS:
! 1385: SCARG(&ia, com) = SIOCGIFFLAGS;
! 1386: break;
! 1387: case LINUX_SIOCGIFADDR:
! 1388: SCARG(&ia, com) = OSIOCGIFADDR;
! 1389: break;
! 1390: case LINUX_SIOCGIFDSTADDR:
! 1391: SCARG(&ia, com) = OSIOCGIFDSTADDR;
! 1392: break;
! 1393: case LINUX_SIOCGIFBRDADDR:
! 1394: SCARG(&ia, com) = OSIOCGIFBRDADDR;
! 1395: break;
! 1396: case LINUX_SIOCGIFNETMASK:
! 1397: SCARG(&ia, com) = OSIOCGIFNETMASK;
! 1398: break;
! 1399: case LINUX_SIOCGIFMETRIC:
! 1400: SCARG(&ia, com) = SIOCGIFMETRIC;
! 1401: break;
! 1402: case LINUX_SIOCGIFMTU:
! 1403: SCARG(&ia, com) = SIOCGIFMTU;
! 1404: break;
! 1405: case LINUX_SIOCADDMULTI:
! 1406: SCARG(&ia, com) = SIOCADDMULTI;
! 1407: break;
! 1408: case LINUX_SIOCDELMULTI:
! 1409: SCARG(&ia, com) = SIOCDELMULTI;
! 1410: break;
! 1411: case LINUX_SIOCGIFHWADDR: {
! 1412: struct linux_ifreq *ifr = (struct linux_ifreq *)SCARG(uap, data);
! 1413: struct sockaddr_dl *sdl;
! 1414: struct ifnet *ifp;
! 1415: struct ifaddr *ifa;
! 1416:
! 1417: /*
! 1418: * Note that we don't actually respect the name in the ifreq
! 1419: * structure, as Linux interface names are all different.
! 1420: */
! 1421: TAILQ_FOREACH(ifp, &ifnet, if_list) {
! 1422: if (ifp->if_type != IFT_ETHER)
! 1423: continue;
! 1424: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 1425: if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
! 1426: (sdl->sdl_family == AF_LINK) &&
! 1427: (sdl->sdl_type == IFT_ETHER)) {
! 1428: error = copyout(LLADDR(sdl),
! 1429: (caddr_t)&ifr->ifr_hwaddr.sa_data,
! 1430: LINUX_IFHWADDRLEN);
! 1431: dosys = 0;
! 1432: goto out;
! 1433: }
! 1434: }
! 1435: }
! 1436: error = ENOENT;
! 1437: break;
! 1438: }
! 1439: default:
! 1440: error = EINVAL;
! 1441: }
! 1442:
! 1443: out:
! 1444: if (error == 0 && dosys) {
! 1445: SCARG(&ia, fd) = SCARG(uap, fd);
! 1446: SCARG(&ia, data) = SCARG(uap, data);
! 1447: error = sys_ioctl(p, &ia, retval);
! 1448: }
! 1449:
! 1450: FRELE(fp);
! 1451: return (error);
! 1452: }
CVSweb