1 /* $NetBSD: linux32_socket.c,v 1.9 2008/07/23 12:32:09 njoly 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.9 2008/07/23 12:32:09 njoly 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/linux_syscallargs.h> 82 83 #include <compat/linux32/common/linux32_types.h> 84 #include <compat/linux32/common/linux32_signal.h> 85 #include <compat/linux32/common/linux32_machdep.h> 86 #include <compat/linux32/common/linux32_sysctl.h> 87 #include <compat/linux32/common/linux32_socketcall.h> 88 #include <compat/linux32/common/linux32_sockio.h> 89 #include <compat/linux32/common/linux32_ioctl.h> 90 #include <compat/linux32/linux32_syscallargs.h> 91 92 int linux32_getifconf(struct lwp *, register_t *, void *); 93 int linux32_getifhwaddr(struct lwp *, register_t *, u_int, void *); 94 95 int 96 linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval) 97 { 98 /* { 99 syscallarg(int) domain; 100 syscallarg(int) type; 101 syscallarg(int) protocol; 102 syscallarg(netbsd32_intp) rsv; 103 } */ 104 struct linux_sys_socketpair_args ua; 105 106 NETBSD32TO64_UAP(domain); 107 NETBSD32TO64_UAP(type); 108 NETBSD32TO64_UAP(protocol); 109 NETBSD32TOP_UAP(rsv, int) 110 111 return linux_sys_socketpair(l, &ua, retval); 112 } 113 114 int 115 linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval) 116 { 117 /* { 118 syscallarg(int) s; 119 syscallarg(netbsd32_voidp) msg; 120 syscallarg(int) len; 121 syscallarg(int) flags; 122 syscallarg(netbsd32_osockaddrp_t) to; 123 syscallarg(int) tolen; 124 } */ 125 struct linux_sys_sendto_args ua; 126 127 NETBSD32TO64_UAP(s); 128 NETBSD32TOP_UAP(msg, void); 129 NETBSD32TO64_UAP(len); 130 NETBSD32TO64_UAP(flags); 131 NETBSD32TOP_UAP(to, struct osockaddr); 132 NETBSD32TO64_UAP(tolen); 133 134 return linux_sys_sendto(l, &ua, retval); 135 } 136 137 138 int 139 linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval) 140 { 141 /* { 142 syscallarg(int) s; 143 syscallarg(netbsd32_voidp) buf; 144 syscallarg(netbsd32_size_t) len; 145 syscallarg(int) flags; 146 syscallarg(netbsd32_osockaddrp_t) from; 147 syscallarg(netbsd32_intp) fromlenaddr; 148 } */ 149 struct linux_sys_recvfrom_args ua; 150 151 NETBSD32TO64_UAP(s); 152 NETBSD32TOP_UAP(buf, void); 153 NETBSD32TO64_UAP(len); 154 NETBSD32TO64_UAP(flags); 155 NETBSD32TOP_UAP(from, struct osockaddr); 156 NETBSD32TOP_UAP(fromlenaddr, unsigned int); 157 158 return linux_sys_recvfrom(l, &ua, retval); 159 } 160 161 int 162 linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval) 163 { 164 /* { 165 syscallarg(int) s; 166 syscallarg(int) level; 167 syscallarg(int) optname; 168 syscallarg(netbsd32_voidp) optval; 169 syscallarg(int) optlen; 170 } */ 171 struct linux_sys_setsockopt_args ua; 172 173 NETBSD32TO64_UAP(s); 174 NETBSD32TO64_UAP(level); 175 NETBSD32TO64_UAP(optname); 176 NETBSD32TOP_UAP(optval, void); 177 NETBSD32TO64_UAP(optlen); 178 179 return linux_sys_setsockopt(l, &ua, retval); 180 } 181 182 183 int 184 linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval) 185 { 186 /* { 187 syscallarg(int) s; 188 syscallarg(int) level; 189 syscallarg(int) optname; 190 syscallarg(netbsd32_voidp) optval; 191 syscallarg(netbsd32_intp) optlen; 192 } */ 193 struct linux_sys_getsockopt_args ua; 194 195 NETBSD32TO64_UAP(s); 196 NETBSD32TO64_UAP(level); 197 NETBSD32TO64_UAP(optname); 198 NETBSD32TOP_UAP(optval, void); 199 NETBSD32TOP_UAP(optlen, int); 200 201 return linux_sys_getsockopt(l, &ua, retval); 202 } 203 204 int 205 linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval) 206 { 207 /* { 208 syscallarg(int) domain; 209 syscallarg(int) type; 210 syscallarg(int) protocol; 211 } */ 212 struct linux_sys_socket_args ua; 213 214 NETBSD32TO64_UAP(domain); 215 NETBSD32TO64_UAP(type); 216 NETBSD32TO64_UAP(protocol); 217 218 return linux_sys_socket(l, &ua, retval); 219 } 220 221 int 222 linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval) 223 { 224 /* { 225 syscallarg(int) s; 226 syscallarg(netbsd32_osockaddrp_t) name; 227 syscallarg(int) namelen; 228 } */ 229 struct linux_sys_bind_args ua; 230 231 NETBSD32TO64_UAP(s); 232 NETBSD32TOP_UAP(name, struct osockaddr) 233 NETBSD32TO64_UAP(namelen); 234 235 return linux_sys_bind(l, &ua, retval); 236 } 237 238 int 239 linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval) 240 { 241 /* { 242 syscallarg(int) s; 243 syscallarg(netbsd32_osockaddrp_t) name; 244 syscallarg(int) namelen; 245 } */ 246 struct linux_sys_connect_args ua; 247 248 NETBSD32TO64_UAP(s); 249 NETBSD32TOP_UAP(name, struct osockaddr) 250 NETBSD32TO64_UAP(namelen); 251 252 #ifdef DEBUG_LINUX 253 printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n", 254 SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen)); 255 #endif 256 257 return linux_sys_connect(l, &ua, retval); 258 } 259 260 int 261 linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval) 262 { 263 /* { 264 syscallarg(int) s; 265 syscallarg(netbsd32_osockaddrp_t) name; 266 syscallarg(netbsd32_intp) anamelen; 267 } */ 268 struct linux_sys_accept_args ua; 269 270 NETBSD32TO64_UAP(s); 271 NETBSD32TOP_UAP(name, struct osockaddr) 272 NETBSD32TOP_UAP(anamelen, int); 273 274 return linux_sys_accept(l, &ua, retval); 275 } 276 277 int 278 linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval) 279 { 280 /* { 281 syscallarg(int) fdes; 282 syscallarg(netbsd32_sockaddrp_t) asa; 283 syscallarg(netbsd32_intp) alen; 284 } */ 285 struct linux_sys_getpeername_args ua; 286 287 NETBSD32TO64_UAP(fdes); 288 NETBSD32TOP_UAP(asa, struct sockaddr) 289 NETBSD32TOP_UAP(alen, int); 290 291 return linux_sys_getpeername(l, &ua, retval); 292 } 293 294 int 295 linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval) 296 { 297 /* { 298 syscallarg(int) fdec; 299 syscallarg(netbsd32_charp) asa; 300 syscallarg(netbsd32_intp) alen; 301 } */ 302 struct linux_sys_getsockname_args ua; 303 304 NETBSD32TO64_UAP(fdec); 305 NETBSD32TOP_UAP(asa, char) 306 NETBSD32TOP_UAP(alen, int); 307 308 return linux_sys_getsockname(l, &ua, retval); 309 } 310 311 int 312 linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval) 313 { 314 /* { 315 syscallarg(int) s; 316 syscallarg(netbsd32_msghdrp_t) msg; 317 syscallarg(int) flags; 318 } */ 319 struct linux_sys_sendmsg_args ua; 320 321 NETBSD32TO64_UAP(s); 322 NETBSD32TOP_UAP(msg, struct msghdr); 323 NETBSD32TO64_UAP(flags); 324 325 return linux_sys_sendmsg(l, &ua, retval); 326 } 327 328 int 329 linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval) 330 { 331 /* { 332 syscallarg(int) s; 333 syscallarg(netbsd32_msghdrp_t) msg; 334 syscallarg(int) flags; 335 } */ 336 struct linux_sys_recvmsg_args ua; 337 338 NETBSD32TO64_UAP(s); 339 NETBSD32TOP_UAP(msg, struct msghdr); 340 NETBSD32TO64_UAP(flags); 341 342 return linux_sys_recvmsg(l, &ua, retval); 343 } 344 345 int 346 linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval) 347 { 348 /* { 349 syscallarg(int) s; 350 syscallarg(netbsd32_voidp) buf; 351 syscallarg(int) len; 352 syscallarg(int) flags; 353 } */ 354 struct sys_sendto_args ua; 355 356 NETBSD32TO64_UAP(s); 357 NETBSD32TOP_UAP(buf, void); 358 NETBSD32TO64_UAP(len); 359 NETBSD32TO64_UAP(flags); 360 SCARG(&ua, to) = NULL; 361 SCARG(&ua, tolen) = 0; 362 363 return sys_sendto(l, &ua, retval); 364 } 365 366 int 367 linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval) 368 { 369 /* { 370 syscallarg(int) s; 371 syscallarg(netbsd32_voidp) buf; 372 syscallarg(int) len; 373 syscallarg(int) flags; 374 } */ 375 struct sys_recvfrom_args ua; 376 377 NETBSD32TO64_UAP(s); 378 NETBSD32TOP_UAP(buf, void); 379 NETBSD32TO64_UAP(len); 380 NETBSD32TO64_UAP(flags); 381 SCARG(&ua, from) = NULL; 382 SCARG(&ua, fromlenaddr) = NULL; 383 384 return sys_recvfrom(l, &ua, retval); 385 } 386 387 int 388 linux32_getifconf(struct lwp *l, register_t *retval, void *data) 389 { 390 struct linux32_ifreq ifr, *ifrp; 391 struct netbsd32_ifconf *ifc = data; 392 struct ifnet *ifp; 393 struct ifaddr *ifa; 394 struct sockaddr *sa; 395 struct osockaddr *osa; 396 int space, error = 0; 397 const int sz = (int)sizeof(ifr); 398 399 ifrp = (struct linux32_ifreq *)NETBSD32PTR64(ifc->ifc_req); 400 if (ifrp == NULL) 401 space = 0; 402 else 403 space = ifc->ifc_len; 404 405 IFNET_FOREACH(ifp) { 406 (void)strncpy(ifr.ifr_name, ifp->if_xname, 407 sizeof(ifr.ifr_name)); 408 if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') 409 return ENAMETOOLONG; 410 if (IFADDR_EMPTY(ifp)) 411 continue; 412 IFADDR_FOREACH(ifa, ifp) { 413 sa = ifa->ifa_addr; 414 if (sa->sa_family != AF_INET || 415 sa->sa_len > sizeof(*osa)) 416 continue; 417 memcpy(&ifr.ifr_addr, sa, sa->sa_len); 418 osa = (struct osockaddr *)&ifr.ifr_addr; 419 osa->sa_family = sa->sa_family; 420 if (space >= sz) { 421 error = copyout(&ifr, ifrp, sz); 422 if (error != 0) 423 return error; 424 ifrp++; 425 } 426 space -= sz; 427 } 428 } 429 430 if (ifrp != NULL) 431 ifc->ifc_len -= space; 432 else 433 ifc->ifc_len = -space; 434 435 return 0; 436 } 437 438 int 439 linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, 440 void *data) 441 { 442 struct linux32_ifreq lreq; 443 file_t *fp; 444 struct ifaddr *ifa; 445 struct ifnet *ifp; 446 struct sockaddr_dl *sadl; 447 int error, found; 448 int index, ifnum; 449 450 /* 451 * We can't emulate this ioctl by calling sys_ioctl() to run 452 * SIOCGIFCONF, because the user buffer is not of the right 453 * type to take those results. We can't use kernel buffers to 454 * receive the results, as the implementation of sys_ioctl() 455 * and ifconf() [which implements SIOCGIFCONF] use 456 * copyin()/copyout() which will fail on kernel addresses. 457 * 458 * So, we must duplicate code from sys_ioctl() and ifconf(). Ugh. 459 */ 460 461 if ((fp = fd_getfile(fd)) == NULL) 462 return (EBADF); 463 464 KERNEL_LOCK(1, NULL); 465 466 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 467 error = EBADF; 468 goto out; 469 } 470 471 error = copyin(data, &lreq, sizeof(lreq)); 472 if (error) 473 goto out; 474 lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0'; /* just in case */ 475 476 /* 477 * Try real interface name first, then fake "ethX" 478 */ 479 found = 0; 480 IFNET_FOREACH(ifp) { 481 if (found) 482 break; 483 if (strcmp(lreq.ifr_name, ifp->if_xname)) 484 /* not this interface */ 485 continue; 486 found=1; 487 if (IFADDR_EMPTY(ifp)) { 488 error = ENODEV; 489 goto out; 490 } 491 IFADDR_FOREACH(ifa, ifp) { 492 sadl = satosdl(ifa->ifa_addr); 493 /* only return ethernet addresses */ 494 /* XXX what about FDDI, etc. ? */ 495 if (sadl->sdl_family != AF_LINK || 496 sadl->sdl_type != IFT_ETHER) 497 continue; 498 memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), 499 MIN(sadl->sdl_alen, 500 sizeof(lreq.ifr_hwaddr.sa_data))); 501 lreq.ifr_hwaddr.sa_family = 502 sadl->sdl_family; 503 error = copyout(&lreq, data, sizeof(lreq)); 504 goto out; 505 } 506 } 507 508 if (strncmp(lreq.ifr_name, "eth", 3) == 0) { 509 for (ifnum = 0, index = 3; 510 lreq.ifr_name[index] != '\0' && index < LINUX32_IFNAMSIZ; 511 index++) { 512 ifnum *= 10; 513 ifnum += lreq.ifr_name[index] - '0'; 514 } 515 516 error = EINVAL; /* in case we don't find one */ 517 found = 0; 518 IFNET_FOREACH(ifp) { 519 if (found) 520 break; 521 memcpy(lreq.ifr_name, ifp->if_xname, 522 MIN(LINUX32_IFNAMSIZ, IFNAMSIZ)); 523 IFADDR_FOREACH(ifa, ifp) { 524 sadl = satosdl(ifa->ifa_addr); 525 /* only return ethernet addresses */ 526 /* XXX what about FDDI, etc. ? */ 527 if (sadl->sdl_family != AF_LINK || 528 sadl->sdl_type != IFT_ETHER) 529 continue; 530 if (ifnum--) 531 /* not the reqested iface */ 532 continue; 533 memcpy(&lreq.ifr_hwaddr.sa_data, 534 CLLADDR(sadl), 535 MIN(sadl->sdl_alen, 536 sizeof(lreq.ifr_hwaddr.sa_data))); 537 lreq.ifr_hwaddr.sa_family = 538 sadl->sdl_family; 539 error = copyout(&lreq, data, sizeof(lreq)); 540 found = 1; 541 break; 542 } 543 } 544 } else { 545 /* unknown interface, not even an "eth*" name */ 546 error = ENODEV; 547 } 548 549 out: 550 KERNEL_UNLOCK_ONE(NULL); 551 fd_putfile(fd); 552 return error; 553 } 554 555 int 556 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) 557 { 558 /* { 559 syscallarg(int) fd; 560 syscallarg(u_long) com; 561 syscallarg(void *) data; 562 } */ 563 u_long com; 564 int error = 0, isdev = 0, dosys = 1; 565 struct netbsd32_ioctl_args ia; 566 file_t *fp; 567 struct vnode *vp; 568 int (*ioctlf)(file_t *, u_long, void *); 569 struct ioctl_pt pt; 570 571 if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) 572 return (EBADF); 573 574 if (fp->f_type == DTYPE_VNODE) { 575 vp = (struct vnode *)fp->f_data; 576 isdev = vp->v_type == VCHR; 577 } 578 579 /* 580 * Don't try to interpret socket ioctl calls that are done 581 * on a device filedescriptor, just pass them through, to 582 * emulate Linux behaviour. Use PTIOCLINUX so that the 583 * device will only handle these if it's prepared to do 584 * so, to avoid unexpected things from happening. 585 */ 586 if (isdev) { 587 dosys = 0; 588 ioctlf = fp->f_ops->fo_ioctl; 589 pt.com = SCARG(uap, com); 590 pt.data = (void *)NETBSD32PTR64(SCARG(uap, data)); 591 error = ioctlf(fp, PTIOCLINUX, &pt); 592 /* 593 * XXX hack: if the function returns EJUSTRETURN, 594 * it has stuffed a sysctl return value in pt.data. 595 */ 596 if (error == EJUSTRETURN) { 597 retval[0] = (register_t)pt.data; 598 error = 0; 599 } 600 goto out; 601 } 602 603 com = SCARG(uap, com); 604 retval[0] = 0; 605 606 switch (com) { 607 case LINUX_SIOCGIFCONF: 608 error = linux32_getifconf(l, retval, SCARG_P32(uap, data)); 609 dosys = 0; 610 break; 611 case LINUX_SIOCGIFFLAGS: 612 SCARG(&ia, com) = OSIOCGIFFLAGS; 613 break; 614 case LINUX_SIOCSIFFLAGS: 615 SCARG(&ia, com) = OSIOCSIFFLAGS; 616 break; 617 case LINUX_SIOCGIFADDR: 618 SCARG(&ia, com) = OOSIOCGIFADDR; 619 break; 620 case LINUX_SIOCGIFDSTADDR: 621 SCARG(&ia, com) = OOSIOCGIFDSTADDR; 622 break; 623 case LINUX_SIOCGIFBRDADDR: 624 SCARG(&ia, com) = OOSIOCGIFBRDADDR; 625 break; 626 case LINUX_SIOCGIFNETMASK: 627 SCARG(&ia, com) = OOSIOCGIFNETMASK; 628 break; 629 case LINUX_SIOCADDMULTI: 630 SCARG(&ia, com) = OSIOCADDMULTI; 631 break; 632 case LINUX_SIOCDELMULTI: 633 SCARG(&ia, com) = OSIOCDELMULTI; 634 break; 635 case LINUX_SIOCGIFHWADDR: 636 error = linux32_getifhwaddr(l, retval, SCARG(uap, fd), 637 SCARG_P32(uap, data)); 638 dosys = 0; 639 break; 640 default: 641 error = EINVAL; 642 } 643 644 out: 645 fd_putfile(SCARG(uap, fd)); 646 647 if (error == 0 && dosys) { 648 SCARG(&ia, fd) = SCARG(uap, fd); 649 SCARG(&ia, data) = SCARG(uap, data); 650 error = netbsd32_ioctl(curlwp, &ia, retval); 651 } 652 653 return error; 654 } 655