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