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