linux_socket.c revision 33148
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.11 1997/12/16 17:40:11 eivind 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/fcntl.h>
43#include <sys/socket.h>
44
45#include <netinet/in.h>
46#include <netinet/in_systm.h>
47#include <netinet/ip.h>
48
49#include <i386/linux/linux.h>
50#include <i386/linux/linux_proto.h>
51#include <i386/linux/linux_util.h>
52
53static int
54linux_to_bsd_domain(int domain)
55{
56    switch (domain) {
57    case LINUX_AF_UNSPEC:
58	return AF_UNSPEC;
59    case LINUX_AF_UNIX:
60	return AF_LOCAL;
61    case LINUX_AF_INET:
62	return AF_INET;
63    case LINUX_AF_AX25:
64	return AF_CCITT;
65    case LINUX_AF_IPX:
66	return AF_IPX;
67    case LINUX_AF_APPLETALK:
68	return AF_APPLETALK;
69    default:
70	return -1;
71    }
72}
73
74static int
75linux_to_bsd_sockopt_level(int level)
76{
77    switch (level) {
78    case LINUX_SOL_SOCKET:
79	return SOL_SOCKET;
80    default:
81	return level;
82    }
83}
84
85static int linux_to_bsd_ip_sockopt(int opt)
86{
87    switch (opt) {
88    case LINUX_IP_TOS:
89	return IP_TOS;
90    case LINUX_IP_TTL:
91	return IP_TTL;
92    case LINUX_IP_OPTIONS:
93	return IP_OPTIONS;
94    case LINUX_IP_MULTICAST_IF:
95	return IP_MULTICAST_IF;
96    case LINUX_IP_MULTICAST_TTL:
97	return IP_MULTICAST_TTL;
98    case LINUX_IP_MULTICAST_LOOP:
99	return IP_MULTICAST_LOOP;
100    case LINUX_IP_ADD_MEMBERSHIP:
101	return IP_ADD_MEMBERSHIP;
102    case LINUX_IP_DROP_MEMBERSHIP:
103	return IP_DROP_MEMBERSHIP;
104    case LINUX_IP_HDRINCL:
105        return IP_HDRINCL;
106    default:
107	return -1;
108    }
109}
110
111static int
112linux_to_bsd_so_sockopt(int opt)
113{
114    switch (opt) {
115    case LINUX_SO_DEBUG:
116	return SO_DEBUG;
117    case LINUX_SO_REUSEADDR:
118	return SO_REUSEADDR;
119    case LINUX_SO_TYPE:
120	return SO_TYPE;
121    case LINUX_SO_ERROR:
122	return SO_ERROR;
123    case LINUX_SO_DONTROUTE:
124	return SO_DONTROUTE;
125    case LINUX_SO_BROADCAST:
126	return SO_BROADCAST;
127    case LINUX_SO_SNDBUF:
128	return SO_SNDBUF;
129    case LINUX_SO_RCVBUF:
130	return SO_RCVBUF;
131    case LINUX_SO_KEEPALIVE:
132	return SO_KEEPALIVE;
133    case LINUX_SO_OOBINLINE:
134	return SO_OOBINLINE;
135    case LINUX_SO_LINGER:
136	return SO_LINGER;
137    case LINUX_SO_PRIORITY:
138    case LINUX_SO_NO_CHECK:
139    default:
140	return -1;
141    }
142}
143
144/* Return 0 if IP_HDRINCL is set of the given socket, not 0 otherwise */
145static int
146linux_check_hdrincl(struct proc *p, int s)
147{
148    struct getsockopt_args /* {
149	int s;
150	int level;
151	int name;
152	caddr_t val;
153	int *avalsize;
154    } */ bsd_args;
155    int error;
156    caddr_t sg, val, valsize;
157    int size_val = sizeof val;
158    int optval;
159
160    sg = stackgap_init();
161    val = stackgap_alloc(&sg, sizeof(int));
162    valsize = stackgap_alloc(&sg, sizeof(int));
163
164    if ((error=copyout(&size_val, valsize, sizeof(size_val))))
165	return error;
166    bsd_args.s = s;
167    bsd_args.level = IPPROTO_IP;
168    bsd_args.name = IP_HDRINCL;
169    bsd_args.val = val;
170    bsd_args.avalsize = (int *)valsize;
171    if ((error=getsockopt(p, &bsd_args)))
172	return error;
173    if ((error=copyin(val, &optval, sizeof(optval))))
174	return error;
175    return optval == 0;
176}
177
178/*
179 * Updated sendto() when IP_HDRINCL is set:
180 * tweak endian-dependent fields in the IP packet.
181 */
182static int
183linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args)
184{
185/*
186 * linux_ip_copysize defines how many bytes we should copy
187 * from the beginning of the IP packet before we customize it for BSD.
188 * It should include all the fields we modify (ip_len and ip_off)
189 * and be as small as possible to minimize copying overhead.
190 */
191#define linux_ip_copysize	8
192
193    caddr_t sg;
194    struct ip *packet;
195    struct msghdr *msg;
196    struct iovec *iov;
197
198    int error;
199    struct  sendmsg_args /* {
200	int s;
201	caddr_t msg;
202	int flags;
203    } */ sendmsg_args;
204
205    /* Check the packet isn't too small before we mess with it */
206    if (bsd_args->len < linux_ip_copysize)
207	return EINVAL;
208
209    /*
210     * Tweaking the user buffer in place would be bad manners.
211     * We create a corrected IP header with just the needed length,
212     * then use an iovec to glue it to the rest of the user packet
213     * when calling sendmsg().
214     */
215    sg = stackgap_init();
216    packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
217    msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
218    iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
219
220    /* Make a copy of the beginning of the packet to be sent */
221    if ((error = copyin(bsd_args->buf, (caddr_t)packet, linux_ip_copysize)))
222	return error;
223
224    /* Convert fields from Linux to BSD raw IP socket format */
225    packet->ip_len = bsd_args->len;
226    packet->ip_off = ntohs(packet->ip_off);
227
228    /* Prepare the msghdr and iovec structures describing the new packet */
229    msg->msg_name = bsd_args->to;
230    msg->msg_namelen = bsd_args->tolen;
231    msg->msg_iov = iov;
232    msg->msg_iovlen = 2;
233    msg->msg_control = NULL;
234    msg->msg_controllen = 0;
235    msg->msg_flags = 0;
236    iov[0].iov_base = (char *)packet;
237    iov[0].iov_len = linux_ip_copysize;
238    iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
239    iov[1].iov_len = bsd_args->len - linux_ip_copysize;
240
241    sendmsg_args.s = bsd_args->s;
242    sendmsg_args.msg = (caddr_t)msg;
243    sendmsg_args.flags = bsd_args->flags;
244    return sendmsg(p, &sendmsg_args);
245}
246
247struct linux_socket_args {
248    int domain;
249    int type;
250    int protocol;
251};
252
253static int
254linux_socket(struct proc *p, struct linux_socket_args *args)
255{
256    struct linux_socket_args linux_args;
257    struct socket_args /* {
258	int domain;
259	int type;
260	int protocol;
261    } */ bsd_args;
262    int error;
263    int retval_socket;
264
265    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
266	return error;
267    bsd_args.protocol = linux_args.protocol;
268    bsd_args.type = linux_args.type;
269    bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
270    if (bsd_args.domain == -1)
271	return EINVAL;
272
273    retval_socket = socket(p, &bsd_args);
274    if (bsd_args.type == SOCK_RAW
275	&& (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
276	&& bsd_args.domain == AF_INET
277	&& retval_socket >= 0) {
278	/* It's a raw IP socket: set the IP_HDRINCL option. */
279	struct setsockopt_args /* {
280	    int s;
281	    int level;
282	    int name;
283	    caddr_t val;
284	    int valsize;
285	} */ bsd_setsockopt_args;
286	caddr_t sg;
287	int *hdrincl;
288
289	sg = stackgap_init();
290	hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
291	*hdrincl = 1;
292	bsd_setsockopt_args.s = p->p_retval[0];
293	bsd_setsockopt_args.level = IPPROTO_IP;
294	bsd_setsockopt_args.name = IP_HDRINCL;
295	bsd_setsockopt_args.val = (caddr_t)hdrincl;
296	bsd_setsockopt_args.valsize = sizeof(*hdrincl);
297	/* We ignore any error returned by setsockopt() */
298	setsockopt(p, &bsd_setsockopt_args);
299	/* Copy back the return value from socket() */
300	p->p_retval[0] = bsd_setsockopt_args.s;
301    }
302    return retval_socket;
303}
304
305struct linux_bind_args {
306    int s;
307    struct sockaddr *name;
308    int namelen;
309};
310
311static int
312linux_bind(struct proc *p, struct linux_bind_args *args)
313{
314    struct linux_bind_args linux_args;
315    struct bind_args /* {
316	int s;
317	caddr_t name;
318	int namelen;
319    } */ bsd_args;
320    int error;
321
322    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
323	return error;
324    bsd_args.s = linux_args.s;
325    bsd_args.name = (caddr_t)linux_args.name;
326    bsd_args.namelen = linux_args.namelen;
327    return bind(p, &bsd_args);
328}
329
330struct linux_connect_args {
331    int s;
332    struct sockaddr * name;
333    int namelen;
334};
335
336static int
337linux_connect(struct proc *p, struct linux_connect_args *args)
338{
339    struct linux_connect_args linux_args;
340    struct connect_args /* {
341	int s;
342	caddr_t name;
343	int namelen;
344    } */ bsd_args;
345    int error;
346
347    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
348	return error;
349    bsd_args.s = linux_args.s;
350    bsd_args.name = (caddr_t)linux_args.name;
351    bsd_args.namelen = linux_args.namelen;
352    error = connect(p, &bsd_args);
353    if (error == EISCONN) {
354	/*
355	 * Linux doesn't return EISCONN the first time it occurs,
356	 * when on a non-blocking socket. Instead it returns the
357	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
358	 */
359	struct fcntl_args /* {
360	    int fd;
361	    int cmd;
362	    int arg;
363	} */ bsd_fcntl_args;
364	struct getsockopt_args /* {
365	    int s;
366	    int level;
367	    int name;
368	    caddr_t val;
369	    int *avalsize;
370	} */ bsd_getsockopt_args;
371	void *status, *statusl;
372	int stat, statl = sizeof stat;
373	caddr_t sg;
374
375	/* Check for non-blocking */
376	bsd_fcntl_args.fd = linux_args.s;
377	bsd_fcntl_args.cmd = F_GETFL;
378	bsd_fcntl_args.arg = 0;
379	error = fcntl(p, &bsd_fcntl_args);
380	if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) {
381	    sg = stackgap_init();
382	    status = stackgap_alloc(&sg, sizeof stat);
383	    statusl = stackgap_alloc(&sg, sizeof statusl);
384
385	    if ((error = copyout(&statl, statusl, sizeof statl)))
386		return error;
387
388	    bsd_getsockopt_args.s = linux_args.s;
389	    bsd_getsockopt_args.level = SOL_SOCKET;
390	    bsd_getsockopt_args.name = SO_ERROR;
391	    bsd_getsockopt_args.val = status;
392	    bsd_getsockopt_args.avalsize = statusl;
393
394	    error = getsockopt(p, &bsd_getsockopt_args);
395	    if (error)
396		return error;
397	    if ((error = copyin(status, &stat, sizeof stat)))
398		return error;
399	    p->p_retval[0] = stat;
400	    return 0;
401	}
402    }
403    return error;
404}
405
406struct linux_listen_args {
407    int s;
408    int backlog;
409};
410
411static int
412linux_listen(struct proc *p, struct linux_listen_args *args)
413{
414    struct linux_listen_args linux_args;
415    struct listen_args /* {
416	int s;
417	int backlog;
418    } */ bsd_args;
419    int error;
420
421    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
422	return error;
423    bsd_args.s = linux_args.s;
424    bsd_args.backlog = linux_args.backlog;
425    return listen(p, &bsd_args);
426}
427
428struct linux_accept_args {
429    int s;
430    struct sockaddr *addr;
431    int *namelen;
432};
433
434static int
435linux_accept(struct proc *p, struct linux_accept_args *args)
436{
437    struct linux_accept_args linux_args;
438    struct accept_args /* {
439	int s;
440	caddr_t name;
441	int *anamelen;
442    } */ bsd_args;
443    int error;
444
445    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
446	return error;
447    bsd_args.s = linux_args.s;
448    bsd_args.name = (caddr_t)linux_args.addr;
449    bsd_args.anamelen = linux_args.namelen;
450    return oaccept(p, &bsd_args);
451}
452
453struct linux_getsockname_args {
454    int s;
455    struct sockaddr *addr;
456    int *namelen;
457};
458
459static int
460linux_getsockname(struct proc *p, struct linux_getsockname_args *args)
461{
462    struct linux_getsockname_args linux_args;
463    struct getsockname_args /* {
464	int fdes;
465	caddr_t asa;
466	int *alen;
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.fdes = linux_args.s;
473    bsd_args.asa = (caddr_t) linux_args.addr;
474    bsd_args.alen = linux_args.namelen;
475    return ogetsockname(p, &bsd_args);
476}
477
478struct linux_getpeername_args {
479    int s;
480    struct sockaddr *addr;
481    int *namelen;
482};
483
484static int
485linux_getpeername(struct proc *p, struct linux_getpeername_args *args)
486{
487    struct linux_getpeername_args linux_args;
488    struct ogetpeername_args /* {
489	int fdes;
490	caddr_t asa;
491	int *alen;
492    } */ bsd_args;
493    int error;
494
495    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
496	return error;
497    bsd_args.fdes = linux_args.s;
498    bsd_args.asa = (caddr_t) linux_args.addr;
499    bsd_args.alen = linux_args.namelen;
500    return ogetpeername(p, &bsd_args);
501}
502
503struct linux_socketpair_args {
504    int domain;
505    int type;
506    int protocol;
507    int *rsv;
508};
509
510static int
511linux_socketpair(struct proc *p, struct linux_socketpair_args *args)
512{
513    struct linux_socketpair_args linux_args;
514    struct socketpair_args /* {
515	int domain;
516	int type;
517	int protocol;
518	int *rsv;
519    } */ bsd_args;
520    int error;
521
522    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
523	return error;
524    bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
525    if (bsd_args.domain == -1)
526	return EINVAL;
527    bsd_args.type = linux_args.type;
528    bsd_args.protocol = linux_args.protocol;
529    bsd_args.rsv = linux_args.rsv;
530    return socketpair(p, &bsd_args);
531}
532
533struct linux_send_args {
534    int s;
535    void *msg;
536    int len;
537    int flags;
538};
539
540static int
541linux_send(struct proc *p, struct linux_send_args *args)
542{
543    struct linux_send_args linux_args;
544    struct osend_args /* {
545	int s;
546	caddr_t buf;
547	int len;
548	int flags;
549    } */ bsd_args;
550    int error;
551
552    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
553	return error;
554    bsd_args.s = linux_args.s;
555    bsd_args.buf = linux_args.msg;
556    bsd_args.len = linux_args.len;
557    bsd_args.flags = linux_args.flags;
558    return osend(p, &bsd_args);
559}
560
561struct linux_recv_args {
562    int s;
563    void *msg;
564    int len;
565    int flags;
566};
567
568static int
569linux_recv(struct proc *p, struct linux_recv_args *args)
570{
571    struct linux_recv_args linux_args;
572    struct orecv_args /* {
573	int s;
574	caddr_t buf;
575	int len;
576	int flags;
577    } */ bsd_args;
578    int error;
579
580    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
581	return error;
582    bsd_args.s = linux_args.s;
583    bsd_args.buf = linux_args.msg;
584    bsd_args.len = linux_args.len;
585    bsd_args.flags = linux_args.flags;
586    return orecv(p, &bsd_args);
587}
588
589struct linux_sendto_args {
590    int s;
591    void *msg;
592    int len;
593    int flags;
594    caddr_t to;
595    int tolen;
596};
597
598static int
599linux_sendto(struct proc *p, struct linux_sendto_args *args)
600{
601    struct linux_sendto_args linux_args;
602    struct sendto_args /* {
603	int s;
604	caddr_t buf;
605	size_t len;
606	int flags;
607	caddr_t to;
608	int tolen;
609    } */ bsd_args;
610    int error;
611
612    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
613	return error;
614    bsd_args.s = linux_args.s;
615    bsd_args.buf = linux_args.msg;
616    bsd_args.len = linux_args.len;
617    bsd_args.flags = linux_args.flags;
618    bsd_args.to = linux_args.to;
619    bsd_args.tolen = linux_args.tolen;
620
621    if (linux_check_hdrincl(p, linux_args.s) == 0)
622	/* IP_HDRINCL set, tweak the packet before sending */
623	return linux_sendto_hdrincl(p, &bsd_args);
624
625    return sendto(p, &bsd_args);
626}
627
628struct linux_recvfrom_args {
629    int s;
630    void *buf;
631    int len;
632    int flags;
633    caddr_t from;
634    int *fromlen;
635};
636
637static int
638linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args)
639{
640    struct linux_recvfrom_args linux_args;
641    struct recvfrom_args /* {
642	int s;
643	caddr_t buf;
644	size_t len;
645	int flags;
646	caddr_t from;
647	int *fromlenaddr;
648    } */ bsd_args;
649    int error;
650
651    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
652	return error;
653    bsd_args.s = linux_args.s;
654    bsd_args.buf = linux_args.buf;
655    bsd_args.len = linux_args.len;
656    bsd_args.flags = linux_args.flags;
657    bsd_args.from = linux_args.from;
658    bsd_args.fromlenaddr = linux_args.fromlen;
659    return orecvfrom(p, &bsd_args);
660}
661
662struct linux_shutdown_args {
663    int s;
664    int how;
665};
666
667static int
668linux_shutdown(struct proc *p, struct linux_shutdown_args *args)
669{
670    struct linux_shutdown_args linux_args;
671    struct shutdown_args /* {
672	int s;
673	int how;
674    } */ bsd_args;
675    int error;
676
677    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
678	return error;
679    bsd_args.s = linux_args.s;
680    bsd_args.how = linux_args.how;
681    return shutdown(p, &bsd_args);
682}
683
684struct linux_setsockopt_args {
685    int s;
686    int level;
687    int optname;
688    void *optval;
689    int optlen;
690};
691
692static int
693linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args)
694{
695    struct linux_setsockopt_args linux_args;
696    struct setsockopt_args /* {
697	int s;
698	int level;
699	int name;
700	caddr_t val;
701	int valsize;
702    } */ bsd_args;
703    int error, name;
704
705    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
706	return error;
707    bsd_args.s = linux_args.s;
708    bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
709    switch (bsd_args.level) {
710    case SOL_SOCKET:
711	name = linux_to_bsd_so_sockopt(linux_args.optname);
712	break;
713    case IPPROTO_IP:
714	name = linux_to_bsd_ip_sockopt(linux_args.optname);
715	break;
716    case IPPROTO_TCP:
717	/* Linux TCP option values match BSD's */
718	name = linux_args.optname;
719	break;
720    default:
721	return EINVAL;
722    }
723    if (name == -1)
724	return EINVAL;
725    bsd_args.name = name;
726    bsd_args.val = linux_args.optval;
727    bsd_args.valsize = linux_args.optlen;
728    return setsockopt(p, &bsd_args);
729}
730
731struct linux_getsockopt_args {
732    int s;
733    int level;
734    int optname;
735    void *optval;
736    int *optlen;
737};
738
739static int
740linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args)
741{
742    struct linux_getsockopt_args linux_args;
743    struct getsockopt_args /* {
744	int s;
745	int level;
746	int name;
747	caddr_t val;
748	int *avalsize;
749    } */ bsd_args;
750    int error, name;
751
752    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
753	return error;
754    bsd_args.s = linux_args.s;
755    bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
756    switch (bsd_args.level) {
757    case SOL_SOCKET:
758	name = linux_to_bsd_so_sockopt(linux_args.optname);
759	break;
760    case IPPROTO_IP:
761	name = linux_to_bsd_ip_sockopt(linux_args.optname);
762	break;
763    case IPPROTO_TCP:
764	/* Linux TCP option values match BSD's */
765	name = linux_args.optname;
766	break;
767    default:
768	return EINVAL;
769    }
770    if (name == -1)
771	return EINVAL;
772    bsd_args.name = name;
773    bsd_args.val = linux_args.optval;
774    bsd_args.avalsize = linux_args.optlen;
775    return getsockopt(p, &bsd_args);
776}
777
778int
779linux_socketcall(struct proc *p, struct linux_socketcall_args *args)
780{
781    switch (args->what) {
782    case LINUX_SOCKET:
783	return linux_socket(p, args->args);
784    case LINUX_BIND:
785	return linux_bind(p, args->args);
786    case LINUX_CONNECT:
787	return linux_connect(p, args->args);
788    case LINUX_LISTEN:
789	return linux_listen(p, args->args);
790    case LINUX_ACCEPT:
791	return linux_accept(p, args->args);
792    case LINUX_GETSOCKNAME:
793	return linux_getsockname(p, args->args);
794    case LINUX_GETPEERNAME:
795	return linux_getpeername(p, args->args);
796    case LINUX_SOCKETPAIR:
797	return linux_socketpair(p, args->args);
798    case LINUX_SEND:
799	return linux_send(p, args->args);
800    case LINUX_RECV:
801	return linux_recv(p, args->args);
802    case LINUX_SENDTO:
803	return linux_sendto(p, args->args);
804    case LINUX_RECVFROM:
805	return linux_recvfrom(p, args->args);
806    case LINUX_SHUTDOWN:
807	return linux_shutdown(p, args->args);
808    case LINUX_SETSOCKOPT:
809	return linux_setsockopt(p, args->args);
810    case LINUX_GETSOCKOPT:
811	return linux_getsockopt(p, args->args);
812    default:
813	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
814	return ENOSYS;
815    }
816}
817