linux_socket.c revision 181803
1183000Smav/*-
2183000Smav * Copyright (c) 1995 S�ren Schmidt
3162924Sjoel * All rights reserved.
4162924Sjoel *
5162924Sjoel * Redistribution and use in source and binary forms, with or without
6162924Sjoel * modification, are permitted provided that the following conditions
7162924Sjoel * are met:
8162924Sjoel * 1. Redistributions of source code must retain the above copyright
9162924Sjoel *    notice, this list of conditions and the following disclaimer
10162924Sjoel *    in this position and unchanged.
11162924Sjoel * 2. Redistributions in binary form must reproduce the above copyright
12162924Sjoel *    notice, this list of conditions and the following disclaimer in the
13162924Sjoel *    documentation and/or other materials provided with the distribution.
14162924Sjoel * 3. The name of the author may not be used to endorse or promote products
15162924Sjoel *    derived from this software without specific prior written permission
16162924Sjoel *
17162924Sjoel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18162924Sjoel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19162924Sjoel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20162924Sjoel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21162924Sjoel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22162924Sjoel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23162924Sjoel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24162924Sjoel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25162924Sjoel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26162924Sjoel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27162924Sjoel */
28230551Smav
29162924Sjoel#include <sys/cdefs.h>
30162924Sjoel__FBSDID("$FreeBSD: head/sys/compat/linux/linux_socket.c 181803 2008-08-17 23:27:27Z bz $");
31162924Sjoel
32162924Sjoel/* XXX we use functions that might not exist. */
33162924Sjoel#include "opt_compat.h"
34162924Sjoel#include "opt_inet6.h"
35162924Sjoel
36162924Sjoel#include <sys/param.h>
37162924Sjoel#include <sys/proc.h>
38162924Sjoel#include <sys/systm.h>
39162924Sjoel#include <sys/sysproto.h>
40162924Sjoel#include <sys/fcntl.h>
41162924Sjoel#include <sys/file.h>
42162924Sjoel#include <sys/limits.h>
43162924Sjoel#include <sys/lock.h>
44162924Sjoel#include <sys/malloc.h>
45162924Sjoel#include <sys/mutex.h>
46162924Sjoel#include <sys/mbuf.h>
47162924Sjoel#include <sys/socket.h>
48162924Sjoel#include <sys/socketvar.h>
49183000Smav#include <sys/syscallsubr.h>
50183000Smav#include <sys/uio.h>
51183000Smav#include <sys/syslog.h>
52183000Smav#include <sys/un.h>
53183000Smav#include <sys/vimage.h>
54162924Sjoel
55162924Sjoel#include <netinet/in.h>
56230130Smav#include <netinet/in_systm.h>
57230130Smav#include <netinet/ip.h>
58230130Smav#ifdef INET6
59162924Sjoel#include <netinet/ip6.h>
60183000Smav#include <netinet6/ip6_var.h>
61184738Smav#endif
62184751Smav
63199247Smav#ifdef COMPAT_LINUX32
64183000Smav#include <machine/../linux32/linux.h>
65162924Sjoel#include <machine/../linux32/linux32_proto.h>
66162924Sjoel#else
67162924Sjoel#include <machine/../linux/linux.h>
68162924Sjoel#include <machine/../linux/linux_proto.h>
69162924Sjoel#endif
70162924Sjoel#include <compat/linux/linux_socket.h>
71183000Smav#include <compat/linux/linux_util.h>
72184738Smav
73183000Smavstatic int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
74183016Sjoel    struct malloc_type *);
75162924Sjoelstatic int linux_to_bsd_domain(int);
76183016Sjoel
77183016Sjoel/*
78183016Sjoel * Reads a linux sockaddr and does any necessary translation.
79183016Sjoel * Linux sockaddrs don't have a length field, only a family.
80184738Smav */
81230130Smavstatic int
82230130Smavlinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
83230130Smav{
84184738Smav	int osalen = len;
85184738Smav
86183564Smav	return (do_sa_get(sap, osa, &osalen, M_SONAME));
87184738Smav}
88184738Smav
89184738Smav/*
90184738Smav * Copy the osockaddr structure pointed to by osa to kernel, adjust
91184751Smav * family and convert to sockaddr.
92166070Sjoel */
93166070Sjoelstatic int
94166070Sjoeldo_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
95166070Sjoel    struct malloc_type *mtype)
96183000Smav{
97183000Smav	int error=0, bdom;
98230130Smav	struct sockaddr *sa;
99166070Sjoel	struct osockaddr *kosa;
100230130Smav	int alloclen;
101169279Sjoel#ifdef INET6
102230130Smav	int oldv6size;
103230130Smav	struct sockaddr_in6 *sin6;
104230130Smav#endif
105230130Smav
106230130Smav	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
107230130Smav		return (EINVAL);
108230130Smav
109230130Smav	alloclen = *osalen;
110230130Smav#ifdef INET6
111230130Smav	oldv6size = 0;
112230130Smav	/*
113230130Smav	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
114230130Smav	 * if it's a v4-mapped address, so reserve the proper space
115230130Smav	 * for it.
116230130Smav	 */
117169279Sjoel	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
118169279Sjoel		alloclen = sizeof (struct sockaddr_in6);
119169279Sjoel		oldv6size = 1;
120169279Sjoel	}
121169279Sjoel#endif
122166070Sjoel
123166070Sjoel	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
124169279Sjoel
125169279Sjoel	if ((error = copyin(osa, kosa, *osalen)))
126169279Sjoel		goto out;
127169279Sjoel
128183000Smav	bdom = linux_to_bsd_domain(kosa->sa_family);
129166070Sjoel	if (bdom == -1) {
130166070Sjoel		error = EINVAL;
131166070Sjoel		goto out;
132166070Sjoel	}
133166070Sjoel
134166070Sjoel#ifdef INET6
135166094Sjoel	/*
136166070Sjoel	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
137166070Sjoel	 * which lacks the scope id compared with RFC2553 one. If we detect
138202160Smav	 * the situation, reject the address and write a message to system log.
139230130Smav	 *
140230130Smav	 * Still accept addresses for which the scope id is not used.
141230130Smav	 */
142230130Smav	if (oldv6size && bdom == AF_INET6) {
143230130Smav		sin6 = (struct sockaddr_in6 *)kosa;
144230130Smav		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
145230130Smav		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
146230130Smav		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
147230130Smav		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
148230130Smav		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
149230130Smav		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
150230130Smav			sin6->sin6_scope_id = 0;
151230130Smav		} else {
152230130Smav			log(LOG_DEBUG,
153230130Smav			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
154230130Smav			error = EINVAL;
155230130Smav			goto out;
156230130Smav		}
157230130Smav	} else
158230130Smav#endif
159230130Smav	if (bdom == AF_INET)
160230130Smav		alloclen = sizeof(struct sockaddr_in);
161230130Smav
162230130Smav	sa = (struct sockaddr *) kosa;
163230130Smav	sa->sa_family = bdom;
164230130Smav	sa->sa_len = alloclen;
165230130Smav
166230130Smav	*sap = sa;
167230130Smav	*osalen = alloclen;
168230130Smav	return (0);
169230130Smav
170230130Smavout:
171230130Smav	FREE(kosa, mtype);
172184738Smav	return (error);
173184738Smav}
174183000Smav
175184738Smavstatic int
176184738Smavlinux_to_bsd_domain(int domain)
177184738Smav{
178230130Smav
179230130Smav	switch (domain) {
180184738Smav	case LINUX_AF_UNSPEC:
181184738Smav		return (AF_UNSPEC);
182184738Smav	case LINUX_AF_UNIX:
183184738Smav		return (AF_LOCAL);
184184738Smav	case LINUX_AF_INET:
185230551Smav		return (AF_INET);
186230551Smav	case LINUX_AF_INET6:
187236443Sjoel		return (AF_INET6);
188230551Smav	case LINUX_AF_AX25:
189230551Smav		return (AF_CCITT);
190230551Smav	case LINUX_AF_IPX:
191230551Smav		return (AF_IPX);
192230551Smav	case LINUX_AF_APPLETALK:
193230551Smav		return (AF_APPLETALK);
194166070Sjoel	}
195230551Smav	return (-1);
196230551Smav}
197230551Smav
198183000Smavstatic int
199183000Smavbsd_to_linux_domain(int domain)
200183000Smav{
201183000Smav
202183000Smav	switch (domain) {
203183000Smav	case AF_UNSPEC:
204183000Smav		return (LINUX_AF_UNSPEC);
205184738Smav	case AF_LOCAL:
206184738Smav		return (LINUX_AF_UNIX);
207184738Smav	case AF_INET:
208184738Smav		return (LINUX_AF_INET);
209184738Smav	case AF_INET6:
210183000Smav		return (LINUX_AF_INET6);
211183000Smav	case AF_CCITT:
212183000Smav		return (LINUX_AF_AX25);
213184738Smav	case AF_IPX:
214183000Smav		return (LINUX_AF_IPX);
215230130Smav	case AF_APPLETALK:
216183000Smav		return (LINUX_AF_APPLETALK);
217184738Smav	}
218184738Smav	return (-1);
219184738Smav}
220184738Smav
221184738Smavstatic int
222184738Smavlinux_to_bsd_sockopt_level(int level)
223184738Smav{
224183000Smav
225183000Smav	switch (level) {
226184738Smav	case LINUX_SOL_SOCKET:
227184738Smav		return (SOL_SOCKET);
228184738Smav	}
229184738Smav	return (level);
230184738Smav}
231184738Smav
232184738Smavstatic int
233184738Smavbsd_to_linux_sockopt_level(int level)
234184738Smav{
235230130Smav
236230130Smav	switch (level) {
237230130Smav	case SOL_SOCKET:
238235317Sgjb		return (LINUX_SOL_SOCKET);
239230130Smav	}
240230130Smav	return (level);
241235317Sgjb}
242230130Smav
243230130Smavstatic int
244230130Smavlinux_to_bsd_ip_sockopt(int opt)
245230130Smav{
246183000Smav
247183000Smav	switch (opt) {
248183000Smav	case LINUX_IP_TOS:
249183000Smav		return (IP_TOS);
250183000Smav	case LINUX_IP_TTL:
251183000Smav		return (IP_TTL);
252183000Smav	case LINUX_IP_OPTIONS:
253183000Smav		return (IP_OPTIONS);
254183000Smav	case LINUX_IP_MULTICAST_IF:
255183000Smav		return (IP_MULTICAST_IF);
256183000Smav	case LINUX_IP_MULTICAST_TTL:
257183000Smav		return (IP_MULTICAST_TTL);
258183000Smav	case LINUX_IP_MULTICAST_LOOP:
259183000Smav		return (IP_MULTICAST_LOOP);
260183000Smav	case LINUX_IP_ADD_MEMBERSHIP:
261183000Smav		return (IP_ADD_MEMBERSHIP);
262183000Smav	case LINUX_IP_DROP_MEMBERSHIP:
263183000Smav		return (IP_DROP_MEMBERSHIP);
264183000Smav	case LINUX_IP_HDRINCL:
265183000Smav		return (IP_HDRINCL);
266183000Smav	}
267183000Smav	return (-1);
268183000Smav}
269184738Smav
270183000Smavstatic int
271184738Smavlinux_to_bsd_so_sockopt(int opt)
272183000Smav{
273183000Smav
274184738Smav	switch (opt) {
275184738Smav	case LINUX_SO_DEBUG:
276183000Smav		return (SO_DEBUG);
277183000Smav	case LINUX_SO_REUSEADDR:
278183000Smav		return (SO_REUSEADDR);
279183000Smav	case LINUX_SO_TYPE:
280183000Smav		return (SO_TYPE);
281184738Smav	case LINUX_SO_ERROR:
282183000Smav		return (SO_ERROR);
283184738Smav	case LINUX_SO_DONTROUTE:
284183000Smav		return (SO_DONTROUTE);
285183000Smav	case LINUX_SO_BROADCAST:
286183000Smav		return (SO_BROADCAST);
287184738Smav	case LINUX_SO_SNDBUF:
288184738Smav		return (SO_SNDBUF);
289184738Smav	case LINUX_SO_RCVBUF:
290184738Smav		return (SO_RCVBUF);
291183000Smav	case LINUX_SO_KEEPALIVE:
292183000Smav		return (SO_KEEPALIVE);
293184738Smav	case LINUX_SO_OOBINLINE:
294183000Smav		return (SO_OOBINLINE);
295183000Smav	case LINUX_SO_LINGER:
296183000Smav		return (SO_LINGER);
297183000Smav	case LINUX_SO_PEERCRED:
298183000Smav		return (LOCAL_PEERCRED);
299183000Smav	case LINUX_SO_RCVLOWAT:
300183000Smav		return (SO_RCVLOWAT);
301183000Smav	case LINUX_SO_SNDLOWAT:
302183000Smav		return (SO_SNDLOWAT);
303183000Smav	case LINUX_SO_RCVTIMEO:
304183000Smav		return (SO_RCVTIMEO);
305183000Smav	case LINUX_SO_SNDTIMEO:
306183000Smav		return (SO_SNDTIMEO);
307183000Smav	case LINUX_SO_TIMESTAMP:
308183000Smav		return (SO_TIMESTAMP);
309183000Smav	case LINUX_SO_ACCEPTCONN:
310183000Smav		return (SO_ACCEPTCONN);
311184738Smav	}
312184738Smav	return (-1);
313184738Smav}
314184738Smav
315183000Smavstatic int
316183000Smavlinux_to_bsd_msg_flags(int flags)
317183000Smav{
318184738Smav	int ret_flags = 0;
319184738Smav
320184738Smav	if (flags & LINUX_MSG_OOB)
321184738Smav		ret_flags |= MSG_OOB;
322183000Smav	if (flags & LINUX_MSG_PEEK)
323183000Smav		ret_flags |= MSG_PEEK;
324183000Smav	if (flags & LINUX_MSG_DONTROUTE)
325184738Smav		ret_flags |= MSG_DONTROUTE;
326184738Smav	if (flags & LINUX_MSG_CTRUNC)
327183000Smav		ret_flags |= MSG_CTRUNC;
328164752Sjoel	if (flags & LINUX_MSG_TRUNC)
329164752Sjoel		ret_flags |= MSG_TRUNC;
330164752Sjoel	if (flags & LINUX_MSG_DONTWAIT)
331164752Sjoel		ret_flags |= MSG_DONTWAIT;
332164752Sjoel	if (flags & LINUX_MSG_EOR)
333164752Sjoel		ret_flags |= MSG_EOR;
334230130Smav	if (flags & LINUX_MSG_WAITALL)
335230130Smav		ret_flags |= MSG_WAITALL;
336230130Smav	if (flags & LINUX_MSG_NOSIGNAL)
337230130Smav		ret_flags |= MSG_NOSIGNAL;
338230130Smav#if 0 /* not handled */
339183000Smav	if (flags & LINUX_MSG_PROXY)
340184738Smav		;
341184738Smav	if (flags & LINUX_MSG_FIN)
342184738Smav		;
343183000Smav	if (flags & LINUX_MSG_SYN)
344183000Smav		;
345164752Sjoel	if (flags & LINUX_MSG_CONFIRM)
346164752Sjoel		;
347164752Sjoel	if (flags & LINUX_MSG_RST)
348230130Smav		;
349230130Smav	if (flags & LINUX_MSG_ERRQUEUE)
350230130Smav		;
351230130Smav#endif
352230130Smav	return ret_flags;
353230130Smav}
354230130Smav
355230130Smav/*
356230130Smav* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
357230130Smav* native syscall will fault.  Thus, we don't really need to check the
358230130Smav* return values for these functions.
359230130Smav*/
360230130Smav
361230130Smavstatic int
362230130Smavbsd_to_linux_sockaddr(struct sockaddr *arg)
363230130Smav{
364230130Smav	struct sockaddr sa;
365230130Smav	size_t sa_len = sizeof(struct sockaddr);
366230130Smav	int error;
367230130Smav
368230130Smav	if ((error = copyin(arg, &sa, sa_len)))
369230130Smav		return (error);
370230130Smav
371235317Sgjb	*(u_short *)&sa = sa.sa_family;
372230551Smav
373230551Smav	error = copyout(&sa, arg, sa_len);
374230551Smav
375230551Smav	return (error);
376230551Smav}
377230551Smav
378230551Smavstatic int
379230551Smavlinux_to_bsd_sockaddr(struct sockaddr *arg, int len)
380230551Smav{
381230551Smav	struct sockaddr sa;
382164752Sjoel	size_t sa_len = sizeof(struct sockaddr);
383183121Smav	int error;
384184738Smav
385184738Smav	if ((error = copyin(arg, &sa, sa_len)))
386184738Smav		return (error);
387184738Smav
388184738Smav	sa.sa_family = *(sa_family_t *)&sa;
389184738Smav	sa.sa_len = len;
390184738Smav
391183121Smav	error = copyout(&sa, arg, sa_len);
392184695Smav
393210676Sjoel	return (error);
394188512Smav}
395183121Smav
396230130Smav
397230130Smavstatic int
398230130Smavlinux_sa_put(struct osockaddr *osa)
399230130Smav{
400230130Smav	struct osockaddr sa;
401230130Smav	int error, bdom;
402230130Smav
403230130Smav	/*
404230130Smav	 * Only read/write the osockaddr family part, the rest is
405230130Smav	 * not changed.
406230130Smav	 */
407230130Smav	error = copyin(osa, &sa, sizeof(sa.sa_family));
408183121Smav	if (error)
409183121Smav		return (error);
410188512Smav
411230130Smav	bdom = bsd_to_linux_domain(sa.sa_family);
412230130Smav	if (bdom == -1)
413184695Smav		return (EINVAL);
414184695Smav
415184695Smav	sa.sa_family = bdom;
416184695Smav	error = copyout(&sa, osa, sizeof(sa.sa_family));
417184695Smav	if (error)
418184695Smav		return (error);
419183121Smav
420230130Smav	return (0);
421230130Smav}
422230130Smav
423230130Smavstatic int
424230130Smavlinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
425230130Smav    enum uio_seg segflg)
426230130Smav{
427230130Smav	struct mbuf *control;
428230130Smav	struct sockaddr *to;
429183121Smav	int error;
430183121Smav
431184738Smav	if (mp->msg_name != NULL) {
432184738Smav		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
433184738Smav		if (error)
434184738Smav			return (error);
435184738Smav		mp->msg_name = to;
436184738Smav	} else
437184738Smav		to = NULL;
438184738Smav
439184738Smav	if (mp->msg_control != NULL) {
440184738Smav		struct cmsghdr *cmsg;
441184738Smav
442184738Smav		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
443184738Smav			error = EINVAL;
444184738Smav			goto bad;
445184738Smav		}
446184738Smav		error = sockargs(&control, mp->msg_control,
447184738Smav		    mp->msg_controllen, MT_CONTROL);
448184738Smav		if (error)
449184738Smav			goto bad;
450184738Smav
451184738Smav		cmsg = mtod(control, struct cmsghdr *);
452184695Smav		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
453184738Smav	} else
454184738Smav		control = NULL;
455184738Smav
456184738Smav	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
457184695Smav	    segflg);
458184738Smav
459184738Smavbad:
460184738Smav	if (to)
461184738Smav		FREE(to, M_SONAME);
462184738Smav	return (error);
463184738Smav}
464183121Smav
465184738Smav/* Return 0 if IP_HDRINCL is set for the given socket. */
466184738Smavstatic int
467184738Smavlinux_check_hdrincl(struct thread *td, int s)
468183121Smav{
469183121Smav	int error, optval, size_val;
470183121Smav
471183121Smav	size_val = sizeof(optval);
472183121Smav	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
473184738Smav	    &optval, UIO_SYSSPACE, &size_val);
474184738Smav	if (error)
475184738Smav		return (error);
476184738Smav
477184738Smav	return (optval == 0);
478184738Smav}
479184738Smav
480184738Smavstruct linux_sendto_args {
481184738Smav	int s;
482184738Smav	l_uintptr_t msg;
483183121Smav	int len;
484184738Smav	int flags;
485184738Smav	l_uintptr_t to;
486184738Smav	int tolen;
487183121Smav};
488183121Smav
489183121Smav/*
490183121Smav * Updated sendto() when IP_HDRINCL is set:
491183121Smav * tweak endian-dependent fields in the IP packet.
492183121Smav */
493184738Smavstatic int
494184738Smavlinux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
495184738Smav{
496184738Smav/*
497184738Smav * linux_ip_copysize defines how many bytes we should copy
498184738Smav * from the beginning of the IP packet before we customize it for BSD.
499184738Smav * It should include all the fields we modify (ip_len and ip_off).
500184738Smav */
501184738Smav#define linux_ip_copysize	8
502184738Smav
503184738Smav	struct ip *packet;
504184738Smav	struct msghdr msg;
505183121Smav	struct iovec aiov[1];
506184738Smav	int error;
507184738Smav
508184738Smav	/* Check that the packet isn't too big or too small. */
509183121Smav	if (linux_args->len < linux_ip_copysize ||
510183121Smav	    linux_args->len > IP_MAXPACKET)
511183121Smav		return (EINVAL);
512183121Smav
513183121Smav	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
514183121Smav
515183121Smav	/* Make kernel copy of the packet to be sent */
516183121Smav	if ((error = copyin(PTRIN(linux_args->msg), packet,
517183121Smav	    linux_args->len)))
518184738Smav		goto goout;
519184738Smav
520184738Smav	/* Convert fields from Linux to BSD raw IP socket format */
521184738Smav	packet->ip_len = linux_args->len;
522184738Smav	packet->ip_off = ntohs(packet->ip_off);
523184738Smav
524184738Smav	/* Prepare the msghdr and iovec structures describing the new packet */
525184738Smav	msg.msg_name = PTRIN(linux_args->to);
526184738Smav	msg.msg_namelen = linux_args->tolen;
527184738Smav	msg.msg_iov = aiov;
528183121Smav	msg.msg_iovlen = 1;
529184738Smav	msg.msg_control = NULL;
530184738Smav	msg.msg_flags = 0;
531184738Smav	aiov[0].iov_base = (char *)packet;
532183121Smav	aiov[0].iov_len = linux_args->len;
533183121Smav	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
534183121Smav	    UIO_SYSSPACE);
535183121Smavgoout:
536183121Smav	free(packet, M_TEMP);
537183121Smav	return (error);
538183121Smav}
539184738Smav
540184738Smavstruct linux_socket_args {
541184738Smav	int domain;
542184738Smav	int type;
543184738Smav	int protocol;
544184738Smav};
545184738Smav
546202798Smavstatic int
547202798Smavlinux_socket(struct thread *td, struct linux_socket_args *args)
548202798Smav{
549202798Smav	struct linux_socket_args linux_args;
550202798Smav	struct socket_args /* {
551202798Smav		int domain;
552202798Smav		int type;
553202798Smav		int protocol;
554202798Smav	} */ bsd_args;
555202798Smav	int error;
556202798Smav	int retval_socket;
557202798Smav
558202798Smav	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
559202798Smav		return (error);
560202798Smav
561202798Smav	bsd_args.protocol = linux_args.protocol;
562202798Smav	bsd_args.type = linux_args.type;
563202798Smav	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
564202798Smav	if (bsd_args.domain == -1)
565202798Smav		return (EINVAL);
566202798Smav
567202798Smav	retval_socket = socket(td, &bsd_args);
568202798Smav	if (bsd_args.type == SOCK_RAW
569202798Smav	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
570202798Smav	    && bsd_args.domain == AF_INET
571202798Smav	    && retval_socket >= 0) {
572202798Smav		/* It's a raw IP socket: set the IP_HDRINCL option. */
573202798Smav		int hdrincl;
574202798Smav
575202798Smav		hdrincl = 1;
576202798Smav		/* We ignore any error returned by kern_setsockopt() */
577202798Smav		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
578202798Smav		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
579202798Smav	}
580202798Smav#ifdef INET6
581162924Sjoel	/*
582162924Sjoel	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
583162924Sjoel	 * default and some apps depend on this. So, set V6ONLY to 0
584230130Smav	 * for Linux apps if the sysctl value is set to 1.
585230130Smav	 */
586162924Sjoel	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
587230130Smav#ifndef KLD_MODULE
588230130Smav	    /*
589235317Sgjb	     * XXX: Avoid undefined symbol error with an IPv4 only
590230130Smav	     * kernel.
591230130Smav	     */
592162924Sjoel	    && V_ip6_v6only
593162924Sjoel#endif
594186810Smav	    ) {
595166070Sjoel		int v6only;
596166070Sjoel
597166070Sjoel		v6only = 0;
598162924Sjoel		/* We ignore any error returned by setsockopt() */
599162924Sjoel		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
600162924Sjoel		    &v6only, UIO_SYSSPACE, sizeof(v6only));
601162924Sjoel	}
602175084Sgabor#endif
603162924Sjoel
604162924Sjoel	return (retval_socket);
605162924Sjoel}
606162924Sjoel
607162924Sjoelstruct linux_bind_args {
608183000Smav	int s;
609183000Smav	l_uintptr_t name;
610162924Sjoel	int namelen;
611183000Smav};
612162924Sjoel
613184738Smavstatic int
614184738Smavlinux_bind(struct thread *td, struct linux_bind_args *args)
615183000Smav{
616184738Smav	struct linux_bind_args linux_args;
617162924Sjoel	struct sockaddr *sa;
618230130Smav	int error;
619230130Smav
620230130Smav	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
621162924Sjoel		return (error);
622223160Sbcr
623223160Sbcr	error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
624223160Sbcr	    linux_args.namelen);
625223160Sbcr	if (error)
626230130Smav		return (error);
627230130Smav
628230130Smav	error = kern_bind(td, linux_args.s, sa);
629183121Smav	free(sa, M_SONAME);
630223160Sbcr	if (error == EADDRNOTAVAIL && linux_args.namelen != sizeof(struct sockaddr_in))
631223160Sbcr	   	return (EINVAL);
632223160Sbcr	return (error);
633223160Sbcr}
634199247Smav
635199247Smavstruct linux_connect_args {
636	int s;
637	l_uintptr_t name;
638	int namelen;
639};
640int linux_connect(struct thread *, struct linux_connect_args *);
641
642int
643linux_connect(struct thread *td, struct linux_connect_args *args)
644{
645	struct linux_connect_args linux_args;
646	struct socket *so;
647	struct sockaddr *sa;
648	u_int fflag;
649	int error;
650
651	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
652		return (error);
653
654	error = linux_getsockaddr(&sa,
655	    (struct osockaddr *)PTRIN(linux_args.name),
656	    linux_args.namelen);
657	if (error)
658		return (error);
659
660	error = kern_connect(td, linux_args.s, sa);
661	free(sa, M_SONAME);
662	if (error != EISCONN)
663		return (error);
664
665	/*
666	 * Linux doesn't return EISCONN the first time it occurs,
667	 * when on a non-blocking socket. Instead it returns the
668	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
669	 *
670	 * XXXRW: Instead of using fgetsock(), check that it is a
671	 * socket and use the file descriptor reference instead of
672	 * creating a new one.
673	 */
674	error = fgetsock(td, linux_args.s, &so, &fflag);
675	if (error == 0) {
676		error = EISCONN;
677		if (fflag & FNONBLOCK) {
678			SOCK_LOCK(so);
679			if (so->so_emuldata == 0)
680				error = so->so_error;
681			so->so_emuldata = (void *)1;
682			SOCK_UNLOCK(so);
683		}
684		fputsock(so);
685	}
686	return (error);
687}
688
689struct linux_listen_args {
690	int s;
691	int backlog;
692};
693
694static int
695linux_listen(struct thread *td, struct linux_listen_args *args)
696{
697	struct linux_listen_args linux_args;
698	struct listen_args /* {
699		int s;
700		int backlog;
701	} */ bsd_args;
702	int error;
703
704	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
705		return (error);
706
707	bsd_args.s = linux_args.s;
708	bsd_args.backlog = linux_args.backlog;
709	return (listen(td, &bsd_args));
710}
711
712struct linux_accept_args {
713	int s;
714	l_uintptr_t addr;
715	l_uintptr_t namelen;
716};
717
718static int
719linux_accept(struct thread *td, struct linux_accept_args *args)
720{
721	struct linux_accept_args linux_args;
722	struct accept_args /* {
723		int	s;
724		struct sockaddr * __restrict name;
725		socklen_t * __restrict anamelen;
726	} */ bsd_args;
727	int error, fd;
728
729	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
730		return (error);
731
732	bsd_args.s = linux_args.s;
733	/* XXX: */
734	bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
735	bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
736	error = accept(td, &bsd_args);
737	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
738	if (error) {
739	   	if (error == EFAULT && linux_args.namelen != sizeof(struct sockaddr_in))
740		   	return (EINVAL);
741		return (error);
742	}
743	if (linux_args.addr) {
744		error = linux_sa_put(PTRIN(linux_args.addr));
745		if (error) {
746			(void)kern_close(td, td->td_retval[0]);
747			return (error);
748		}
749	}
750
751	/*
752	 * linux appears not to copy flags from the parent socket to the
753	 * accepted one, so we must clear the flags in the new descriptor.
754	 * Ignore any errors, because we already have an open fd.
755	 */
756	fd = td->td_retval[0];
757	(void)kern_fcntl(td, fd, F_SETFL, 0);
758	td->td_retval[0] = fd;
759	return (0);
760}
761
762struct linux_getsockname_args {
763	int s;
764	l_uintptr_t addr;
765	l_uintptr_t namelen;
766};
767
768static int
769linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
770{
771	struct linux_getsockname_args linux_args;
772	struct getsockname_args /* {
773		int	fdes;
774		struct sockaddr * __restrict asa;
775		socklen_t * __restrict alen;
776	} */ bsd_args;
777	int error;
778
779	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
780		return (error);
781
782	bsd_args.fdes = linux_args.s;
783	/* XXX: */
784	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
785	bsd_args.alen = PTRIN(linux_args.namelen);	/* XXX */
786	error = getsockname(td, &bsd_args);
787	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
788	if (error)
789		return (error);
790	error = linux_sa_put(PTRIN(linux_args.addr));
791	if (error)
792		return (error);
793	return (0);
794}
795
796struct linux_getpeername_args {
797	int s;
798	l_uintptr_t addr;
799	l_uintptr_t namelen;
800};
801
802static int
803linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
804{
805	struct linux_getpeername_args linux_args;
806	struct getpeername_args /* {
807		int fdes;
808		caddr_t asa;
809		int *alen;
810	} */ bsd_args;
811	int error;
812
813	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
814		return (error);
815
816	bsd_args.fdes = linux_args.s;
817	bsd_args.asa = (struct sockaddr *)PTRIN(linux_args.addr);
818	bsd_args.alen = (int *)PTRIN(linux_args.namelen);
819	error = getpeername(td, &bsd_args);
820	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
821	if (error)
822		return (error);
823	error = linux_sa_put(PTRIN(linux_args.addr));
824	if (error)
825		return (error);
826	return (0);
827}
828
829struct linux_socketpair_args {
830	int domain;
831	int type;
832	int protocol;
833	l_uintptr_t rsv;
834};
835
836static int
837linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
838{
839	struct linux_socketpair_args linux_args;
840	struct socketpair_args /* {
841		int domain;
842		int type;
843		int protocol;
844		int *rsv;
845	} */ bsd_args;
846	int error;
847
848	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
849		return (error);
850
851	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
852	if (bsd_args.domain == -1)
853		return (EINVAL);
854
855	bsd_args.type = linux_args.type;
856	bsd_args.protocol = linux_args.protocol;
857	bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
858	return (socketpair(td, &bsd_args));
859}
860
861struct linux_send_args {
862	int s;
863	l_uintptr_t msg;
864	int len;
865	int flags;
866};
867
868static int
869linux_send(struct thread *td, struct linux_send_args *args)
870{
871	struct linux_send_args linux_args;
872	struct sendto_args /* {
873		int s;
874		caddr_t buf;
875		int len;
876		int flags;
877		caddr_t to;
878		int tolen;
879	} */ bsd_args;
880	int error;
881
882	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
883		return (error);
884
885	bsd_args.s = linux_args.s;
886	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
887	bsd_args.len = linux_args.len;
888	bsd_args.flags = linux_args.flags;
889	bsd_args.to = NULL;
890	bsd_args.tolen = 0;
891	return sendto(td, &bsd_args);
892}
893
894struct linux_recv_args {
895	int s;
896	l_uintptr_t msg;
897	int len;
898	int flags;
899};
900
901static int
902linux_recv(struct thread *td, struct linux_recv_args *args)
903{
904	struct linux_recv_args linux_args;
905	struct recvfrom_args /* {
906		int s;
907		caddr_t buf;
908		int len;
909		int flags;
910		struct sockaddr *from;
911		socklen_t fromlenaddr;
912	} */ bsd_args;
913	int error;
914
915	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
916		return (error);
917
918	bsd_args.s = linux_args.s;
919	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
920	bsd_args.len = linux_args.len;
921	bsd_args.flags = linux_args.flags;
922	bsd_args.from = NULL;
923	bsd_args.fromlenaddr = 0;
924	return (recvfrom(td, &bsd_args));
925}
926
927static int
928linux_sendto(struct thread *td, struct linux_sendto_args *args)
929{
930	struct linux_sendto_args linux_args;
931	struct msghdr msg;
932	struct iovec aiov;
933	int error;
934
935	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
936		return (error);
937
938	if (linux_check_hdrincl(td, linux_args.s) == 0)
939		/* IP_HDRINCL set, tweak the packet before sending */
940		return (linux_sendto_hdrincl(td, &linux_args));
941
942	msg.msg_name = PTRIN(linux_args.to);
943	msg.msg_namelen = linux_args.tolen;
944	msg.msg_iov = &aiov;
945	msg.msg_iovlen = 1;
946	msg.msg_control = NULL;
947	msg.msg_flags = 0;
948	aiov.iov_base = PTRIN(linux_args.msg);
949	aiov.iov_len = linux_args.len;
950	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
951	    UIO_USERSPACE);
952	return (error);
953}
954
955struct linux_recvfrom_args {
956	int s;
957	l_uintptr_t buf;
958	int len;
959	int flags;
960	l_uintptr_t from;
961	l_uintptr_t fromlen;
962};
963
964static int
965linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
966{
967	struct linux_recvfrom_args linux_args;
968	struct recvfrom_args /* {
969		int	s;
970		caddr_t	buf;
971		size_t	len;
972		int	flags;
973		struct sockaddr * __restrict from;
974		socklen_t * __restrict fromlenaddr;
975	} */ bsd_args;
976	size_t len;
977	int error;
978
979	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
980		return (error);
981
982	if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
983		return (error);
984
985	bsd_args.s = linux_args.s;
986	bsd_args.buf = PTRIN(linux_args.buf);
987	bsd_args.len = linux_args.len;
988	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
989	/* XXX: */
990	bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
991	bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
992
993	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
994	error = recvfrom(td, &bsd_args);
995	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
996
997	if (error)
998		return (error);
999	if (linux_args.from) {
1000		error = linux_sa_put((struct osockaddr *)
1001		    PTRIN(linux_args.from));
1002		if (error)
1003			return (error);
1004	}
1005	return (0);
1006}
1007
1008struct linux_sendmsg_args {
1009	int s;
1010	l_uintptr_t msg;
1011	int flags;
1012};
1013
1014static int
1015linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1016{
1017	struct linux_sendmsg_args linux_args;
1018	struct msghdr msg;
1019	struct iovec *iov;
1020	int error;
1021
1022	/* XXXTJR sendmsg is broken on amd64 */
1023
1024	error = copyin(args, &linux_args, sizeof(linux_args));
1025	if (error)
1026		return (error);
1027	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1028	if (error)
1029		return (error);
1030
1031	/*
1032	 * Some Linux applications (ping) define a non-NULL control data
1033	 * pointer, but a msg_controllen of 0, which is not allowed in the
1034	 * FreeBSD system call interface.  NULL the msg_control pointer in
1035	 * order to handle this case.  This should be checked, but allows the
1036	 * Linux ping to work.
1037	 */
1038	if (msg.msg_control != NULL && msg.msg_controllen == 0)
1039		msg.msg_control = NULL;
1040	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1041	if (error)
1042		return (error);
1043	msg.msg_iov = iov;
1044	msg.msg_flags = 0;
1045	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
1046	    UIO_USERSPACE);
1047	free(iov, M_IOV);
1048	return (error);
1049}
1050
1051struct linux_recvmsg_args {
1052	int s;
1053	l_uintptr_t msg;
1054	int flags;
1055};
1056
1057static int
1058linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1059{
1060	struct linux_recvmsg_args linux_args;
1061	struct recvmsg_args /* {
1062		int	s;
1063		struct	msghdr *msg;
1064		int	flags;
1065	} */ bsd_args;
1066	struct msghdr msg;
1067	struct cmsghdr *cmsg;
1068	int error;
1069
1070	/* XXXTJR recvmsg is broken on amd64 */
1071
1072	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1073		return (error);
1074
1075	if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg))))
1076		return (error);
1077
1078	bsd_args.s = linux_args.s;
1079	bsd_args.msg = PTRIN(linux_args.msg);
1080	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1081	if (msg.msg_name) {
1082	   	linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
1083		      msg.msg_namelen);
1084		error = recvmsg(td, &bsd_args);
1085		bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name);
1086	} else
1087	   	error = recvmsg(td, &bsd_args);
1088	if (error)
1089		return (error);
1090
1091	if (bsd_args.msg->msg_control != NULL &&
1092	    bsd_args.msg->msg_controllen > 0) {
1093		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
1094		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
1095	}
1096
1097	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1098	if (error)
1099		return (error);
1100	if (msg.msg_name && msg.msg_namelen > 2)
1101		error = linux_sa_put(msg.msg_name);
1102	return (error);
1103}
1104
1105struct linux_shutdown_args {
1106	int s;
1107	int how;
1108};
1109
1110static int
1111linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1112{
1113	struct linux_shutdown_args linux_args;
1114	struct shutdown_args /* {
1115		int s;
1116		int how;
1117	} */ bsd_args;
1118	int error;
1119
1120	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1121		return (error);
1122
1123	bsd_args.s = linux_args.s;
1124	bsd_args.how = linux_args.how;
1125	return (shutdown(td, &bsd_args));
1126}
1127
1128struct linux_setsockopt_args {
1129	int s;
1130	int level;
1131	int optname;
1132	l_uintptr_t optval;
1133	int optlen;
1134};
1135
1136static int
1137linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1138{
1139	struct linux_setsockopt_args linux_args;
1140	struct setsockopt_args /* {
1141		int s;
1142		int level;
1143		int name;
1144		caddr_t val;
1145		int valsize;
1146	} */ bsd_args;
1147	int error, name;
1148
1149	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1150		return (error);
1151
1152	bsd_args.s = linux_args.s;
1153	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1154	switch (bsd_args.level) {
1155	case SOL_SOCKET:
1156		name = linux_to_bsd_so_sockopt(linux_args.optname);
1157		break;
1158	case IPPROTO_IP:
1159		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1160		break;
1161	case IPPROTO_TCP:
1162		/* Linux TCP option values match BSD's */
1163		name = linux_args.optname;
1164		break;
1165	default:
1166		name = -1;
1167		break;
1168	}
1169	if (name == -1)
1170		return (ENOPROTOOPT);
1171
1172	bsd_args.name = name;
1173	bsd_args.val = PTRIN(linux_args.optval);
1174	bsd_args.valsize = linux_args.optlen;
1175
1176	if (name == IPV6_NEXTHOP) {
1177		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
1178			bsd_args.valsize);
1179		error = setsockopt(td, &bsd_args);
1180		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1181	} else
1182		error = setsockopt(td, &bsd_args);
1183
1184	return (error);
1185}
1186
1187struct linux_getsockopt_args {
1188	int s;
1189	int level;
1190	int optname;
1191	l_uintptr_t optval;
1192	l_uintptr_t optlen;
1193};
1194
1195static int
1196linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1197{
1198	struct linux_getsockopt_args linux_args;
1199	struct getsockopt_args /* {
1200		int s;
1201		int level;
1202		int name;
1203		caddr_t val;
1204		int *avalsize;
1205	} */ bsd_args;
1206	int error, name;
1207
1208	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1209		return (error);
1210
1211	bsd_args.s = linux_args.s;
1212	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1213	switch (bsd_args.level) {
1214	case SOL_SOCKET:
1215		name = linux_to_bsd_so_sockopt(linux_args.optname);
1216		break;
1217	case IPPROTO_IP:
1218		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1219		break;
1220	case IPPROTO_TCP:
1221		/* Linux TCP option values match BSD's */
1222		name = linux_args.optname;
1223		break;
1224	default:
1225		name = -1;
1226		break;
1227	}
1228	if (name == -1)
1229		return (EINVAL);
1230
1231	bsd_args.name = name;
1232	bsd_args.val = PTRIN(linux_args.optval);
1233	bsd_args.avalsize = PTRIN(linux_args.optlen);
1234
1235	if (name == IPV6_NEXTHOP) {
1236		error = getsockopt(td, &bsd_args);
1237		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1238	} else
1239		error = getsockopt(td, &bsd_args);
1240
1241	return (error);
1242}
1243
1244int
1245linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1246{
1247	void *arg = (void *)(intptr_t)args->args;
1248
1249	switch (args->what) {
1250	case LINUX_SOCKET:
1251		return (linux_socket(td, arg));
1252	case LINUX_BIND:
1253		return (linux_bind(td, arg));
1254	case LINUX_CONNECT:
1255		return (linux_connect(td, arg));
1256	case LINUX_LISTEN:
1257		return (linux_listen(td, arg));
1258	case LINUX_ACCEPT:
1259		return (linux_accept(td, arg));
1260	case LINUX_GETSOCKNAME:
1261		return (linux_getsockname(td, arg));
1262	case LINUX_GETPEERNAME:
1263		return (linux_getpeername(td, arg));
1264	case LINUX_SOCKETPAIR:
1265		return (linux_socketpair(td, arg));
1266	case LINUX_SEND:
1267		return (linux_send(td, arg));
1268	case LINUX_RECV:
1269		return (linux_recv(td, arg));
1270	case LINUX_SENDTO:
1271		return (linux_sendto(td, arg));
1272	case LINUX_RECVFROM:
1273		return (linux_recvfrom(td, arg));
1274	case LINUX_SHUTDOWN:
1275		return (linux_shutdown(td, arg));
1276	case LINUX_SETSOCKOPT:
1277		return (linux_setsockopt(td, arg));
1278	case LINUX_GETSOCKOPT:
1279		return (linux_getsockopt(td, arg));
1280	case LINUX_SENDMSG:
1281		return (linux_sendmsg(td, arg));
1282	case LINUX_RECVMSG:
1283		return (linux_recvmsg(td, arg));
1284	}
1285
1286	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1287	return (ENOSYS);
1288}
1289