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