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