linux_socket.c revision 31711
1181847Sjkim/*- 2181847Sjkim * Copyright (c) 1995 S�ren Schmidt 3181847Sjkim * All rights reserved. 4181847Sjkim * 5181847Sjkim * Redistribution and use in source and binary forms, with or without 6181847Sjkim * modification, are permitted provided that the following conditions 7181847Sjkim * are met: 8181847Sjkim * 1. Redistributions of source code must retain the above copyright 9181847Sjkim * notice, this list of conditions and the following disclaimer 10181847Sjkim * in this position and unchanged. 11181847Sjkim * 2. Redistributions in binary form must reproduce the above copyright 12181847Sjkim * notice, this list of conditions and the following disclaimer in the 13181847Sjkim * documentation and/or other materials provided with the distribution. 14181847Sjkim * 3. The name of the author may not be used to endorse or promote products 15181847Sjkim * derived from this software withough specific prior written permission 16181847Sjkim * 17181847Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18181847Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19181847Sjkim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20181847Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21181847Sjkim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22181847Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23181847Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24181847Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25181847Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26181847Sjkim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27181847Sjkim * 28181847Sjkim * $Id: linux_socket.c,v 1.9 1997/11/06 19:29:03 phk Exp $ 29181847Sjkim */ 30182393Sjkim 31181847Sjkim/* XXX we use functions that might not exist. */ 32#define COMPAT_43 1 33 34#include <sys/param.h> 35#include <sys/proc.h> 36#include <sys/systm.h> 37#include <sys/sysproto.h> 38#include <sys/socket.h> 39 40#include <netinet/in.h> 41#include <netinet/in_systm.h> 42#include <netinet/ip.h> 43 44#include <i386/linux/linux.h> 45#include <i386/linux/linux_proto.h> 46#include <i386/linux/linux_util.h> 47 48static int 49linux_to_bsd_domain(int domain) 50{ 51 switch (domain) { 52 case LINUX_AF_UNSPEC: 53 return AF_UNSPEC; 54 case LINUX_AF_UNIX: 55 return AF_LOCAL; 56 case LINUX_AF_INET: 57 return AF_INET; 58 case LINUX_AF_AX25: 59 return AF_CCITT; 60 case LINUX_AF_IPX: 61 return AF_IPX; 62 case LINUX_AF_APPLETALK: 63 return AF_APPLETALK; 64 default: 65 return -1; 66 } 67} 68 69static int 70linux_to_bsd_sockopt_level(int level) 71{ 72 switch (level) { 73 case LINUX_SOL_SOCKET: 74 return SOL_SOCKET; 75 default: 76 return level; 77 } 78} 79 80static int linux_to_bsd_ip_sockopt(int opt) 81{ 82 switch (opt) { 83 case LINUX_IP_TOS: 84 return IP_TOS; 85 case LINUX_IP_TTL: 86 return IP_TTL; 87 case LINUX_IP_OPTIONS: 88 return IP_OPTIONS; 89 case LINUX_IP_MULTICAST_IF: 90 return IP_MULTICAST_IF; 91 case LINUX_IP_MULTICAST_TTL: 92 return IP_MULTICAST_TTL; 93 case LINUX_IP_MULTICAST_LOOP: 94 return IP_MULTICAST_LOOP; 95 case LINUX_IP_ADD_MEMBERSHIP: 96 return IP_ADD_MEMBERSHIP; 97 case LINUX_IP_DROP_MEMBERSHIP: 98 return IP_DROP_MEMBERSHIP; 99 case LINUX_IP_HDRINCL: 100 return IP_HDRINCL; 101 default: 102 return -1; 103 } 104} 105 106static int 107linux_to_bsd_so_sockopt(int opt) 108{ 109 switch (opt) { 110 case LINUX_SO_DEBUG: 111 return SO_DEBUG; 112 case LINUX_SO_REUSEADDR: 113 return SO_REUSEADDR; 114 case LINUX_SO_TYPE: 115 return SO_TYPE; 116 case LINUX_SO_ERROR: 117 return SO_ERROR; 118 case LINUX_SO_DONTROUTE: 119 return SO_DONTROUTE; 120 case LINUX_SO_BROADCAST: 121 return SO_BROADCAST; 122 case LINUX_SO_SNDBUF: 123 return SO_SNDBUF; 124 case LINUX_SO_RCVBUF: 125 return SO_RCVBUF; 126 case LINUX_SO_KEEPALIVE: 127 return SO_KEEPALIVE; 128 case LINUX_SO_OOBINLINE: 129 return SO_OOBINLINE; 130 case LINUX_SO_LINGER: 131 return SO_LINGER; 132 case LINUX_SO_PRIORITY: 133 case LINUX_SO_NO_CHECK: 134 default: 135 return -1; 136 } 137} 138 139/* Return 0 if IP_HDRINCL is set of the given socket, not 0 otherwise */ 140static int 141linux_check_hdrincl(struct proc *p, int s) 142{ 143 struct getsockopt_args /* { 144 int s; 145 int level; 146 int name; 147 caddr_t val; 148 int *avalsize; 149 } */ bsd_args; 150 int error; 151 caddr_t sg, val, valsize; 152 int size_val = sizeof val; 153 int optval; 154 155 sg = stackgap_init(); 156 val = stackgap_alloc(&sg, sizeof(int)); 157 valsize = stackgap_alloc(&sg, sizeof(int)); 158 159 if ((error=copyout(&size_val, valsize, sizeof(size_val)))) 160 return error; 161 bsd_args.s = s; 162 bsd_args.level = IPPROTO_IP; 163 bsd_args.name = IP_HDRINCL; 164 bsd_args.val = val; 165 bsd_args.avalsize = (int *)valsize; 166 if ((error=getsockopt(p, &bsd_args))) 167 return error; 168 if ((error=copyin(val, &optval, sizeof(optval)))) 169 return error; 170 return optval == 0; 171} 172 173/* 174 * Updated sendto() when IP_HDRINCL is set: 175 * tweak endian-dependent fields in the IP packet. 176 */ 177static int 178linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args) 179{ 180/* 181 * linux_ip_copysize defines how many bytes we should copy 182 * from the beginning of the IP packet before we customize it for BSD. 183 * It should include all the fields we modify (ip_len and ip_off) 184 * and be as small as possible to minimize copying overhead. 185 */ 186#define linux_ip_copysize 8 187 188 caddr_t sg; 189 struct ip *packet; 190 struct msghdr *msg; 191 struct iovec *iov; 192 193 int error; 194 struct sendmsg_args /* { 195 int s; 196 caddr_t msg; 197 int flags; 198 } */ sendmsg_args; 199 200 /* Check the packet isn't too small before we mess with it */ 201 if (bsd_args->len < linux_ip_copysize) 202 return EINVAL; 203 204 /* 205 * Tweaking the user buffer in place would be bad manners. 206 * We create a corrected IP header with just the needed length, 207 * then use an iovec to glue it to the rest of the user packet 208 * when calling sendmsg(). 209 */ 210 sg = stackgap_init(); 211 packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize); 212 msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg)); 213 iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2); 214 215 /* Make a copy of the beginning of the packet to be sent */ 216 if ((error = copyin(bsd_args->buf, (caddr_t)packet, linux_ip_copysize))) 217 return error; 218 219 /* Convert fields from Linux to BSD raw IP socket format */ 220 packet->ip_len = bsd_args->len; 221 packet->ip_off = ntohs(packet->ip_off); 222 223 /* Prepare the msghdr and iovec structures describing the new packet */ 224 msg->msg_name = bsd_args->to; 225 msg->msg_namelen = bsd_args->tolen; 226 msg->msg_iov = iov; 227 msg->msg_iovlen = 2; 228 msg->msg_control = NULL; 229 msg->msg_controllen = 0; 230 msg->msg_flags = 0; 231 iov[0].iov_base = (char *)packet; 232 iov[0].iov_len = linux_ip_copysize; 233 iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize; 234 iov[1].iov_len = bsd_args->len - linux_ip_copysize; 235 236 sendmsg_args.s = bsd_args->s; 237 sendmsg_args.msg = (caddr_t)msg; 238 sendmsg_args.flags = bsd_args->flags; 239 return sendmsg(p, &sendmsg_args); 240} 241 242struct linux_socket_args { 243 int domain; 244 int type; 245 int protocol; 246}; 247 248static int 249linux_socket(struct proc *p, struct linux_socket_args *args) 250{ 251 struct linux_socket_args linux_args; 252 struct socket_args /* { 253 int domain; 254 int type; 255 int protocol; 256 } */ bsd_args; 257 int error; 258 int retval_socket; 259 260 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 261 return error; 262 bsd_args.protocol = linux_args.protocol; 263 bsd_args.type = linux_args.type; 264 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 265 if (bsd_args.domain == -1) 266 return EINVAL; 267 268 retval_socket = socket(p, &bsd_args); 269 if (bsd_args.type == SOCK_RAW 270 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) 271 && bsd_args.domain == AF_INET 272 && retval_socket >= 0) { 273 /* It's a raw IP socket: set the IP_HDRINCL option. */ 274 struct setsockopt_args /* { 275 int s; 276 int level; 277 int name; 278 caddr_t val; 279 int valsize; 280 } */ bsd_setsockopt_args; 281 caddr_t sg; 282 int *hdrincl; 283 284 sg = stackgap_init(); 285 hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl)); 286 *hdrincl = 1; 287 bsd_setsockopt_args.s = p->p_retval[0]; 288 bsd_setsockopt_args.level = IPPROTO_IP; 289 bsd_setsockopt_args.name = IP_HDRINCL; 290 bsd_setsockopt_args.val = (caddr_t)hdrincl; 291 bsd_setsockopt_args.valsize = sizeof(*hdrincl); 292 /* We ignore any error returned by setsockopt() */ 293 setsockopt(p, &bsd_setsockopt_args); 294 /* Copy back the return value from socket() */ 295 p->p_retval[0] = bsd_setsockopt_args.s; 296 } 297 return retval_socket; 298} 299 300struct linux_bind_args { 301 int s; 302 struct sockaddr *name; 303 int namelen; 304}; 305 306static int 307linux_bind(struct proc *p, struct linux_bind_args *args) 308{ 309 struct linux_bind_args linux_args; 310 struct bind_args /* { 311 int s; 312 caddr_t name; 313 int namelen; 314 } */ bsd_args; 315 int error; 316 317 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 318 return error; 319 bsd_args.s = linux_args.s; 320 bsd_args.name = (caddr_t)linux_args.name; 321 bsd_args.namelen = linux_args.namelen; 322 return bind(p, &bsd_args); 323} 324 325struct linux_connect_args { 326 int s; 327 struct sockaddr * name; 328 int namelen; 329}; 330 331static int 332linux_connect(struct proc *p, struct linux_connect_args *args) 333{ 334 struct linux_connect_args linux_args; 335 struct connect_args /* { 336 int s; 337 caddr_t name; 338 int namelen; 339 } */ bsd_args; 340 int error; 341 342 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 343 return error; 344 bsd_args.s = linux_args.s; 345 bsd_args.name = (caddr_t)linux_args.name; 346 bsd_args.namelen = linux_args.namelen; 347 return connect(p, &bsd_args); 348} 349 350struct linux_listen_args { 351 int s; 352 int backlog; 353}; 354 355static int 356linux_listen(struct proc *p, struct linux_listen_args *args) 357{ 358 struct linux_listen_args linux_args; 359 struct listen_args /* { 360 int s; 361 int backlog; 362 } */ bsd_args; 363 int error; 364 365 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 366 return error; 367 bsd_args.s = linux_args.s; 368 bsd_args.backlog = linux_args.backlog; 369 return listen(p, &bsd_args); 370} 371 372struct linux_accept_args { 373 int s; 374 struct sockaddr *addr; 375 int *namelen; 376}; 377 378static int 379linux_accept(struct proc *p, struct linux_accept_args *args) 380{ 381 struct linux_accept_args linux_args; 382 struct accept_args /* { 383 int s; 384 caddr_t name; 385 int *anamelen; 386 } */ bsd_args; 387 int error; 388 389 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 390 return error; 391 bsd_args.s = linux_args.s; 392 bsd_args.name = (caddr_t)linux_args.addr; 393 bsd_args.anamelen = linux_args.namelen; 394 return oaccept(p, &bsd_args); 395} 396 397struct linux_getsockname_args { 398 int s; 399 struct sockaddr *addr; 400 int *namelen; 401}; 402 403static int 404linux_getsockname(struct proc *p, struct linux_getsockname_args *args) 405{ 406 struct linux_getsockname_args linux_args; 407 struct getsockname_args /* { 408 int fdes; 409 caddr_t asa; 410 int *alen; 411 } */ bsd_args; 412 int error; 413 414 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 415 return error; 416 bsd_args.fdes = linux_args.s; 417 bsd_args.asa = (caddr_t) linux_args.addr; 418 bsd_args.alen = linux_args.namelen; 419 return ogetsockname(p, &bsd_args); 420} 421 422struct linux_getpeername_args { 423 int s; 424 struct sockaddr *addr; 425 int *namelen; 426}; 427 428static int 429linux_getpeername(struct proc *p, struct linux_getpeername_args *args) 430{ 431 struct linux_getpeername_args linux_args; 432 struct ogetpeername_args /* { 433 int fdes; 434 caddr_t asa; 435 int *alen; 436 } */ bsd_args; 437 int error; 438 439 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 440 return error; 441 bsd_args.fdes = linux_args.s; 442 bsd_args.asa = (caddr_t) linux_args.addr; 443 bsd_args.alen = linux_args.namelen; 444 return ogetpeername(p, &bsd_args); 445} 446 447struct linux_socketpair_args { 448 int domain; 449 int type; 450 int protocol; 451 int *rsv; 452}; 453 454static int 455linux_socketpair(struct proc *p, struct linux_socketpair_args *args) 456{ 457 struct linux_socketpair_args linux_args; 458 struct socketpair_args /* { 459 int domain; 460 int type; 461 int protocol; 462 int *rsv; 463 } */ bsd_args; 464 int error; 465 466 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 467 return error; 468 bsd_args.domain = linux_to_bsd_domain(linux_args.domain); 469 if (bsd_args.domain == -1) 470 return EINVAL; 471 bsd_args.type = linux_args.type; 472 bsd_args.protocol = linux_args.protocol; 473 bsd_args.rsv = linux_args.rsv; 474 return socketpair(p, &bsd_args); 475} 476 477struct linux_send_args { 478 int s; 479 void *msg; 480 int len; 481 int flags; 482}; 483 484static int 485linux_send(struct proc *p, struct linux_send_args *args) 486{ 487 struct linux_send_args linux_args; 488 struct osend_args /* { 489 int s; 490 caddr_t buf; 491 int len; 492 int flags; 493 } */ bsd_args; 494 int error; 495 496 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 497 return error; 498 bsd_args.s = linux_args.s; 499 bsd_args.buf = linux_args.msg; 500 bsd_args.len = linux_args.len; 501 bsd_args.flags = linux_args.flags; 502 return osend(p, &bsd_args); 503} 504 505struct linux_recv_args { 506 int s; 507 void *msg; 508 int len; 509 int flags; 510}; 511 512static int 513linux_recv(struct proc *p, struct linux_recv_args *args) 514{ 515 struct linux_recv_args linux_args; 516 struct orecv_args /* { 517 int s; 518 caddr_t buf; 519 int len; 520 int flags; 521 } */ bsd_args; 522 int error; 523 524 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 525 return error; 526 bsd_args.s = linux_args.s; 527 bsd_args.buf = linux_args.msg; 528 bsd_args.len = linux_args.len; 529 bsd_args.flags = linux_args.flags; 530 return orecv(p, &bsd_args); 531} 532 533struct linux_sendto_args { 534 int s; 535 void *msg; 536 int len; 537 int flags; 538 caddr_t to; 539 int tolen; 540}; 541 542static int 543linux_sendto(struct proc *p, struct linux_sendto_args *args) 544{ 545 struct linux_sendto_args linux_args; 546 struct sendto_args /* { 547 int s; 548 caddr_t buf; 549 size_t len; 550 int flags; 551 caddr_t to; 552 int tolen; 553 } */ bsd_args; 554 int error; 555 556 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 557 return error; 558 bsd_args.s = linux_args.s; 559 bsd_args.buf = linux_args.msg; 560 bsd_args.len = linux_args.len; 561 bsd_args.flags = linux_args.flags; 562 bsd_args.to = linux_args.to; 563 bsd_args.tolen = linux_args.tolen; 564 565 if (linux_check_hdrincl(p, linux_args.s) == 0) 566 /* IP_HDRINCL set, tweak the packet before sending */ 567 return linux_sendto_hdrincl(p, &bsd_args); 568 569 return sendto(p, &bsd_args); 570} 571 572struct linux_recvfrom_args { 573 int s; 574 void *buf; 575 int len; 576 int flags; 577 caddr_t from; 578 int *fromlen; 579}; 580 581static int 582linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args) 583{ 584 struct linux_recvfrom_args linux_args; 585 struct recvfrom_args /* { 586 int s; 587 caddr_t buf; 588 size_t len; 589 int flags; 590 caddr_t from; 591 int *fromlenaddr; 592 } */ bsd_args; 593 int error; 594 595 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 596 return error; 597 bsd_args.s = linux_args.s; 598 bsd_args.buf = linux_args.buf; 599 bsd_args.len = linux_args.len; 600 bsd_args.flags = linux_args.flags; 601 bsd_args.from = linux_args.from; 602 bsd_args.fromlenaddr = linux_args.fromlen; 603 return orecvfrom(p, &bsd_args); 604} 605 606struct linux_shutdown_args { 607 int s; 608 int how; 609}; 610 611static int 612linux_shutdown(struct proc *p, struct linux_shutdown_args *args) 613{ 614 struct linux_shutdown_args linux_args; 615 struct shutdown_args /* { 616 int s; 617 int how; 618 } */ bsd_args; 619 int error; 620 621 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 622 return error; 623 bsd_args.s = linux_args.s; 624 bsd_args.how = linux_args.how; 625 return shutdown(p, &bsd_args); 626} 627 628struct linux_setsockopt_args { 629 int s; 630 int level; 631 int optname; 632 void *optval; 633 int optlen; 634}; 635 636static int 637linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) 638{ 639 struct linux_setsockopt_args linux_args; 640 struct setsockopt_args /* { 641 int s; 642 int level; 643 int name; 644 caddr_t val; 645 int valsize; 646 } */ bsd_args; 647 int error, name; 648 649 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 650 return error; 651 bsd_args.s = linux_args.s; 652 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 653 switch (bsd_args.level) { 654 case SOL_SOCKET: 655 name = linux_to_bsd_so_sockopt(linux_args.optname); 656 break; 657 case IPPROTO_IP: 658 name = linux_to_bsd_ip_sockopt(linux_args.optname); 659 break; 660 default: 661 return EINVAL; 662 } 663 if (name == -1) 664 return EINVAL; 665 bsd_args.name = name; 666 bsd_args.val = linux_args.optval; 667 bsd_args.valsize = linux_args.optlen; 668 return setsockopt(p, &bsd_args); 669} 670 671struct linux_getsockopt_args { 672 int s; 673 int level; 674 int optname; 675 void *optval; 676 int *optlen; 677}; 678 679static int 680linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) 681{ 682 struct linux_getsockopt_args linux_args; 683 struct getsockopt_args /* { 684 int s; 685 int level; 686 int name; 687 caddr_t val; 688 int *avalsize; 689 } */ bsd_args; 690 int error, name; 691 692 if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) 693 return error; 694 bsd_args.s = linux_args.s; 695 bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); 696 switch (bsd_args.level) { 697 case SOL_SOCKET: 698 name = linux_to_bsd_so_sockopt(linux_args.optname); 699 break; 700 case IPPROTO_IP: 701 name = linux_to_bsd_ip_sockopt(linux_args.optname); 702 break; 703 default: 704 return EINVAL; 705 } 706 if (name == -1) 707 return EINVAL; 708 bsd_args.name = name; 709 bsd_args.val = linux_args.optval; 710 bsd_args.avalsize = linux_args.optlen; 711 return getsockopt(p, &bsd_args); 712} 713 714int 715linux_socketcall(struct proc *p, struct linux_socketcall_args *args) 716{ 717 switch (args->what) { 718 case LINUX_SOCKET: 719 return linux_socket(p, args->args); 720 case LINUX_BIND: 721 return linux_bind(p, args->args); 722 case LINUX_CONNECT: 723 return linux_connect(p, args->args); 724 case LINUX_LISTEN: 725 return linux_listen(p, args->args); 726 case LINUX_ACCEPT: 727 return linux_accept(p, args->args); 728 case LINUX_GETSOCKNAME: 729 return linux_getsockname(p, args->args); 730 case LINUX_GETPEERNAME: 731 return linux_getpeername(p, args->args); 732 case LINUX_SOCKETPAIR: 733 return linux_socketpair(p, args->args); 734 case LINUX_SEND: 735 return linux_send(p, args->args); 736 case LINUX_RECV: 737 return linux_recv(p, args->args); 738 case LINUX_SENDTO: 739 return linux_sendto(p, args->args); 740 case LINUX_RECVFROM: 741 return linux_recvfrom(p, args->args); 742 case LINUX_SHUTDOWN: 743 return linux_shutdown(p, args->args); 744 case LINUX_SETSOCKOPT: 745 return linux_setsockopt(p, args->args); 746 case LINUX_GETSOCKOPT: 747 return linux_getsockopt(p, args->args); 748 default: 749 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); 750 return ENOSYS; 751 } 752} 753