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