1 /* $NetBSD: linux32_socket.c,v 1.10 2008/11/19 18:36:04 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.10 2008/11/19 18:36:04 ad Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/fstypes.h> 41 #include <sys/signal.h> 42 #include <sys/dirent.h> 43 #include <sys/kernel.h> 44 #include <sys/fcntl.h> 45 #include <sys/select.h> 46 #include <sys/proc.h> 47 #include <sys/ucred.h> 48 #include <sys/swap.h> 49 #include <sys/file.h> 50 #include <sys/vnode.h> 51 #include <sys/filedesc.h> 52 53 #include <machine/types.h> 54 55 #include <net/if.h> 56 #include <net/if_dl.h> 57 #include <net/if_types.h> 58 #include <net/route.h> 59 60 #include <netinet/in.h> 61 #include <netinet/ip_mroute.h> 62 63 #include <sys/syscallargs.h> 64 65 #include <compat/netbsd32/netbsd32.h> 66 #include <compat/netbsd32/netbsd32_ioctl.h> 67 #include <compat/netbsd32/netbsd32_conv.h> 68 #include <compat/netbsd32/netbsd32_syscallargs.h> 69 70 #include <compat/sys/socket.h> 71 #include <compat/sys/sockio.h> 72 73 #include <compat/linux/common/linux_types.h> 74 #include <compat/linux/common/linux_types.h> 75 #include <compat/linux/common/linux_signal.h> 76 #include <compat/linux/common/linux_machdep.h> 77 #include <compat/linux/common/linux_misc.h> 78 #include <compat/linux/common/linux_oldolduname.h> 79 #include <compat/linux/common/linux_ioctl.h> 80 #include <compat/linux/common/linux_sockio.h> 81 #include <compat/linux/common/linux_ipc.h> 82 #include <compat/linux/common/linux_sem.h> 83 #include <compat/linux/linux_syscallargs.h> 84 85 #include <compat/linux32/common/linux32_types.h> 86 #include <compat/linux32/common/linux32_signal.h> 87 #include <compat/linux32/common/linux32_machdep.h> 88 #include <compat/linux32/common/linux32_sysctl.h> 89 #include <compat/linux32/common/linux32_socketcall.h> 90 #include <compat/linux32/common/linux32_sockio.h> 91 #include <compat/linux32/common/linux32_ioctl.h> 92 #include <compat/linux32/linux32_syscallargs.h> 93 94 int linux32_getifconf(struct lwp *, register_t *, void *); 95 int linux32_getifhwaddr(struct lwp *, register_t *, u_int, void *); 96 97 int 98 linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval) 99 { 100 /* { 101 syscallarg(int) domain; 102 syscallarg(int) type; 103 syscallarg(int) protocol; 104 syscallarg(netbsd32_intp) rsv; 105 } */ 106 struct linux_sys_socketpair_args ua; 107 108 NETBSD32TO64_UAP(domain); 109 NETBSD32TO64_UAP(type); 110 NETBSD32TO64_UAP(protocol); 111 NETBSD32TOP_UAP(rsv, int) 112 113 return linux_sys_socketpair(l, &ua, retval); 114 } 115 116 int 117 linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval) 118 { 119 /* { 120 syscallarg(int) s; 121 syscallarg(netbsd32_voidp) msg; 122 syscallarg(int) len; 123 syscallarg(int) flags; 124 syscallarg(netbsd32_osockaddrp_t) to; 125 syscallarg(int) tolen; 126 } */ 127 struct linux_sys_sendto_args ua; 128 129 NETBSD32TO64_UAP(s); 130 NETBSD32TOP_UAP(msg, void); 131 NETBSD32TO64_UAP(len); 132 NETBSD32TO64_UAP(flags); 133 NETBSD32TOP_UAP(to, struct osockaddr); 134 NETBSD32TO64_UAP(tolen); 135 136 return linux_sys_sendto(l, &ua, retval); 137 } 138 139 140 int 141 linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval) 142 { 143 /* { 144 syscallarg(int) s; 145 syscallarg(netbsd32_voidp) buf; 146 syscallarg(netbsd32_size_t) len; 147 syscallarg(int) flags; 148 syscallarg(netbsd32_osockaddrp_t) from; 149 syscallarg(netbsd32_intp) fromlenaddr; 150 } */ 151 struct linux_sys_recvfrom_args ua; 152 153 NETBSD32TO64_UAP(s); 154 NETBSD32TOP_UAP(buf, void); 155 NETBSD32TO64_UAP(len); 156 NETBSD32TO64_UAP(flags); 157 NETBSD32TOP_UAP(from, struct osockaddr); 158 NETBSD32TOP_UAP(fromlenaddr, unsigned int); 159 160 return linux_sys_recvfrom(l, &ua, retval); 161 } 162 163 int 164 linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval) 165 { 166 /* { 167 syscallarg(int) s; 168 syscallarg(int) level; 169 syscallarg(int) optname; 170 syscallarg(netbsd32_voidp) optval; 171 syscallarg(int) optlen; 172 } */ 173 struct linux_sys_setsockopt_args ua; 174 175 NETBSD32TO64_UAP(s); 176 NETBSD32TO64_UAP(level); 177 NETBSD32TO64_UAP(optname); 178 NETBSD32TOP_UAP(optval, void); 179 NETBSD32TO64_UAP(optlen); 180 181 return linux_sys_setsockopt(l, &ua, retval); 182 } 183 184 185 int 186 linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval) 187 { 188 /* { 189 syscallarg(int) s; 190 syscallarg(int) level; 191 syscallarg(int) optname; 192 syscallarg(netbsd32_voidp) optval; 193 syscallarg(netbsd32_intp) optlen; 194 } */ 195 struct linux_sys_getsockopt_args ua; 196 197 NETBSD32TO64_UAP(s); 198 NETBSD32TO64_UAP(level); 199 NETBSD32TO64_UAP(optname); 200 NETBSD32TOP_UAP(optval, void); 201 NETBSD32TOP_UAP(optlen, int); 202 203 return linux_sys_getsockopt(l, &ua, retval); 204 } 205 206 int 207 linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval) 208 { 209 /* { 210 syscallarg(int) domain; 211 syscallarg(int) type; 212 syscallarg(int) protocol; 213 } */ 214 struct linux_sys_socket_args ua; 215 216 NETBSD32TO64_UAP(domain); 217 NETBSD32TO64_UAP(type); 218 NETBSD32TO64_UAP(protocol); 219 220 return linux_sys_socket(l, &ua, retval); 221 } 222 223 int 224 linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval) 225 { 226 /* { 227 syscallarg(int) s; 228 syscallarg(netbsd32_osockaddrp_t) name; 229 syscallarg(int) namelen; 230 } */ 231 struct linux_sys_bind_args ua; 232 233 NETBSD32TO64_UAP(s); 234 NETBSD32TOP_UAP(name, struct osockaddr) 235 NETBSD32TO64_UAP(namelen); 236 237 return linux_sys_bind(l, &ua, retval); 238 } 239 240 int 241 linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval) 242 { 243 /* { 244 syscallarg(int) s; 245 syscallarg(netbsd32_osockaddrp_t) name; 246 syscallarg(int) namelen; 247 } */ 248 struct linux_sys_connect_args ua; 249 250 NETBSD32TO64_UAP(s); 251 NETBSD32TOP_UAP(name, struct osockaddr) 252 NETBSD32TO64_UAP(namelen); 253 254 #ifdef DEBUG_LINUX 255 printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n", 256 SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen)); 257 #endif 258 259 return linux_sys_connect(l, &ua, retval); 260 } 261 262 int 263 linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval) 264 { 265 /* { 266 syscallarg(int) s; 267 syscallarg(netbsd32_osockaddrp_t) name; 268 syscallarg(netbsd32_intp) anamelen; 269 } */ 270 struct linux_sys_accept_args ua; 271 272 NETBSD32TO64_UAP(s); 273 NETBSD32TOP_UAP(name, struct osockaddr) 274 NETBSD32TOP_UAP(anamelen, int); 275 276 return linux_sys_accept(l, &ua, retval); 277 } 278 279 int 280 linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval) 281 { 282 /* { 283 syscallarg(int) fdes; 284 syscallarg(netbsd32_sockaddrp_t) asa; 285 syscallarg(netbsd32_intp) alen; 286 } */ 287 struct linux_sys_getpeername_args ua; 288 289 NETBSD32TO64_UAP(fdes); 290 NETBSD32TOP_UAP(asa, struct sockaddr) 291 NETBSD32TOP_UAP(alen, int); 292 293 return linux_sys_getpeername(l, &ua, retval); 294 } 295 296 int 297 linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval) 298 { 299 /* { 300 syscallarg(int) fdec; 301 syscallarg(netbsd32_charp) asa; 302 syscallarg(netbsd32_intp) alen; 303 } */ 304 struct linux_sys_getsockname_args ua; 305 306 NETBSD32TO64_UAP(fdec); 307 NETBSD32TOP_UAP(asa, char) 308 NETBSD32TOP_UAP(alen, int); 309 310 return linux_sys_getsockname(l, &ua, retval); 311 } 312 313 int 314 linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval) 315 { 316 /* { 317 syscallarg(int) s; 318 syscallarg(netbsd32_msghdrp_t) msg; 319 syscallarg(int) flags; 320 } */ 321 struct linux_sys_sendmsg_args ua; 322 323 NETBSD32TO64_UAP(s); 324 NETBSD32TOP_UAP(msg, struct msghdr); 325 NETBSD32TO64_UAP(flags); 326 327 return linux_sys_sendmsg(l, &ua, retval); 328 } 329 330 int 331 linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval) 332 { 333 /* { 334 syscallarg(int) s; 335 syscallarg(netbsd32_msghdrp_t) msg; 336 syscallarg(int) flags; 337 } */ 338 struct linux_sys_recvmsg_args ua; 339 340 NETBSD32TO64_UAP(s); 341 NETBSD32TOP_UAP(msg, struct msghdr); 342 NETBSD32TO64_UAP(flags); 343 344 return linux_sys_recvmsg(l, &ua, retval); 345 } 346 347 int 348 linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval) 349 { 350 /* { 351 syscallarg(int) s; 352 syscallarg(netbsd32_voidp) buf; 353 syscallarg(int) len; 354 syscallarg(int) flags; 355 } */ 356 struct sys_sendto_args ua; 357 358 NETBSD32TO64_UAP(s); 359 NETBSD32TOP_UAP(buf, void); 360 NETBSD32TO64_UAP(len); 361 NETBSD32TO64_UAP(flags); 362 SCARG(&ua, to) = NULL; 363 SCARG(&ua, tolen) = 0; 364 365 return sys_sendto(l, &ua, retval); 366 } 367 368 int 369 linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval) 370 { 371 /* { 372 syscallarg(int) s; 373 syscallarg(netbsd32_voidp) buf; 374 syscallarg(int) len; 375 syscallarg(int) flags; 376 } */ 377 struct sys_recvfrom_args ua; 378 379 NETBSD32TO64_UAP(s); 380 NETBSD32TOP_UAP(buf, void); 381 NETBSD32TO64_UAP(len); 382 NETBSD32TO64_UAP(flags); 383 SCARG(&ua, from) = NULL; 384 SCARG(&ua, fromlenaddr) = NULL; 385 386 return sys_recvfrom(l, &ua, retval); 387 } 388 389 int 390 linux32_getifconf(struct lwp *l, register_t *retval, void *data) 391 { 392 struct linux32_ifreq ifr, *ifrp; 393 struct netbsd32_ifconf *ifc = data; 394 struct ifnet *ifp; 395 struct ifaddr *ifa; 396 struct sockaddr *sa; 397 struct osockaddr *osa; 398 int space, error = 0; 399 const int sz = (int)sizeof(ifr); 400 401 ifrp = (struct linux32_ifreq *)NETBSD32PTR64(ifc->ifc_req); 402 if (ifrp == NULL) 403 space = 0; 404 else 405 space = ifc->ifc_len; 406 407 IFNET_FOREACH(ifp) { 408 (void)strncpy(ifr.ifr_name, ifp->if_xname, 409 sizeof(ifr.ifr_name)); 410 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') 411 return ENAMETOOLONG; 412 if (IFADDR_EMPTY(ifp)) 413 continue; 414 IFADDR_FOREACH(ifa, ifp) { 415 sa = ifa->ifa_addr; 416 if (sa->sa_family != AF_INET || 417 sa->sa_len > sizeof(*osa)) 418 continue; 419 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 420 osa = (struct osockaddr *)&ifr.ifr_addr; 421 osa->sa_family = sa->sa_family; 422 if (space >= sz) { 423 error = copyout(&ifr, ifrp, sz); 424 if (error != 0) 425 return error; 426 ifrp++; 427 } 428 space -= sz; 429 } 430 } 431 432 if (ifrp != NULL) 433 ifc->ifc_len -= space; 434 else 435 ifc->ifc_len = -space; 436 437 return 0; 438 } 439 440 int 441 linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, 442 void *data) 443 { 444 struct linux32_ifreq lreq; 445 file_t *fp; 446 struct ifaddr *ifa; 447 struct ifnet *ifp; 448 struct sockaddr_dl *sadl; 449 int error, found; 450 int index, ifnum; 451 452 /* 453 * We can't emulate this ioctl by calling sys_ioctl() to run 454 * SIOCGIFCONF, because the user buffer is not of the right 455 * type to take those results. We can't use kernel buffers to 456 * receive the results, as the implementation of sys_ioctl() 457 * and ifconf() [which implements SIOCGIFCONF] use 458 * copyin()/copyout() which will fail on kernel addresses. 459 * 460 * So, we must duplicate code from sys_ioctl() and ifconf(). Ugh. 461 */ 462 463 if ((fp = fd_getfile(fd)) == NULL) 464 return (EBADF); 465 466 KERNEL_LOCK(1, NULL); 467 468 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 469 error = EBADF; 470 goto out; 471 } 472 473 error = copyin(data, &lreq, sizeof(lreq)); 474 if (error) 475 goto out; 476 lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0'; /* just in case */ 477 478 /* 479 * Try real interface name first, then fake "ethX" 480 */ 481 found = 0; 482 IFNET_FOREACH(ifp) { 483 if (found) 484 break; 485 if (strcmp(lreq.ifr_name, ifp->if_xname)) 486 /* not this interface */ 487 continue; 488 found=1; 489 if (IFADDR_EMPTY(ifp)) { 490 error = ENODEV; 491 goto out; 492 } 493 IFADDR_FOREACH(ifa, ifp) { 494 sadl = satosdl(ifa->ifa_addr); 495 /* only return ethernet addresses */ 496 /* XXX what about FDDI, etc. ? */ 497 if (sadl->sdl_family != AF_LINK || 498 sadl->sdl_type != IFT_ETHER) 499 continue; 500 memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), 501 MIN(sadl->sdl_alen, 502 sizeof(lreq.ifr_hwaddr.sa_data))); 503 lreq.ifr_hwaddr.sa_family = 504 sadl->sdl_family; 505 error = copyout(&lreq, data, sizeof(lreq)); 506 goto out; 507 } 508 } 509 510 if (strncmp(lreq.ifr_name, "eth", 3) == 0) { 511 for (ifnum = 0, index = 3; 512 lreq.ifr_name[index] != '\0' && index < LINUX32_IFNAMSIZ; 513 index++) { 514 ifnum *= 10; 515 ifnum += lreq.ifr_name[index] - '0'; 516 } 517 518 error = EINVAL; /* in case we don't find one */ 519 found = 0; 520 IFNET_FOREACH(ifp) { 521 if (found) 522 break; 523 memcpy(lreq.ifr_name, ifp->if_xname, 524 MIN(LINUX32_IFNAMSIZ, IFNAMSIZ)); 525 IFADDR_FOREACH(ifa, ifp) { 526 sadl = satosdl(ifa->ifa_addr); 527 /* only return ethernet addresses */ 528 /* XXX what about FDDI, etc. ? */ 529 if (sadl->sdl_family != AF_LINK || 530 sadl->sdl_type != IFT_ETHER) 531 continue; 532 if (ifnum--) 533 /* not the reqested iface */ 534 continue; 535 memcpy(&lreq.ifr_hwaddr.sa_data, 536 CLLADDR(sadl), 537 MIN(sadl->sdl_alen, 538 sizeof(lreq.ifr_hwaddr.sa_data))); 539 lreq.ifr_hwaddr.sa_family = 540 sadl->sdl_family; 541 error = copyout(&lreq, data, sizeof(lreq)); 542 found = 1; 543 break; 544 } 545 } 546 } else { 547 /* unknown interface, not even an "eth*" name */ 548 error = ENODEV; 549 } 550 551 out: 552 KERNEL_UNLOCK_ONE(NULL); 553 fd_putfile(fd); 554 return error; 555 } 556 557 int 558 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) 559 { 560 /* { 561 syscallarg(int) fd; 562 syscallarg(u_long) com; 563 syscallarg(void *) data; 564 } */ 565 u_long com; 566 int error = 0, isdev = 0, dosys = 1; 567 struct netbsd32_ioctl_args ia; 568 file_t *fp; 569 struct vnode *vp; 570 int (*ioctlf)(file_t *, u_long, void *); 571 struct ioctl_pt pt; 572 573 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 574 return (EBADF); 575 576 if (fp->f_type == DTYPE_VNODE) { 577 vp = (struct vnode *)fp->f_data; 578 isdev = vp->v_type == VCHR; 579 } 580 581 /* 582 * Don't try to interpret socket ioctl calls that are done 583 * on a device filedescriptor, just pass them through, to 584 * emulate Linux behaviour. Use PTIOCLINUX so that the 585 * device will only handle these if it's prepared to do 586 * so, to avoid unexpected things from happening. 587 */ 588 if (isdev) { 589 dosys = 0; 590 ioctlf = fp->f_ops->fo_ioctl; 591 pt.com = SCARG(uap, com); 592 pt.data = (void *)NETBSD32PTR64(SCARG(uap, data)); 593 error = ioctlf(fp, PTIOCLINUX, &pt); 594 /* 595 * XXX hack: if the function returns EJUSTRETURN, 596 * it has stuffed a sysctl return value in pt.data. 597 */ 598 if (error == EJUSTRETURN) { 599 retval[0] = (register_t)pt.data; 600 error = 0; 601 } 602 goto out; 603 } 604 605 com = SCARG(uap, com); 606 retval[0] = 0; 607 608 switch (com) { 609 case LINUX_SIOCGIFCONF: 610 error = linux32_getifconf(l, retval, SCARG_P32(uap, data)); 611 dosys = 0; 612 break; 613 case LINUX_SIOCGIFFLAGS: 614 SCARG(&ia, com) = OSIOCGIFFLAGS; 615 break; 616 case LINUX_SIOCSIFFLAGS: 617 SCARG(&ia, com) = OSIOCSIFFLAGS; 618 break; 619 case LINUX_SIOCGIFADDR: 620 SCARG(&ia, com) = OOSIOCGIFADDR; 621 break; 622 case LINUX_SIOCGIFDSTADDR: 623 SCARG(&ia, com) = OOSIOCGIFDSTADDR; 624 break; 625 case LINUX_SIOCGIFBRDADDR: 626 SCARG(&ia, com) = OOSIOCGIFBRDADDR; 627 break; 628 case LINUX_SIOCGIFNETMASK: 629 SCARG(&ia, com) = OOSIOCGIFNETMASK; 630 break; 631 case LINUX_SIOCADDMULTI: 632 SCARG(&ia, com) = OSIOCADDMULTI; 633 break; 634 case LINUX_SIOCDELMULTI: 635 SCARG(&ia, com) = OSIOCDELMULTI; 636 break; 637 case LINUX_SIOCGIFHWADDR: 638 error = linux32_getifhwaddr(l, retval, SCARG(uap, fd), 639 SCARG_P32(uap, data)); 640 dosys = 0; 641 break; 642 default: 643 error = EINVAL; 644 } 645 646 out: 647 fd_putfile(SCARG(uap, fd)); 648 649 if (error == 0 && dosys) { 650 SCARG(&ia, fd) = SCARG(uap, fd); 651 SCARG(&ia, data) = SCARG(uap, data); 652 error = netbsd32_ioctl(curlwp, &ia, retval); 653 } 654 655 return error; 656 } 657