1c21dee17SSøren Schmidt /*-
20ba1b365SEd Maste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37f2d13d6SPedro F. Giffuni *
49a14aa01SUlrich Spörlein * Copyright (c) 1995 Søren Schmidt
5c21dee17SSøren Schmidt * All rights reserved.
6c21dee17SSøren Schmidt *
7c21dee17SSøren Schmidt * Redistribution and use in source and binary forms, with or without
8c21dee17SSøren Schmidt * modification, are permitted provided that the following conditions
9c21dee17SSøren Schmidt * are met:
10c21dee17SSøren Schmidt * 1. Redistributions of source code must retain the above copyright
110ba1b365SEd Maste * notice, this list of conditions and the following disclaimer.
12c21dee17SSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright
13c21dee17SSøren Schmidt * notice, this list of conditions and the following disclaimer in the
14c21dee17SSøren Schmidt * documentation and/or other materials provided with the distribution.
15c21dee17SSøren Schmidt *
160ba1b365SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170ba1b365SEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180ba1b365SEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190ba1b365SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200ba1b365SEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210ba1b365SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220ba1b365SEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230ba1b365SEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240ba1b365SEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250ba1b365SEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260ba1b365SEd Maste * SUCH DAMAGE.
27c21dee17SSøren Schmidt */
28c21dee17SSøren Schmidt
2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h>
3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$");
3116dbc7f2SDavid E. O'Brien
321f3dad5aSBruce Evans /* XXX we use functions that might not exist. */
33aefce619SRuslan Ermilov #include "opt_compat.h"
34ca26842eSHajimu UMEMOTO #include "opt_inet6.h"
355591b823SEivind Eklund
36c21dee17SSøren Schmidt #include <sys/param.h>
37f2477ae1SMike Smith #include <sys/proc.h>
38c21dee17SSøren Schmidt #include <sys/systm.h>
391f3dad5aSBruce Evans #include <sys/sysproto.h>
404a144410SRobert Watson #include <sys/capsicum.h>
41dad3b88aSMike Smith #include <sys/fcntl.h>
420bf301c0SJonathan Lemon #include <sys/file.h>
43104a9b7eSAlexander Kabaev #include <sys/limits.h>
444641373fSJohn Baldwin #include <sys/lock.h>
45ca26842eSHajimu UMEMOTO #include <sys/malloc.h>
464641373fSJohn Baldwin #include <sys/mutex.h>
475a8a13e0SDavid Malone #include <sys/mbuf.h>
48c21dee17SSøren Schmidt #include <sys/socket.h>
490bf301c0SJonathan Lemon #include <sys/socketvar.h>
50ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h>
5108637435SBruce Evans #include <sys/uio.h>
52ca26842eSHajimu UMEMOTO #include <sys/syslog.h>
53d0b2365eSKonstantin Belousov #include <sys/un.h>
541f3dad5aSBruce Evans
554b79449eSBjoern A. Zeeb #include <net/if.h>
56eedc7fd9SGleb Smirnoff #include <net/vnet.h>
57c21dee17SSøren Schmidt #include <netinet/in.h>
58f2477ae1SMike Smith #include <netinet/in_systm.h>
59f2477ae1SMike Smith #include <netinet/ip.h>
60fb709557SJohn Baldwin #include <netinet/tcp.h>
61ca26842eSHajimu UMEMOTO #ifdef INET6
62ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
63ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
64ca26842eSHajimu UMEMOTO #endif
65c21dee17SSøren Schmidt
661997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
674af27623STim J. Robbins #include <machine/../linux32/linux.h>
684af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
691997c537SDavid E. O'Brien #else
701997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
711997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
724af27623STim J. Robbins #endif
734d0f380dSDmitry Chagin #include <compat/linux/linux_file.h>
7440dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
75e1ff74c0SDmitry Chagin #include <compat/linux/linux_timer.h>
76ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
77c21dee17SSøren Schmidt
78ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
79e1ff74c0SDmitry Chagin static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
80e1ff74c0SDmitry Chagin l_uint);
81e1ff74c0SDmitry Chagin static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
82e1ff74c0SDmitry Chagin l_uint, struct msghdr *);
834cf10e29SDmitry Chagin static int linux_set_socket_flags(int, int *);
84ca26842eSHajimu UMEMOTO
854730796cSBill Fenner /*
86eae594f7SEd Maste * Reads a Linux sockaddr and does any necessary translation.
87ca26842eSHajimu UMEMOTO * Linux sockaddrs don't have a length field, only a family.
88ca26842eSHajimu UMEMOTO * Copy the osockaddr structure pointed to by osa to kernel, adjust
89ca26842eSHajimu UMEMOTO * family and convert to sockaddr.
90ca26842eSHajimu UMEMOTO */
91ca26842eSHajimu UMEMOTO static int
linux_getsockaddr(struct sockaddr ** sap,const struct osockaddr * osa,int salen)92b6f96462SJung-uk Kim linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
93ca26842eSHajimu UMEMOTO {
94ca26842eSHajimu UMEMOTO struct sockaddr *sa;
95ca26842eSHajimu UMEMOTO struct osockaddr *kosa;
96ca26842eSHajimu UMEMOTO #ifdef INET6
97ca26842eSHajimu UMEMOTO struct sockaddr_in6 *sin6;
983106d670SJung-uk Kim int oldv6size;
99ca26842eSHajimu UMEMOTO #endif
100c02637c7SJung-uk Kim char *name;
101b6f96462SJung-uk Kim int bdom, error, hdrlen, namelen;
102ca26842eSHajimu UMEMOTO
103b6f96462SJung-uk Kim if (salen < 2 || salen > UCHAR_MAX || !osa)
104ca26842eSHajimu UMEMOTO return (EINVAL);
105ca26842eSHajimu UMEMOTO
106ca26842eSHajimu UMEMOTO #ifdef INET6
107ca26842eSHajimu UMEMOTO oldv6size = 0;
108ca26842eSHajimu UMEMOTO /*
109ca26842eSHajimu UMEMOTO * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
110ca26842eSHajimu UMEMOTO * if it's a v4-mapped address, so reserve the proper space
111ca26842eSHajimu UMEMOTO * for it.
112ca26842eSHajimu UMEMOTO */
113b6f96462SJung-uk Kim if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
114b6f96462SJung-uk Kim salen += sizeof(uint32_t);
115ca26842eSHajimu UMEMOTO oldv6size = 1;
116ca26842eSHajimu UMEMOTO }
117ca26842eSHajimu UMEMOTO #endif
118ca26842eSHajimu UMEMOTO
119b6f96462SJung-uk Kim kosa = malloc(salen, M_SONAME, M_WAITOK);
120ca26842eSHajimu UMEMOTO
121b6f96462SJung-uk Kim if ((error = copyin(osa, kosa, salen)))
122ca26842eSHajimu UMEMOTO goto out;
123ca26842eSHajimu UMEMOTO
124ca26842eSHajimu UMEMOTO bdom = linux_to_bsd_domain(kosa->sa_family);
125ca26842eSHajimu UMEMOTO if (bdom == -1) {
1265cb9c68cSXin LI error = EAFNOSUPPORT;
127ca26842eSHajimu UMEMOTO goto out;
128ca26842eSHajimu UMEMOTO }
129ca26842eSHajimu UMEMOTO
130ca26842eSHajimu UMEMOTO #ifdef INET6
131ca26842eSHajimu UMEMOTO /*
132ca26842eSHajimu UMEMOTO * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
133ca26842eSHajimu UMEMOTO * which lacks the scope id compared with RFC2553 one. If we detect
134ca26842eSHajimu UMEMOTO * the situation, reject the address and write a message to system log.
135ca26842eSHajimu UMEMOTO *
136ca26842eSHajimu UMEMOTO * Still accept addresses for which the scope id is not used.
137ca26842eSHajimu UMEMOTO */
138f05531a3SJung-uk Kim if (oldv6size) {
139f05531a3SJung-uk Kim if (bdom == AF_INET6) {
140ca26842eSHajimu UMEMOTO sin6 = (struct sockaddr_in6 *)kosa;
141ca26842eSHajimu UMEMOTO if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
142ca26842eSHajimu UMEMOTO (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
143ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
144ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
145ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
146ca26842eSHajimu UMEMOTO !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
147ca26842eSHajimu UMEMOTO sin6->sin6_scope_id = 0;
148ca26842eSHajimu UMEMOTO } else {
149ca26842eSHajimu UMEMOTO log(LOG_DEBUG,
1503c616032SGleb Smirnoff "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
151ca26842eSHajimu UMEMOTO error = EINVAL;
152ca26842eSHajimu UMEMOTO goto out;
153ca26842eSHajimu UMEMOTO }
154ca26842eSHajimu UMEMOTO } else
155b6f96462SJung-uk Kim salen -= sizeof(uint32_t);
156f05531a3SJung-uk Kim }
157ca26842eSHajimu UMEMOTO #endif
1585cb9c68cSXin LI if (bdom == AF_INET) {
159b6f96462SJung-uk Kim if (salen < sizeof(struct sockaddr_in)) {
1605cb9c68cSXin LI error = EINVAL;
1615cb9c68cSXin LI goto out;
1625cb9c68cSXin LI }
163b6f96462SJung-uk Kim salen = sizeof(struct sockaddr_in);
1645cb9c68cSXin LI }
165ca26842eSHajimu UMEMOTO
166b6f96462SJung-uk Kim if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
167c15cdbf2SJung-uk Kim hdrlen = offsetof(struct sockaddr_un, sun_path);
168c02637c7SJung-uk Kim name = ((struct sockaddr_un *)kosa)->sun_path;
169c02637c7SJung-uk Kim if (*name == '\0') {
170c02637c7SJung-uk Kim /*
171c02637c7SJung-uk Kim * Linux abstract namespace starts with a NULL byte.
172c02637c7SJung-uk Kim * XXX We do not support abstract namespace yet.
173c02637c7SJung-uk Kim */
174b6f96462SJung-uk Kim namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
175c02637c7SJung-uk Kim } else
176b6f96462SJung-uk Kim namelen = strnlen(name, salen - hdrlen);
177bf3a36ccSJung-uk Kim salen = hdrlen + namelen;
178bf3a36ccSJung-uk Kim if (salen > sizeof(struct sockaddr_un)) {
17943399111SJung-uk Kim error = ENAMETOOLONG;
1805da3eb94SColin Percival goto out;
1815da3eb94SColin Percival }
1825da3eb94SColin Percival }
1835da3eb94SColin Percival
184ca26842eSHajimu UMEMOTO sa = (struct sockaddr *)kosa;
185ca26842eSHajimu UMEMOTO sa->sa_family = bdom;
186b6f96462SJung-uk Kim sa->sa_len = salen;
187ca26842eSHajimu UMEMOTO
188ca26842eSHajimu UMEMOTO *sap = sa;
189ca26842eSHajimu UMEMOTO return (0);
190ca26842eSHajimu UMEMOTO
191ca26842eSHajimu UMEMOTO out:
1920007f669SJung-uk Kim free(kosa, M_SONAME);
193ca26842eSHajimu UMEMOTO return (error);
194ca26842eSHajimu UMEMOTO }
195ca26842eSHajimu UMEMOTO
196c21dee17SSøren Schmidt static int
linux_to_bsd_domain(int domain)197c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
198c21dee17SSøren Schmidt {
1993f3a4815SMarcel Moolenaar
200c21dee17SSøren Schmidt switch (domain) {
201c21dee17SSøren Schmidt case LINUX_AF_UNSPEC:
2023f3a4815SMarcel Moolenaar return (AF_UNSPEC);
203c21dee17SSøren Schmidt case LINUX_AF_UNIX:
2043f3a4815SMarcel Moolenaar return (AF_LOCAL);
205c21dee17SSøren Schmidt case LINUX_AF_INET:
2063f3a4815SMarcel Moolenaar return (AF_INET);
207ca26842eSHajimu UMEMOTO case LINUX_AF_INET6:
208ca26842eSHajimu UMEMOTO return (AF_INET6);
209c21dee17SSøren Schmidt case LINUX_AF_AX25:
2103f3a4815SMarcel Moolenaar return (AF_CCITT);
211c21dee17SSøren Schmidt case LINUX_AF_IPX:
2123f3a4815SMarcel Moolenaar return (AF_IPX);
213c21dee17SSøren Schmidt case LINUX_AF_APPLETALK:
2143f3a4815SMarcel Moolenaar return (AF_APPLETALK);
215c21dee17SSøren Schmidt }
2163f3a4815SMarcel Moolenaar return (-1);
217c21dee17SSøren Schmidt }
218c21dee17SSøren Schmidt
219ca26842eSHajimu UMEMOTO static int
bsd_to_linux_domain(int domain)220ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
221ca26842eSHajimu UMEMOTO {
222ca26842eSHajimu UMEMOTO
223ca26842eSHajimu UMEMOTO switch (domain) {
224ca26842eSHajimu UMEMOTO case AF_UNSPEC:
225ca26842eSHajimu UMEMOTO return (LINUX_AF_UNSPEC);
226ca26842eSHajimu UMEMOTO case AF_LOCAL:
227ca26842eSHajimu UMEMOTO return (LINUX_AF_UNIX);
228ca26842eSHajimu UMEMOTO case AF_INET:
229ca26842eSHajimu UMEMOTO return (LINUX_AF_INET);
230ca26842eSHajimu UMEMOTO case AF_INET6:
231ca26842eSHajimu UMEMOTO return (LINUX_AF_INET6);
232ca26842eSHajimu UMEMOTO case AF_CCITT:
233ca26842eSHajimu UMEMOTO return (LINUX_AF_AX25);
234ca26842eSHajimu UMEMOTO case AF_IPX:
235ca26842eSHajimu UMEMOTO return (LINUX_AF_IPX);
236ca26842eSHajimu UMEMOTO case AF_APPLETALK:
237ca26842eSHajimu UMEMOTO return (LINUX_AF_APPLETALK);
238ca26842eSHajimu UMEMOTO }
239ca26842eSHajimu UMEMOTO return (-1);
240ca26842eSHajimu UMEMOTO }
241ca26842eSHajimu UMEMOTO
242c21dee17SSøren Schmidt static int
linux_to_bsd_sockopt_level(int level)243c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
244c21dee17SSøren Schmidt {
2453f3a4815SMarcel Moolenaar
246c21dee17SSøren Schmidt switch (level) {
247c21dee17SSøren Schmidt case LINUX_SOL_SOCKET:
2483f3a4815SMarcel Moolenaar return (SOL_SOCKET);
249c21dee17SSøren Schmidt }
2503f3a4815SMarcel Moolenaar return (level);
251c21dee17SSøren Schmidt }
252c21dee17SSøren Schmidt
2533f3a4815SMarcel Moolenaar static int
bsd_to_linux_sockopt_level(int level)25484b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
25584b11cd8SMitsuru IWASAKI {
25684b11cd8SMitsuru IWASAKI
25784b11cd8SMitsuru IWASAKI switch (level) {
25884b11cd8SMitsuru IWASAKI case SOL_SOCKET:
25984b11cd8SMitsuru IWASAKI return (LINUX_SOL_SOCKET);
26084b11cd8SMitsuru IWASAKI }
26184b11cd8SMitsuru IWASAKI return (level);
26284b11cd8SMitsuru IWASAKI }
26384b11cd8SMitsuru IWASAKI
26484b11cd8SMitsuru IWASAKI static int
linux_to_bsd_ip_sockopt(int opt)2653f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
266c21dee17SSøren Schmidt {
2673f3a4815SMarcel Moolenaar
268c21dee17SSøren Schmidt switch (opt) {
269c21dee17SSøren Schmidt case LINUX_IP_TOS:
2703f3a4815SMarcel Moolenaar return (IP_TOS);
271c21dee17SSøren Schmidt case LINUX_IP_TTL:
2723f3a4815SMarcel Moolenaar return (IP_TTL);
27366ff6a3cSBill Fenner case LINUX_IP_OPTIONS:
2743f3a4815SMarcel Moolenaar return (IP_OPTIONS);
27566ff6a3cSBill Fenner case LINUX_IP_MULTICAST_IF:
2763f3a4815SMarcel Moolenaar return (IP_MULTICAST_IF);
27766ff6a3cSBill Fenner case LINUX_IP_MULTICAST_TTL:
2783f3a4815SMarcel Moolenaar return (IP_MULTICAST_TTL);
27966ff6a3cSBill Fenner case LINUX_IP_MULTICAST_LOOP:
2803f3a4815SMarcel Moolenaar return (IP_MULTICAST_LOOP);
28166ff6a3cSBill Fenner case LINUX_IP_ADD_MEMBERSHIP:
2823f3a4815SMarcel Moolenaar return (IP_ADD_MEMBERSHIP);
28366ff6a3cSBill Fenner case LINUX_IP_DROP_MEMBERSHIP:
2843f3a4815SMarcel Moolenaar return (IP_DROP_MEMBERSHIP);
28566ff6a3cSBill Fenner case LINUX_IP_HDRINCL:
2863f3a4815SMarcel Moolenaar return (IP_HDRINCL);
287c21dee17SSøren Schmidt }
2883f3a4815SMarcel Moolenaar return (-1);
289c21dee17SSøren Schmidt }
290c21dee17SSøren Schmidt
291c21dee17SSøren Schmidt static int
linux_to_bsd_ip6_sockopt(int opt)29286a9058bSAndrey V. Elsukov linux_to_bsd_ip6_sockopt(int opt)
29386a9058bSAndrey V. Elsukov {
29486a9058bSAndrey V. Elsukov
29586a9058bSAndrey V. Elsukov switch (opt) {
29686a9058bSAndrey V. Elsukov case LINUX_IPV6_NEXTHOP:
29786a9058bSAndrey V. Elsukov return (IPV6_NEXTHOP);
29886a9058bSAndrey V. Elsukov case LINUX_IPV6_UNICAST_HOPS:
29986a9058bSAndrey V. Elsukov return (IPV6_UNICAST_HOPS);
30086a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_IF:
30186a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_IF);
30286a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_HOPS:
30386a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_HOPS);
30486a9058bSAndrey V. Elsukov case LINUX_IPV6_MULTICAST_LOOP:
30586a9058bSAndrey V. Elsukov return (IPV6_MULTICAST_LOOP);
30686a9058bSAndrey V. Elsukov case LINUX_IPV6_ADD_MEMBERSHIP:
30786a9058bSAndrey V. Elsukov return (IPV6_JOIN_GROUP);
30886a9058bSAndrey V. Elsukov case LINUX_IPV6_DROP_MEMBERSHIP:
30986a9058bSAndrey V. Elsukov return (IPV6_LEAVE_GROUP);
31086a9058bSAndrey V. Elsukov case LINUX_IPV6_V6ONLY:
31186a9058bSAndrey V. Elsukov return (IPV6_V6ONLY);
31286a9058bSAndrey V. Elsukov case LINUX_IPV6_DONTFRAG:
31386a9058bSAndrey V. Elsukov return (IPV6_DONTFRAG);
31486a9058bSAndrey V. Elsukov #if 0
31586a9058bSAndrey V. Elsukov case LINUX_IPV6_CHECKSUM:
31686a9058bSAndrey V. Elsukov return (IPV6_CHECKSUM);
31786a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPKTINFO:
31886a9058bSAndrey V. Elsukov return (IPV6_RECVPKTINFO);
31986a9058bSAndrey V. Elsukov case LINUX_IPV6_PKTINFO:
32086a9058bSAndrey V. Elsukov return (IPV6_PKTINFO);
32186a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPLIMIT:
32286a9058bSAndrey V. Elsukov return (IPV6_RECVHOPLIMIT);
32386a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPLIMIT:
32486a9058bSAndrey V. Elsukov return (IPV6_HOPLIMIT);
32586a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVHOPOPTS:
32686a9058bSAndrey V. Elsukov return (IPV6_RECVHOPOPTS);
32786a9058bSAndrey V. Elsukov case LINUX_IPV6_HOPOPTS:
32886a9058bSAndrey V. Elsukov return (IPV6_HOPOPTS);
32986a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDRDSTOPTS:
33086a9058bSAndrey V. Elsukov return (IPV6_RTHDRDSTOPTS);
33186a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVRTHDR:
33286a9058bSAndrey V. Elsukov return (IPV6_RECVRTHDR);
33386a9058bSAndrey V. Elsukov case LINUX_IPV6_RTHDR:
33486a9058bSAndrey V. Elsukov return (IPV6_RTHDR);
33586a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVDSTOPTS:
33686a9058bSAndrey V. Elsukov return (IPV6_RECVDSTOPTS);
33786a9058bSAndrey V. Elsukov case LINUX_IPV6_DSTOPTS:
33886a9058bSAndrey V. Elsukov return (IPV6_DSTOPTS);
33986a9058bSAndrey V. Elsukov case LINUX_IPV6_RECVPATHMTU:
34086a9058bSAndrey V. Elsukov return (IPV6_RECVPATHMTU);
34186a9058bSAndrey V. Elsukov case LINUX_IPV6_PATHMTU:
34286a9058bSAndrey V. Elsukov return (IPV6_PATHMTU);
34386a9058bSAndrey V. Elsukov #endif
34486a9058bSAndrey V. Elsukov }
34586a9058bSAndrey V. Elsukov return (-1);
34686a9058bSAndrey V. Elsukov }
34786a9058bSAndrey V. Elsukov
34886a9058bSAndrey V. Elsukov static int
linux_to_bsd_so_sockopt(int opt)349c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
350c21dee17SSøren Schmidt {
3513f3a4815SMarcel Moolenaar
352c21dee17SSøren Schmidt switch (opt) {
353c21dee17SSøren Schmidt case LINUX_SO_DEBUG:
3543f3a4815SMarcel Moolenaar return (SO_DEBUG);
355c21dee17SSøren Schmidt case LINUX_SO_REUSEADDR:
3563f3a4815SMarcel Moolenaar return (SO_REUSEADDR);
357c21dee17SSøren Schmidt case LINUX_SO_TYPE:
3583f3a4815SMarcel Moolenaar return (SO_TYPE);
359c21dee17SSøren Schmidt case LINUX_SO_ERROR:
3603f3a4815SMarcel Moolenaar return (SO_ERROR);
361c21dee17SSøren Schmidt case LINUX_SO_DONTROUTE:
3623f3a4815SMarcel Moolenaar return (SO_DONTROUTE);
363c21dee17SSøren Schmidt case LINUX_SO_BROADCAST:
3643f3a4815SMarcel Moolenaar return (SO_BROADCAST);
365c21dee17SSøren Schmidt case LINUX_SO_SNDBUF:
3663f3a4815SMarcel Moolenaar return (SO_SNDBUF);
367c21dee17SSøren Schmidt case LINUX_SO_RCVBUF:
3683f3a4815SMarcel Moolenaar return (SO_RCVBUF);
369c21dee17SSøren Schmidt case LINUX_SO_KEEPALIVE:
3703f3a4815SMarcel Moolenaar return (SO_KEEPALIVE);
371c21dee17SSøren Schmidt case LINUX_SO_OOBINLINE:
3723f3a4815SMarcel Moolenaar return (SO_OOBINLINE);
373c21dee17SSøren Schmidt case LINUX_SO_LINGER:
3743f3a4815SMarcel Moolenaar return (SO_LINGER);
375d0b2365eSKonstantin Belousov case LINUX_SO_PEERCRED:
376d0b2365eSKonstantin Belousov return (LOCAL_PEERCRED);
377d0b2365eSKonstantin Belousov case LINUX_SO_RCVLOWAT:
378d0b2365eSKonstantin Belousov return (SO_RCVLOWAT);
379d0b2365eSKonstantin Belousov case LINUX_SO_SNDLOWAT:
380d0b2365eSKonstantin Belousov return (SO_SNDLOWAT);
381d0b2365eSKonstantin Belousov case LINUX_SO_RCVTIMEO:
382d0b2365eSKonstantin Belousov return (SO_RCVTIMEO);
383d0b2365eSKonstantin Belousov case LINUX_SO_SNDTIMEO:
384d0b2365eSKonstantin Belousov return (SO_SNDTIMEO);
385d0b2365eSKonstantin Belousov case LINUX_SO_TIMESTAMP:
386d0b2365eSKonstantin Belousov return (SO_TIMESTAMP);
387d0b2365eSKonstantin Belousov case LINUX_SO_ACCEPTCONN:
388d0b2365eSKonstantin Belousov return (SO_ACCEPTCONN);
389c21dee17SSøren Schmidt }
3903f3a4815SMarcel Moolenaar return (-1);
391c21dee17SSøren Schmidt }
392c21dee17SSøren Schmidt
39340dbba57SAssar Westerlund static int
linux_to_bsd_tcp_sockopt(int opt)394fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt)
395fb709557SJohn Baldwin {
396fb709557SJohn Baldwin
397fb709557SJohn Baldwin switch (opt) {
398fb709557SJohn Baldwin case LINUX_TCP_NODELAY:
399fb709557SJohn Baldwin return (TCP_NODELAY);
400fb709557SJohn Baldwin case LINUX_TCP_MAXSEG:
401fb709557SJohn Baldwin return (TCP_MAXSEG);
402fb709557SJohn Baldwin case LINUX_TCP_KEEPIDLE:
403fb709557SJohn Baldwin return (TCP_KEEPIDLE);
404fb709557SJohn Baldwin case LINUX_TCP_KEEPINTVL:
405fb709557SJohn Baldwin return (TCP_KEEPINTVL);
406fb709557SJohn Baldwin case LINUX_TCP_KEEPCNT:
407fb709557SJohn Baldwin return (TCP_KEEPCNT);
408fb709557SJohn Baldwin case LINUX_TCP_MD5SIG:
409fb709557SJohn Baldwin return (TCP_MD5SIG);
410fb709557SJohn Baldwin }
411fb709557SJohn Baldwin return (-1);
412fb709557SJohn Baldwin }
413fb709557SJohn Baldwin
414fb709557SJohn Baldwin static int
linux_to_bsd_msg_flags(int flags)41540dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
41640dbba57SAssar Westerlund {
41740dbba57SAssar Westerlund int ret_flags = 0;
41840dbba57SAssar Westerlund
41940dbba57SAssar Westerlund if (flags & LINUX_MSG_OOB)
42040dbba57SAssar Westerlund ret_flags |= MSG_OOB;
42140dbba57SAssar Westerlund if (flags & LINUX_MSG_PEEK)
42240dbba57SAssar Westerlund ret_flags |= MSG_PEEK;
42340dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTROUTE)
42440dbba57SAssar Westerlund ret_flags |= MSG_DONTROUTE;
42540dbba57SAssar Westerlund if (flags & LINUX_MSG_CTRUNC)
42640dbba57SAssar Westerlund ret_flags |= MSG_CTRUNC;
42740dbba57SAssar Westerlund if (flags & LINUX_MSG_TRUNC)
42840dbba57SAssar Westerlund ret_flags |= MSG_TRUNC;
42940dbba57SAssar Westerlund if (flags & LINUX_MSG_DONTWAIT)
43040dbba57SAssar Westerlund ret_flags |= MSG_DONTWAIT;
43140dbba57SAssar Westerlund if (flags & LINUX_MSG_EOR)
43240dbba57SAssar Westerlund ret_flags |= MSG_EOR;
43340dbba57SAssar Westerlund if (flags & LINUX_MSG_WAITALL)
43440dbba57SAssar Westerlund ret_flags |= MSG_WAITALL;
4358d6e40c3SMaxim Sobolev if (flags & LINUX_MSG_NOSIGNAL)
4368d6e40c3SMaxim Sobolev ret_flags |= MSG_NOSIGNAL;
43740dbba57SAssar Westerlund #if 0 /* not handled */
43840dbba57SAssar Westerlund if (flags & LINUX_MSG_PROXY)
43940dbba57SAssar Westerlund ;
44040dbba57SAssar Westerlund if (flags & LINUX_MSG_FIN)
44140dbba57SAssar Westerlund ;
44240dbba57SAssar Westerlund if (flags & LINUX_MSG_SYN)
44340dbba57SAssar Westerlund ;
44440dbba57SAssar Westerlund if (flags & LINUX_MSG_CONFIRM)
44540dbba57SAssar Westerlund ;
44640dbba57SAssar Westerlund if (flags & LINUX_MSG_RST)
44740dbba57SAssar Westerlund ;
44840dbba57SAssar Westerlund if (flags & LINUX_MSG_ERRQUEUE)
44940dbba57SAssar Westerlund ;
45040dbba57SAssar Westerlund #endif
451e667ee63SDmitry Chagin return (ret_flags);
45240dbba57SAssar Westerlund }
45340dbba57SAssar Westerlund
4545c8919adSAlexander Leidinger /*
4555c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
4565c8919adSAlexander Leidinger * native syscall will fault. Thus, we don't really need to check the
4575c8919adSAlexander Leidinger * return values for these functions.
4585c8919adSAlexander Leidinger */
4595c8919adSAlexander Leidinger
4605c8919adSAlexander Leidinger static int
bsd_to_linux_sockaddr(struct sockaddr * arg)4615c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
4625c8919adSAlexander Leidinger {
4635c8919adSAlexander Leidinger struct sockaddr sa;
4645c8919adSAlexander Leidinger size_t sa_len = sizeof(struct sockaddr);
465df964aa4SDmitry Chagin int error, bdom;
4665c8919adSAlexander Leidinger
4675c8919adSAlexander Leidinger if ((error = copyin(arg, &sa, sa_len)))
4685c8919adSAlexander Leidinger return (error);
4695c8919adSAlexander Leidinger
470df964aa4SDmitry Chagin bdom = bsd_to_linux_domain(sa.sa_family);
471df964aa4SDmitry Chagin if (bdom == -1)
472df964aa4SDmitry Chagin return (EAFNOSUPPORT);
473df964aa4SDmitry Chagin
474df964aa4SDmitry Chagin *(u_short *)&sa = bdom;
475e667ee63SDmitry Chagin return (copyout(&sa, arg, sa_len));
4765c8919adSAlexander Leidinger }
4775c8919adSAlexander Leidinger
4785c8919adSAlexander Leidinger static int
linux_to_bsd_sockaddr(struct sockaddr * arg,int len)4795c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
4805c8919adSAlexander Leidinger {
4815c8919adSAlexander Leidinger struct sockaddr sa;
4825c8919adSAlexander Leidinger size_t sa_len = sizeof(struct sockaddr);
483df964aa4SDmitry Chagin int error, bdom;
4845c8919adSAlexander Leidinger
4855c8919adSAlexander Leidinger if ((error = copyin(arg, &sa, sa_len)))
4865c8919adSAlexander Leidinger return (error);
4875c8919adSAlexander Leidinger
488df964aa4SDmitry Chagin bdom = linux_to_bsd_domain(*(sa_family_t *)&sa);
489df964aa4SDmitry Chagin if (bdom == -1)
490df964aa4SDmitry Chagin return (EAFNOSUPPORT);
491df964aa4SDmitry Chagin
492df964aa4SDmitry Chagin sa.sa_family = bdom;
4935c8919adSAlexander Leidinger sa.sa_len = len;
494e667ee63SDmitry Chagin return (copyout(&sa, arg, sa_len));
4955c8919adSAlexander Leidinger }
4965c8919adSAlexander Leidinger
497ca26842eSHajimu UMEMOTO static int
linux_sa_put(struct osockaddr * osa)498ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
499ca26842eSHajimu UMEMOTO {
500ca26842eSHajimu UMEMOTO struct osockaddr sa;
501ca26842eSHajimu UMEMOTO int error, bdom;
502ca26842eSHajimu UMEMOTO
503ca26842eSHajimu UMEMOTO /*
504ca26842eSHajimu UMEMOTO * Only read/write the osockaddr family part, the rest is
505ca26842eSHajimu UMEMOTO * not changed.
506ca26842eSHajimu UMEMOTO */
5074b7ef73dSDag-Erling Smørgrav error = copyin(osa, &sa, sizeof(sa.sa_family));
508dddb7e7fSDmitry Chagin if (error != 0)
509ca26842eSHajimu UMEMOTO return (error);
510ca26842eSHajimu UMEMOTO
511ca26842eSHajimu UMEMOTO bdom = bsd_to_linux_domain(sa.sa_family);
512ca26842eSHajimu UMEMOTO if (bdom == -1)
513ca26842eSHajimu UMEMOTO return (EINVAL);
514ca26842eSHajimu UMEMOTO
515ca26842eSHajimu UMEMOTO sa.sa_family = bdom;
516e667ee63SDmitry Chagin return (copyout(&sa, osa, sizeof(sa.sa_family)));
517ca26842eSHajimu UMEMOTO }
518ca26842eSHajimu UMEMOTO
5195a8a13e0SDavid Malone static int
linux_to_bsd_cmsg_type(int cmsg_type)52074f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type)
5215a8a13e0SDavid Malone {
52274f5d680SKonstantin Belousov
52374f5d680SKonstantin Belousov switch (cmsg_type) {
52474f5d680SKonstantin Belousov case LINUX_SCM_RIGHTS:
52574f5d680SKonstantin Belousov return (SCM_RIGHTS);
526605da56bSAndriy Gapon case LINUX_SCM_CREDENTIALS:
527605da56bSAndriy Gapon return (SCM_CREDS);
52874f5d680SKonstantin Belousov }
52974f5d680SKonstantin Belousov return (-1);
53074f5d680SKonstantin Belousov }
53174f5d680SKonstantin Belousov
53274f5d680SKonstantin Belousov static int
bsd_to_linux_cmsg_type(int cmsg_type)53374f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type)
53474f5d680SKonstantin Belousov {
53574f5d680SKonstantin Belousov
53674f5d680SKonstantin Belousov switch (cmsg_type) {
53774f5d680SKonstantin Belousov case SCM_RIGHTS:
53874f5d680SKonstantin Belousov return (LINUX_SCM_RIGHTS);
539605da56bSAndriy Gapon case SCM_CREDS:
540605da56bSAndriy Gapon return (LINUX_SCM_CREDENTIALS);
541bbf392d5SDmitry Chagin case SCM_TIMESTAMP:
542bbf392d5SDmitry Chagin return (LINUX_SCM_TIMESTAMP);
54374f5d680SKonstantin Belousov }
54474f5d680SKonstantin Belousov return (-1);
54574f5d680SKonstantin Belousov }
54674f5d680SKonstantin Belousov
54774f5d680SKonstantin Belousov static int
linux_to_bsd_msghdr(struct msghdr * bhdr,const struct l_msghdr * lhdr)54874f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
54974f5d680SKonstantin Belousov {
55074f5d680SKonstantin Belousov if (lhdr->msg_controllen > INT_MAX)
55174f5d680SKonstantin Belousov return (ENOBUFS);
55274f5d680SKonstantin Belousov
55374f5d680SKonstantin Belousov bhdr->msg_name = PTRIN(lhdr->msg_name);
55474f5d680SKonstantin Belousov bhdr->msg_namelen = lhdr->msg_namelen;
55574f5d680SKonstantin Belousov bhdr->msg_iov = PTRIN(lhdr->msg_iov);
55674f5d680SKonstantin Belousov bhdr->msg_iovlen = lhdr->msg_iovlen;
55774f5d680SKonstantin Belousov bhdr->msg_control = PTRIN(lhdr->msg_control);
558605da56bSAndriy Gapon
559605da56bSAndriy Gapon /*
560605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages
561605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used
562605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system).
563605da56bSAndriy Gapon *
564605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the
565605da56bSAndriy Gapon * control messages.
566605da56bSAndriy Gapon */
567605da56bSAndriy Gapon
56874f5d680SKonstantin Belousov bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags);
56974f5d680SKonstantin Belousov return (0);
57074f5d680SKonstantin Belousov }
57174f5d680SKonstantin Belousov
57274f5d680SKonstantin Belousov static int
bsd_to_linux_msghdr(const struct msghdr * bhdr,struct l_msghdr * lhdr)57374f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
57474f5d680SKonstantin Belousov {
57574f5d680SKonstantin Belousov lhdr->msg_name = PTROUT(bhdr->msg_name);
57674f5d680SKonstantin Belousov lhdr->msg_namelen = bhdr->msg_namelen;
57774f5d680SKonstantin Belousov lhdr->msg_iov = PTROUT(bhdr->msg_iov);
57874f5d680SKonstantin Belousov lhdr->msg_iovlen = bhdr->msg_iovlen;
57974f5d680SKonstantin Belousov lhdr->msg_control = PTROUT(bhdr->msg_control);
580605da56bSAndriy Gapon
581605da56bSAndriy Gapon /*
582605da56bSAndriy Gapon * msg_controllen is skipped since BSD and LINUX control messages
583605da56bSAndriy Gapon * are potentially different sizes (e.g. the cred structure used
584605da56bSAndriy Gapon * by SCM_CREDS is different between the two operating system).
585605da56bSAndriy Gapon *
586605da56bSAndriy Gapon * The caller can set it (if necessary) after converting all the
587605da56bSAndriy Gapon * control messages.
588605da56bSAndriy Gapon */
589605da56bSAndriy Gapon
59074f5d680SKonstantin Belousov /* msg_flags skipped */
59174f5d680SKonstantin Belousov return (0);
59274f5d680SKonstantin Belousov }
59374f5d680SKonstantin Belousov
59474f5d680SKonstantin Belousov static int
linux_set_socket_flags(int lflags,int * flags)5954cf10e29SDmitry Chagin linux_set_socket_flags(int lflags, int *flags)
59638a18e97SDmitry Chagin {
59738a18e97SDmitry Chagin
5984cf10e29SDmitry Chagin if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
5994cf10e29SDmitry Chagin return (EINVAL);
6004cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_NONBLOCK)
6014cf10e29SDmitry Chagin *flags |= SOCK_NONBLOCK;
6024cf10e29SDmitry Chagin if (lflags & LINUX_SOCK_CLOEXEC)
6034cf10e29SDmitry Chagin *flags |= SOCK_CLOEXEC;
60438a18e97SDmitry Chagin return (0);
60538a18e97SDmitry Chagin }
60638a18e97SDmitry Chagin
60738a18e97SDmitry Chagin static int
linux_sendit(struct thread * td,int s,struct msghdr * mp,int flags,struct mbuf * control,enum uio_seg segflg)60874f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
60974f5d680SKonstantin Belousov struct mbuf *control, enum uio_seg segflg)
61074f5d680SKonstantin Belousov {
6115a8a13e0SDavid Malone struct sockaddr *to;
6125a8a13e0SDavid Malone int error;
6135a8a13e0SDavid Malone
6145a8a13e0SDavid Malone if (mp->msg_name != NULL) {
6155a8a13e0SDavid Malone error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
616dddb7e7fSDmitry Chagin if (error != 0)
6175a8a13e0SDavid Malone return (error);
6185a8a13e0SDavid Malone mp->msg_name = to;
6195a8a13e0SDavid Malone } else
6205a8a13e0SDavid Malone to = NULL;
6215a8a13e0SDavid Malone
622a6886ef1SMaxim Sobolev error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
623a6886ef1SMaxim Sobolev segflg);
6245a8a13e0SDavid Malone
6255a8a13e0SDavid Malone if (to)
6261ede983cSDag-Erling Smørgrav free(to, M_SONAME);
6275a8a13e0SDavid Malone return (error);
6285a8a13e0SDavid Malone }
6295a8a13e0SDavid Malone
6303f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
631f2477ae1SMike Smith static int
linux_check_hdrincl(struct thread * td,int s)632e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
633f2477ae1SMike Smith {
634857ad5a3SDmitry Chagin int error, optval;
635857ad5a3SDmitry Chagin socklen_t size_val;
636f2477ae1SMike Smith
637e140eb43SDavid Malone size_val = sizeof(optval);
638e140eb43SDavid Malone error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
639e140eb43SDavid Malone &optval, UIO_SYSSPACE, &size_val);
640dddb7e7fSDmitry Chagin if (error != 0)
6413f3a4815SMarcel Moolenaar return (error);
6423f3a4815SMarcel Moolenaar
6433f3a4815SMarcel Moolenaar return (optval == 0);
644f2477ae1SMike Smith }
645f2477ae1SMike Smith
646f2477ae1SMike Smith /*
647f2477ae1SMike Smith * Updated sendto() when IP_HDRINCL is set:
648f2477ae1SMike Smith * tweak endian-dependent fields in the IP packet.
649f2477ae1SMike Smith */
650f2477ae1SMike Smith static int
linux_sendto_hdrincl(struct thread * td,struct linux_sendto_args * linux_args)65138da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
652f2477ae1SMike Smith {
653f2477ae1SMike Smith /*
654f2477ae1SMike Smith * linux_ip_copysize defines how many bytes we should copy
655f2477ae1SMike Smith * from the beginning of the IP packet before we customize it for BSD.
656a6886ef1SMaxim Sobolev * It should include all the fields we modify (ip_len and ip_off).
657f2477ae1SMike Smith */
658f2477ae1SMike Smith #define linux_ip_copysize 8
659f2477ae1SMike Smith
660f2477ae1SMike Smith struct ip *packet;
6615a8a13e0SDavid Malone struct msghdr msg;
662a6886ef1SMaxim Sobolev struct iovec aiov[1];
663f2477ae1SMike Smith int error;
664f2477ae1SMike Smith
665aa675b57SDavid Schultz /* Check that the packet isn't too big or too small. */
666aa675b57SDavid Schultz if (linux_args->len < linux_ip_copysize ||
667aa675b57SDavid Schultz linux_args->len > IP_MAXPACKET)
6683f3a4815SMarcel Moolenaar return (EINVAL);
669f2477ae1SMike Smith
670e0d3ea8cSDmitry Chagin packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
671f2477ae1SMike Smith
672a6886ef1SMaxim Sobolev /* Make kernel copy of the packet to be sent */
6734af27623STim J. Robbins if ((error = copyin(PTRIN(linux_args->msg), packet,
674a6886ef1SMaxim Sobolev linux_args->len)))
675a6886ef1SMaxim Sobolev goto goout;
676f2477ae1SMike Smith
677f2477ae1SMike Smith /* Convert fields from Linux to BSD raw IP socket format */
6785a8a13e0SDavid Malone packet->ip_len = linux_args->len;
679f2477ae1SMike Smith packet->ip_off = ntohs(packet->ip_off);
680f2477ae1SMike Smith
681f2477ae1SMike Smith /* Prepare the msghdr and iovec structures describing the new packet */
6824af27623STim J. Robbins msg.msg_name = PTRIN(linux_args->to);
6835a8a13e0SDavid Malone msg.msg_namelen = linux_args->tolen;
6845a8a13e0SDavid Malone msg.msg_iov = aiov;
685a6886ef1SMaxim Sobolev msg.msg_iovlen = 1;
6865a8a13e0SDavid Malone msg.msg_control = NULL;
6875a8a13e0SDavid Malone msg.msg_flags = 0;
6885a8a13e0SDavid Malone aiov[0].iov_base = (char *)packet;
689a6886ef1SMaxim Sobolev aiov[0].iov_len = linux_args->len;
690a6886ef1SMaxim Sobolev error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
69174f5d680SKonstantin Belousov NULL, UIO_SYSSPACE);
692a6886ef1SMaxim Sobolev goout:
693e0d3ea8cSDmitry Chagin free(packet, M_LINUX);
6945a8a13e0SDavid Malone return (error);
695f2477ae1SMike Smith }
696f2477ae1SMike Smith
697a12b9b3dSDmitry Chagin int
linux_socket(struct thread * td,struct linux_socket_args * args)698b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
699c21dee17SSøren Schmidt {
700d293f35cSEdward Tomasz Napierala int domain, retval_socket, type;
701c21dee17SSøren Schmidt
702d293f35cSEdward Tomasz Napierala type = args->type & LINUX_SOCK_TYPE_MASK;
703d293f35cSEdward Tomasz Napierala if (type < 0 || type > LINUX_SOCK_MAX)
704eeb63e51SDmitry Chagin return (EINVAL);
7054cf10e29SDmitry Chagin retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
706d293f35cSEdward Tomasz Napierala &type);
7074cf10e29SDmitry Chagin if (retval_socket != 0)
7084cf10e29SDmitry Chagin return (retval_socket);
709d293f35cSEdward Tomasz Napierala domain = linux_to_bsd_domain(args->domain);
710d293f35cSEdward Tomasz Napierala if (domain == -1)
711d9b063ccSDmitry Chagin return (EAFNOSUPPORT);
712f2477ae1SMike Smith
713d293f35cSEdward Tomasz Napierala retval_socket = kern_socket(td, domain, type, args->protocol);
7146994ea54SDmitry Chagin if (retval_socket)
7156994ea54SDmitry Chagin return (retval_socket);
7166994ea54SDmitry Chagin
717d293f35cSEdward Tomasz Napierala if (type == SOCK_RAW
718d293f35cSEdward Tomasz Napierala && (args->protocol == IPPROTO_RAW || args->protocol == 0)
719d293f35cSEdward Tomasz Napierala && domain == PF_INET) {
720f2477ae1SMike Smith /* It's a raw IP socket: set the IP_HDRINCL option. */
721e140eb43SDavid Malone int hdrincl;
722f2477ae1SMike Smith
723e140eb43SDavid Malone hdrincl = 1;
724e140eb43SDavid Malone /* We ignore any error returned by kern_setsockopt() */
725e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
726e140eb43SDavid Malone &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
727f2477ae1SMike Smith }
728ca26842eSHajimu UMEMOTO #ifdef INET6
729ca26842eSHajimu UMEMOTO /*
730d97bee3eSBjoern A. Zeeb * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
731d97bee3eSBjoern A. Zeeb * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
732d97bee3eSBjoern A. Zeeb * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
733d97bee3eSBjoern A. Zeeb * sysctl value.
734ca26842eSHajimu UMEMOTO */
735d293f35cSEdward Tomasz Napierala if (domain == PF_INET6) {
736e140eb43SDavid Malone int v6only;
737ca26842eSHajimu UMEMOTO
738e140eb43SDavid Malone v6only = 0;
739ca26842eSHajimu UMEMOTO /* We ignore any error returned by setsockopt() */
740e140eb43SDavid Malone kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
741e140eb43SDavid Malone &v6only, UIO_SYSSPACE, sizeof(v6only));
742ca26842eSHajimu UMEMOTO }
743ca26842eSHajimu UMEMOTO #endif
7443f3a4815SMarcel Moolenaar
7453f3a4815SMarcel Moolenaar return (retval_socket);
746c21dee17SSøren Schmidt }
747c21dee17SSøren Schmidt
748a12b9b3dSDmitry Chagin int
linux_bind(struct thread * td,struct linux_bind_args * args)749b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
750c21dee17SSøren Schmidt {
751ca26842eSHajimu UMEMOTO struct sockaddr *sa;
752c21dee17SSøren Schmidt int error;
753c21dee17SSøren Schmidt
754745aaef5SKonstantin Belousov error = linux_getsockaddr(&sa, PTRIN(args->name),
755745aaef5SKonstantin Belousov args->namelen);
756dddb7e7fSDmitry Chagin if (error != 0)
757ca26842eSHajimu UMEMOTO return (error);
758ca26842eSHajimu UMEMOTO
7596e646651SKonstantin Belousov error = kern_bindat(td, AT_FDCWD, args->s, sa);
760b33887eaSJohn Baldwin free(sa, M_SONAME);
761745aaef5SKonstantin Belousov if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
762d4b7423fSAlexander Leidinger return (EINVAL);
763b33887eaSJohn Baldwin return (error);
764c21dee17SSøren Schmidt }
765c21dee17SSøren Schmidt
766930a65feSAndrew Gallatin int
linux_connect(struct thread * td,struct linux_connect_args * args)767b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
768c21dee17SSøren Schmidt {
7690bf301c0SJonathan Lemon struct socket *so;
770ca26842eSHajimu UMEMOTO struct sockaddr *sa;
77195653579SGleb Smirnoff struct file *fp;
77239c95b83SMatthew Dillon u_int fflag;
773c21dee17SSøren Schmidt int error;
774c21dee17SSøren Schmidt
775745aaef5SKonstantin Belousov error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
776745aaef5SKonstantin Belousov args->namelen);
777dddb7e7fSDmitry Chagin if (error != 0)
778ca26842eSHajimu UMEMOTO return (error);
779ca26842eSHajimu UMEMOTO
7806e646651SKonstantin Belousov error = kern_connectat(td, AT_FDCWD, args->s, sa);
781b33887eaSJohn Baldwin free(sa, M_SONAME);
7820bf301c0SJonathan Lemon if (error != EISCONN)
7830bf301c0SJonathan Lemon return (error);
7840bf301c0SJonathan Lemon
785dad3b88aSMike Smith /*
786dad3b88aSMike Smith * Linux doesn't return EISCONN the first time it occurs,
787dad3b88aSMike Smith * when on a non-blocking socket. Instead it returns the
788dad3b88aSMike Smith * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
789dad3b88aSMike Smith */
790cbd92ce6SMatt Macy error = getsock_cap(td, args->s, &cap_connect_rights,
79195653579SGleb Smirnoff &fp, &fflag, NULL);
79295653579SGleb Smirnoff if (error != 0)
79395653579SGleb Smirnoff return (error);
79495653579SGleb Smirnoff
7950bf301c0SJonathan Lemon error = EISCONN;
79695653579SGleb Smirnoff so = fp->f_data;
79739c95b83SMatthew Dillon if (fflag & FNONBLOCK) {
7984641373fSJohn Baldwin SOCK_LOCK(so);
7995002a60fSMarcel Moolenaar if (so->so_emuldata == 0)
8000bf301c0SJonathan Lemon error = so->so_error;
8010bf301c0SJonathan Lemon so->so_emuldata = (void *)1;
8024641373fSJohn Baldwin SOCK_UNLOCK(so);
803dad3b88aSMike Smith }
80495653579SGleb Smirnoff fdrop(fp, td);
80595653579SGleb Smirnoff
8063f3a4815SMarcel Moolenaar return (error);
807c21dee17SSøren Schmidt }
808c21dee17SSøren Schmidt
809a12b9b3dSDmitry Chagin int
linux_listen(struct thread * td,struct linux_listen_args * args)810b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
811c21dee17SSøren Schmidt {
812c21dee17SSøren Schmidt
813d293f35cSEdward Tomasz Napierala return (kern_listen(td, args->s, args->backlog));
814c21dee17SSøren Schmidt }
815c21dee17SSøren Schmidt
81601e0ffbaSAlexander Leidinger static int
linux_accept_common(struct thread * td,int s,l_uintptr_t addr,l_uintptr_t namelen,int flags)817c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
818f83427b8SDmitry Chagin l_uintptr_t namelen, int flags)
819c21dee17SSøren Schmidt {
8204cf10e29SDmitry Chagin struct accept4_args /* {
821c21dee17SSøren Schmidt int s;
8223db2a843SBruce Evans struct sockaddr * __restrict name;
8233db2a843SBruce Evans socklen_t * __restrict anamelen;
8244cf10e29SDmitry Chagin int flags;
825ef04503dSPeter Wemm } */ bsd_args;
826fc4b98fbSDmitry Chagin struct socket *so;
827fc4b98fbSDmitry Chagin struct file *fp;
828fc4b98fbSDmitry Chagin int error, error1;
82993e694c9SDmitry Chagin
830c8f37d61SDmitry Chagin bsd_args.s = s;
831c8f37d61SDmitry Chagin bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
832dddb7e7fSDmitry Chagin bsd_args.anamelen = PTRIN(namelen);
8331a01bdf9SJung-uk Kim bsd_args.flags = 0;
8344cf10e29SDmitry Chagin error = linux_set_socket_flags(flags, &bsd_args.flags);
8354cf10e29SDmitry Chagin if (error != 0)
8364cf10e29SDmitry Chagin return (error);
8374cf10e29SDmitry Chagin error = sys_accept4(td, &bsd_args);
8385c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
839dddb7e7fSDmitry Chagin if (error != 0) {
840c8f37d61SDmitry Chagin if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
841d4b7423fSAlexander Leidinger return (EINVAL);
842fc4b98fbSDmitry Chagin if (error == EINVAL) {
843cbd92ce6SMatt Macy error1 = getsock_cap(td, s, &cap_accept_rights, &fp, NULL, NULL);
844fc4b98fbSDmitry Chagin if (error1 != 0)
845fc4b98fbSDmitry Chagin return (error1);
84691f514e4SDmitry Chagin so = fp->f_data;
84791f514e4SDmitry Chagin if (so->so_type == SOCK_DGRAM) {
84891f514e4SDmitry Chagin fdrop(fp, td);
849fc4b98fbSDmitry Chagin return (EOPNOTSUPP);
850fc4b98fbSDmitry Chagin }
85191f514e4SDmitry Chagin fdrop(fp, td);
85291f514e4SDmitry Chagin }
853dba5ab66SMarcel Moolenaar return (error);
854d4b7423fSAlexander Leidinger }
85593e694c9SDmitry Chagin if (addr)
85693e694c9SDmitry Chagin error = linux_sa_put(PTRIN(addr));
857dddb7e7fSDmitry Chagin if (error != 0) {
85893e694c9SDmitry Chagin (void)kern_close(td, td->td_retval[0]);
85993e694c9SDmitry Chagin td->td_retval[0] = 0;
86093e694c9SDmitry Chagin }
86193e694c9SDmitry Chagin return (error);
862c21dee17SSøren Schmidt }
863c21dee17SSøren Schmidt
864a12b9b3dSDmitry Chagin int
linux_accept(struct thread * td,struct linux_accept_args * args)865c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args)
866c8f37d61SDmitry Chagin {
867c8f37d61SDmitry Chagin
868c8f37d61SDmitry Chagin return (linux_accept_common(td, args->s, args->addr,
869f83427b8SDmitry Chagin args->namelen, 0));
870c8f37d61SDmitry Chagin }
871c8f37d61SDmitry Chagin
872a12b9b3dSDmitry Chagin int
linux_accept4(struct thread * td,struct linux_accept4_args * args)873f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args)
874f8cd0af2SDmitry Chagin {
875f8cd0af2SDmitry Chagin
876f8cd0af2SDmitry Chagin return (linux_accept_common(td, args->s, args->addr,
877f8cd0af2SDmitry Chagin args->namelen, args->flags));
878f8cd0af2SDmitry Chagin }
879f8cd0af2SDmitry Chagin
880a12b9b3dSDmitry Chagin int
linux_getsockname(struct thread * td,struct linux_getsockname_args * args)881b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
882c21dee17SSøren Schmidt {
883ef04503dSPeter Wemm struct getsockname_args /* {
884c21dee17SSøren Schmidt int fdes;
8853db2a843SBruce Evans struct sockaddr * __restrict asa;
8863db2a843SBruce Evans socklen_t * __restrict alen;
887ef04503dSPeter Wemm } */ bsd_args;
888c21dee17SSøren Schmidt int error;
889c21dee17SSøren Schmidt
890745aaef5SKonstantin Belousov bsd_args.fdes = args->s;
891745aaef5SKonstantin Belousov bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
892dddb7e7fSDmitry Chagin bsd_args.alen = PTRIN(args->namelen);
8938451d0ddSKip Macy error = sys_getsockname(td, &bsd_args);
8945c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
895dddb7e7fSDmitry Chagin if (error != 0)
896ca26842eSHajimu UMEMOTO return (error);
897e667ee63SDmitry Chagin return (linux_sa_put(PTRIN(args->addr)));
898c21dee17SSøren Schmidt }
899c21dee17SSøren Schmidt
900a12b9b3dSDmitry Chagin int
linux_getpeername(struct thread * td,struct linux_getpeername_args * args)901b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
902c21dee17SSøren Schmidt {
9035c8919adSAlexander Leidinger struct getpeername_args /* {
904c21dee17SSøren Schmidt int fdes;
905c21dee17SSøren Schmidt caddr_t asa;
906c21dee17SSøren Schmidt int *alen;
907ef04503dSPeter Wemm } */ bsd_args;
908c21dee17SSøren Schmidt int error;
909c21dee17SSøren Schmidt
910745aaef5SKonstantin Belousov bsd_args.fdes = args->s;
911745aaef5SKonstantin Belousov bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
912857ad5a3SDmitry Chagin bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
9138451d0ddSKip Macy error = sys_getpeername(td, &bsd_args);
9145c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
915dddb7e7fSDmitry Chagin if (error != 0)
916ca26842eSHajimu UMEMOTO return (error);
917e667ee63SDmitry Chagin return (linux_sa_put(PTRIN(args->addr)));
918c21dee17SSøren Schmidt }
919c21dee17SSøren Schmidt
920a12b9b3dSDmitry Chagin int
linux_socketpair(struct thread * td,struct linux_socketpair_args * args)921b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
922c21dee17SSøren Schmidt {
923ef04503dSPeter Wemm struct socketpair_args /* {
924c21dee17SSøren Schmidt int domain;
925c21dee17SSøren Schmidt int type;
926c21dee17SSøren Schmidt int protocol;
927c21dee17SSøren Schmidt int *rsv;
928ef04503dSPeter Wemm } */ bsd_args;
9294cf10e29SDmitry Chagin int error;
930c21dee17SSøren Schmidt
931745aaef5SKonstantin Belousov bsd_args.domain = linux_to_bsd_domain(args->domain);
9321a52a4abSDmitry Chagin if (bsd_args.domain != PF_LOCAL)
9331a52a4abSDmitry Chagin return (EAFNOSUPPORT);
93439253cf9SDmitry Chagin bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
93539253cf9SDmitry Chagin if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
93639253cf9SDmitry Chagin return (EINVAL);
9374cf10e29SDmitry Chagin error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
9384cf10e29SDmitry Chagin &bsd_args.type);
9394cf10e29SDmitry Chagin if (error != 0)
9404cf10e29SDmitry Chagin return (error);
9411a52a4abSDmitry Chagin if (args->protocol != 0 && args->protocol != PF_UNIX)
9421a52a4abSDmitry Chagin
9431a52a4abSDmitry Chagin /*
9441a52a4abSDmitry Chagin * Use of PF_UNIX as protocol argument is not right,
9451a52a4abSDmitry Chagin * but Linux does it.
9461a52a4abSDmitry Chagin * Do not map PF_UNIX as its Linux value is identical
9471a52a4abSDmitry Chagin * to FreeBSD one.
9481a52a4abSDmitry Chagin */
9491a52a4abSDmitry Chagin return (EPROTONOSUPPORT);
95040092d93SDmitry Chagin else
9511a52a4abSDmitry Chagin bsd_args.protocol = 0;
952745aaef5SKonstantin Belousov bsd_args.rsv = (int *)PTRIN(args->rsv);
9534cf10e29SDmitry Chagin return (sys_socketpair(td, &bsd_args));
954c21dee17SSøren Schmidt }
955c21dee17SSøren Schmidt
956a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
95701e0ffbaSAlexander Leidinger struct linux_send_args {
95856fba8e6SDmitry Chagin register_t s;
95956fba8e6SDmitry Chagin register_t msg;
96056fba8e6SDmitry Chagin register_t len;
96156fba8e6SDmitry Chagin register_t flags;
962c21dee17SSøren Schmidt };
963c21dee17SSøren Schmidt
96401e0ffbaSAlexander Leidinger static int
linux_send(struct thread * td,struct linux_send_args * args)965b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
966c21dee17SSøren Schmidt {
96787d72a8fSPoul-Henning Kamp struct sendto_args /* {
968c21dee17SSøren Schmidt int s;
969c21dee17SSøren Schmidt caddr_t buf;
970044af7c3SJonathan Mini int len;
971c21dee17SSøren Schmidt int flags;
97287d72a8fSPoul-Henning Kamp caddr_t to;
97387d72a8fSPoul-Henning Kamp int tolen;
974ef04503dSPeter Wemm } */ bsd_args;
975c21dee17SSøren Schmidt
976745aaef5SKonstantin Belousov bsd_args.s = args->s;
977745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg);
978745aaef5SKonstantin Belousov bsd_args.len = args->len;
979745aaef5SKonstantin Belousov bsd_args.flags = args->flags;
98087d72a8fSPoul-Henning Kamp bsd_args.to = NULL;
98187d72a8fSPoul-Henning Kamp bsd_args.tolen = 0;
982e667ee63SDmitry Chagin return (sys_sendto(td, &bsd_args));
983c21dee17SSøren Schmidt }
984c21dee17SSøren Schmidt
98501e0ffbaSAlexander Leidinger struct linux_recv_args {
98656fba8e6SDmitry Chagin register_t s;
98756fba8e6SDmitry Chagin register_t msg;
98856fba8e6SDmitry Chagin register_t len;
98956fba8e6SDmitry Chagin register_t flags;
990c21dee17SSøren Schmidt };
991c21dee17SSøren Schmidt
99201e0ffbaSAlexander Leidinger static int
linux_recv(struct thread * td,struct linux_recv_args * args)993b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
994c21dee17SSøren Schmidt {
99587d72a8fSPoul-Henning Kamp struct recvfrom_args /* {
996c21dee17SSøren Schmidt int s;
997c21dee17SSøren Schmidt caddr_t buf;
998c21dee17SSøren Schmidt int len;
999c21dee17SSøren Schmidt int flags;
100087d72a8fSPoul-Henning Kamp struct sockaddr *from;
100187d72a8fSPoul-Henning Kamp socklen_t fromlenaddr;
1002ef04503dSPeter Wemm } */ bsd_args;
1003c21dee17SSøren Schmidt
1004745aaef5SKonstantin Belousov bsd_args.s = args->s;
1005745aaef5SKonstantin Belousov bsd_args.buf = (caddr_t)PTRIN(args->msg);
1006745aaef5SKonstantin Belousov bsd_args.len = args->len;
10073980a435SDmitry Chagin bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
100887d72a8fSPoul-Henning Kamp bsd_args.from = NULL;
100987d72a8fSPoul-Henning Kamp bsd_args.fromlenaddr = 0;
10108451d0ddSKip Macy return (sys_recvfrom(td, &bsd_args));
1011c21dee17SSøren Schmidt }
1012a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1013c21dee17SSøren Schmidt
1014a12b9b3dSDmitry Chagin int
linux_sendto(struct thread * td,struct linux_sendto_args * args)1015b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
1016c21dee17SSøren Schmidt {
10175a8a13e0SDavid Malone struct msghdr msg;
10185a8a13e0SDavid Malone struct iovec aiov;
1019c21dee17SSøren Schmidt
1020745aaef5SKonstantin Belousov if (linux_check_hdrincl(td, args->s) == 0)
1021f2477ae1SMike Smith /* IP_HDRINCL set, tweak the packet before sending */
1022745aaef5SKonstantin Belousov return (linux_sendto_hdrincl(td, args));
1023f2477ae1SMike Smith
1024745aaef5SKonstantin Belousov msg.msg_name = PTRIN(args->to);
1025745aaef5SKonstantin Belousov msg.msg_namelen = args->tolen;
10265a8a13e0SDavid Malone msg.msg_iov = &aiov;
10275a8a13e0SDavid Malone msg.msg_iovlen = 1;
10285a8a13e0SDavid Malone msg.msg_control = NULL;
10295a8a13e0SDavid Malone msg.msg_flags = 0;
1030745aaef5SKonstantin Belousov aiov.iov_base = PTRIN(args->msg);
1031745aaef5SKonstantin Belousov aiov.iov_len = args->len;
1032e667ee63SDmitry Chagin return (linux_sendit(td, args->s, &msg, args->flags, NULL,
1033e667ee63SDmitry Chagin UIO_USERSPACE));
1034c21dee17SSøren Schmidt }
1035c21dee17SSøren Schmidt
1036a12b9b3dSDmitry Chagin int
linux_recvfrom(struct thread * td,struct linux_recvfrom_args * args)1037b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
1038c21dee17SSøren Schmidt {
10399599b0ecSDmitry Chagin struct msghdr msg;
10409599b0ecSDmitry Chagin struct iovec aiov;
10413a49978fSDmitry Chagin int error, fromlen;
1042c21dee17SSøren Schmidt
10439599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL) {
10443a49978fSDmitry Chagin error = copyin(PTRIN(args->fromlen), &fromlen,
10453a49978fSDmitry Chagin sizeof(fromlen));
10469599b0ecSDmitry Chagin if (error != 0)
10473f3a4815SMarcel Moolenaar return (error);
10483a49978fSDmitry Chagin if (fromlen < 0)
10493a49978fSDmitry Chagin return (EINVAL);
10503a49978fSDmitry Chagin msg.msg_namelen = fromlen;
10519599b0ecSDmitry Chagin } else
10529599b0ecSDmitry Chagin msg.msg_namelen = 0;
10539599b0ecSDmitry Chagin
10549599b0ecSDmitry Chagin msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
10559599b0ecSDmitry Chagin msg.msg_iov = &aiov;
10569599b0ecSDmitry Chagin msg.msg_iovlen = 1;
10579599b0ecSDmitry Chagin aiov.iov_base = PTRIN(args->buf);
10589599b0ecSDmitry Chagin aiov.iov_len = args->len;
10599599b0ecSDmitry Chagin msg.msg_control = 0;
10609599b0ecSDmitry Chagin msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
10619599b0ecSDmitry Chagin
10629599b0ecSDmitry Chagin error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
10639599b0ecSDmitry Chagin if (error != 0)
10649599b0ecSDmitry Chagin return (error);
10659599b0ecSDmitry Chagin
10669599b0ecSDmitry Chagin if (PTRIN(args->from) != NULL) {
10679599b0ecSDmitry Chagin error = bsd_to_linux_sockaddr((struct sockaddr *)
10689599b0ecSDmitry Chagin PTRIN(args->from));
10699599b0ecSDmitry Chagin if (error != 0)
10709599b0ecSDmitry Chagin return (error);
10719599b0ecSDmitry Chagin
10724af27623STim J. Robbins error = linux_sa_put((struct osockaddr *)
1073745aaef5SKonstantin Belousov PTRIN(args->from));
1074ca26842eSHajimu UMEMOTO }
10759599b0ecSDmitry Chagin
10769599b0ecSDmitry Chagin if (PTRIN(args->fromlen) != NULL)
10779599b0ecSDmitry Chagin error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
10789599b0ecSDmitry Chagin sizeof(msg.msg_namelen));
10799599b0ecSDmitry Chagin
10809599b0ecSDmitry Chagin return (error);
1081ca26842eSHajimu UMEMOTO }
1082ca26842eSHajimu UMEMOTO
1083e1ff74c0SDmitry Chagin static int
linux_sendmsg_common(struct thread * td,l_int s,struct l_msghdr * msghdr,l_uint flags)1084e1ff74c0SDmitry Chagin linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1085e1ff74c0SDmitry Chagin l_uint flags)
1086ca26842eSHajimu UMEMOTO {
108774f5d680SKonstantin Belousov struct cmsghdr *cmsg;
108874f5d680SKonstantin Belousov struct mbuf *control;
1089ca26842eSHajimu UMEMOTO struct msghdr msg;
109074f5d680SKonstantin Belousov struct l_cmsghdr linux_cmsg;
109174f5d680SKonstantin Belousov struct l_cmsghdr *ptr_cmsg;
109274f5d680SKonstantin Belousov struct l_msghdr linux_msg;
1093552afd9cSPoul-Henning Kamp struct iovec *iov;
109474f5d680SKonstantin Belousov socklen_t datalen;
1095605da56bSAndriy Gapon struct sockaddr *sa;
1096605da56bSAndriy Gapon sa_family_t sa_family;
109774f5d680SKonstantin Belousov void *data;
1098edf16b7aSTijl Coosemans l_size_t len;
1099b720fbf3STijl Coosemans l_size_t clen;
1100ca26842eSHajimu UMEMOTO int error;
1101ca26842eSHajimu UMEMOTO
1102e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1103e1ff74c0SDmitry Chagin if (error != 0)
110474f5d680SKonstantin Belousov return (error);
1105d72a6158SRobert Watson
1106d72a6158SRobert Watson /*
1107d72a6158SRobert Watson * Some Linux applications (ping) define a non-NULL control data
1108d72a6158SRobert Watson * pointer, but a msg_controllen of 0, which is not allowed in the
1109d72a6158SRobert Watson * FreeBSD system call interface. NULL the msg_control pointer in
1110d72a6158SRobert Watson * order to handle this case. This should be checked, but allows the
1111d72a6158SRobert Watson * Linux ping to work.
1112d72a6158SRobert Watson */
1113605da56bSAndriy Gapon if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
1114605da56bSAndriy Gapon linux_msg.msg_control = PTROUT(NULL);
1115605da56bSAndriy Gapon
1116605da56bSAndriy Gapon error = linux_to_bsd_msghdr(&msg, &linux_msg);
1117e1ff74c0SDmitry Chagin if (error != 0)
1118605da56bSAndriy Gapon return (error);
111974f5d680SKonstantin Belousov
112074f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
112174f5d680SKonstantin Belousov error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
112274f5d680SKonstantin Belousov &iov, EMSGSIZE);
112374f5d680SKonstantin Belousov #else
1124552afd9cSPoul-Henning Kamp error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
112574f5d680SKonstantin Belousov #endif
1126e1ff74c0SDmitry Chagin if (error != 0)
1127552afd9cSPoul-Henning Kamp return (error);
112874f5d680SKonstantin Belousov
1129605da56bSAndriy Gapon control = NULL;
1130605da56bSAndriy Gapon
1131b720fbf3STijl Coosemans if (linux_msg.msg_controllen >= sizeof(struct l_cmsghdr)) {
1132e1ff74c0SDmitry Chagin error = kern_getsockname(td, s, &sa, &datalen);
1133e1ff74c0SDmitry Chagin if (error != 0)
1134605da56bSAndriy Gapon goto bad;
1135605da56bSAndriy Gapon sa_family = sa->sa_family;
1136605da56bSAndriy Gapon free(sa, M_SONAME);
1137605da56bSAndriy Gapon
113874f5d680SKonstantin Belousov error = ENOBUFS;
1139eb1b1807SGleb Smirnoff control = m_get(M_WAITOK, MT_CONTROL);
1140edf16b7aSTijl Coosemans MCLGET(control, M_WAITOK);
1141edf16b7aSTijl Coosemans data = mtod(control, void *);
1142edf16b7aSTijl Coosemans datalen = 0;
114374f5d680SKonstantin Belousov
1144b720fbf3STijl Coosemans ptr_cmsg = PTRIN(linux_msg.msg_control);
1145b720fbf3STijl Coosemans clen = linux_msg.msg_controllen;
114674f5d680SKonstantin Belousov do {
114774f5d680SKonstantin Belousov error = copyin(ptr_cmsg, &linux_cmsg,
114874f5d680SKonstantin Belousov sizeof(struct l_cmsghdr));
1149e1ff74c0SDmitry Chagin if (error != 0)
115074f5d680SKonstantin Belousov goto bad;
115174f5d680SKonstantin Belousov
115274f5d680SKonstantin Belousov error = EINVAL;
1153b720fbf3STijl Coosemans if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr) ||
1154b720fbf3STijl Coosemans linux_cmsg.cmsg_len > clen)
115574f5d680SKonstantin Belousov goto bad;
115674f5d680SKonstantin Belousov
1157edf16b7aSTijl Coosemans if (datalen + CMSG_HDRSZ > MCLBYTES)
1158edf16b7aSTijl Coosemans goto bad;
1159edf16b7aSTijl Coosemans
116074f5d680SKonstantin Belousov /*
1161605da56bSAndriy Gapon * Now we support only SCM_RIGHTS and SCM_CRED,
1162605da56bSAndriy Gapon * so return EINVAL in any other cmsg_type
116374f5d680SKonstantin Belousov */
1164edf16b7aSTijl Coosemans cmsg = data;
1165605da56bSAndriy Gapon cmsg->cmsg_type =
1166605da56bSAndriy Gapon linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
116774f5d680SKonstantin Belousov cmsg->cmsg_level =
116874f5d680SKonstantin Belousov linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1169605da56bSAndriy Gapon if (cmsg->cmsg_type == -1
1170605da56bSAndriy Gapon || cmsg->cmsg_level != SOL_SOCKET)
1171605da56bSAndriy Gapon goto bad;
117274f5d680SKonstantin Belousov
1173605da56bSAndriy Gapon /*
1174605da56bSAndriy Gapon * Some applications (e.g. pulseaudio) attempt to
1175605da56bSAndriy Gapon * send ancillary data even if the underlying protocol
1176605da56bSAndriy Gapon * doesn't support it which is not allowed in the
1177605da56bSAndriy Gapon * FreeBSD system call interface.
1178605da56bSAndriy Gapon */
1179605da56bSAndriy Gapon if (sa_family != AF_UNIX)
1180605da56bSAndriy Gapon continue;
1181605da56bSAndriy Gapon
1182edf16b7aSTijl Coosemans if (cmsg->cmsg_type == SCM_CREDS) {
1183edf16b7aSTijl Coosemans len = sizeof(struct cmsgcred);
1184edf16b7aSTijl Coosemans if (datalen + CMSG_SPACE(len) > MCLBYTES)
1185edf16b7aSTijl Coosemans goto bad;
1186605da56bSAndriy Gapon
1187605da56bSAndriy Gapon /*
1188605da56bSAndriy Gapon * The lower levels will fill in the structure
1189605da56bSAndriy Gapon */
1190edf16b7aSTijl Coosemans memset(CMSG_DATA(data), 0, len);
1191edf16b7aSTijl Coosemans } else {
1192edf16b7aSTijl Coosemans len = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1193edf16b7aSTijl Coosemans if (datalen + CMSG_SPACE(len) < datalen ||
1194edf16b7aSTijl Coosemans datalen + CMSG_SPACE(len) > MCLBYTES)
1195edf16b7aSTijl Coosemans goto bad;
1196edf16b7aSTijl Coosemans
1197edf16b7aSTijl Coosemans error = copyin(LINUX_CMSG_DATA(ptr_cmsg),
1198edf16b7aSTijl Coosemans CMSG_DATA(data), len);
1199edf16b7aSTijl Coosemans if (error != 0)
1200edf16b7aSTijl Coosemans goto bad;
1201605da56bSAndriy Gapon }
1202605da56bSAndriy Gapon
1203edf16b7aSTijl Coosemans cmsg->cmsg_len = CMSG_LEN(len);
1204edf16b7aSTijl Coosemans data = (char *)data + CMSG_SPACE(len);
1205edf16b7aSTijl Coosemans datalen += CMSG_SPACE(len);
1206b720fbf3STijl Coosemans
1207b720fbf3STijl Coosemans if (clen <= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len))
1208b720fbf3STijl Coosemans break;
1209b720fbf3STijl Coosemans
1210b720fbf3STijl Coosemans clen -= LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len);
1211b720fbf3STijl Coosemans ptr_cmsg = (struct l_cmsghdr *)((char *)ptr_cmsg +
1212b720fbf3STijl Coosemans LINUX_CMSG_ALIGN(linux_cmsg.cmsg_len));
1213b720fbf3STijl Coosemans } while(clen >= sizeof(struct l_cmsghdr));
1214605da56bSAndriy Gapon
1215edf16b7aSTijl Coosemans control->m_len = datalen;
1216edf16b7aSTijl Coosemans if (datalen == 0) {
1217605da56bSAndriy Gapon m_freem(control);
121874f5d680SKonstantin Belousov control = NULL;
1219605da56bSAndriy Gapon }
122074f5d680SKonstantin Belousov }
122174f5d680SKonstantin Belousov
12225a8a13e0SDavid Malone msg.msg_iov = iov;
12235a8a13e0SDavid Malone msg.msg_flags = 0;
1224e1ff74c0SDmitry Chagin error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
122567968b35SDmitry Chagin control = NULL;
122674f5d680SKonstantin Belousov
122774f5d680SKonstantin Belousov bad:
12284f65e9cfSDmitry Chagin m_freem(control);
1229552afd9cSPoul-Henning Kamp free(iov, M_IOV);
1230ca26842eSHajimu UMEMOTO return (error);
1231c21dee17SSøren Schmidt }
1232c21dee17SSøren Schmidt
1233a12b9b3dSDmitry Chagin int
linux_sendmsg(struct thread * td,struct linux_sendmsg_args * args)1234e1ff74c0SDmitry Chagin linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1235e1ff74c0SDmitry Chagin {
1236e1ff74c0SDmitry Chagin
1237e1ff74c0SDmitry Chagin return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
1238e1ff74c0SDmitry Chagin args->flags));
1239e1ff74c0SDmitry Chagin }
1240e1ff74c0SDmitry Chagin
1241e1ff74c0SDmitry Chagin int
linux_sendmmsg(struct thread * td,struct linux_sendmmsg_args * args)1242e1ff74c0SDmitry Chagin linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
1243e1ff74c0SDmitry Chagin {
1244e1ff74c0SDmitry Chagin struct l_mmsghdr *msg;
1245e1ff74c0SDmitry Chagin l_uint retval;
1246e1ff74c0SDmitry Chagin int error, datagrams;
1247e1ff74c0SDmitry Chagin
1248e1ff74c0SDmitry Chagin if (args->vlen > UIO_MAXIOV)
1249e1ff74c0SDmitry Chagin args->vlen = UIO_MAXIOV;
1250e1ff74c0SDmitry Chagin
1251e1ff74c0SDmitry Chagin msg = PTRIN(args->msg);
1252e1ff74c0SDmitry Chagin datagrams = 0;
1253e1ff74c0SDmitry Chagin while (datagrams < args->vlen) {
1254e1ff74c0SDmitry Chagin error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
1255e1ff74c0SDmitry Chagin args->flags);
1256e1ff74c0SDmitry Chagin if (error != 0)
1257e1ff74c0SDmitry Chagin break;
1258e1ff74c0SDmitry Chagin
1259e1ff74c0SDmitry Chagin retval = td->td_retval[0];
1260e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1261e1ff74c0SDmitry Chagin if (error != 0)
1262e1ff74c0SDmitry Chagin break;
1263e1ff74c0SDmitry Chagin ++msg;
1264e1ff74c0SDmitry Chagin ++datagrams;
1265e1ff74c0SDmitry Chagin }
1266e1ff74c0SDmitry Chagin if (error == 0)
1267e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams;
1268e1ff74c0SDmitry Chagin return (error);
1269e1ff74c0SDmitry Chagin }
1270e1ff74c0SDmitry Chagin
1271e1ff74c0SDmitry Chagin static int
linux_recvmsg_common(struct thread * td,l_int s,struct l_msghdr * msghdr,l_uint flags,struct msghdr * msg)1272e1ff74c0SDmitry Chagin linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1273e1ff74c0SDmitry Chagin l_uint flags, struct msghdr *msg)
127440dbba57SAssar Westerlund {
127574f5d680SKonstantin Belousov struct cmsghdr *cm;
1276605da56bSAndriy Gapon struct cmsgcred *cmcred;
127774f5d680SKonstantin Belousov struct l_cmsghdr *linux_cmsg = NULL;
1278605da56bSAndriy Gapon struct l_ucred linux_ucred;
1279c7902fbeSMark Johnston socklen_t datalen, maxlen, outlen;
128074f5d680SKonstantin Belousov struct l_msghdr linux_msg;
128174f5d680SKonstantin Belousov struct iovec *iov, *uiov;
128274f5d680SKonstantin Belousov struct mbuf *control = NULL;
128374f5d680SKonstantin Belousov struct mbuf **controlp;
1284bbf392d5SDmitry Chagin struct timeval *ftmvl;
1285bbf392d5SDmitry Chagin l_timeval ltmvl;
128674f5d680SKonstantin Belousov caddr_t outbuf;
128774f5d680SKonstantin Belousov void *data;
12883a72bf04SDmitry Chagin int error, i, fd, fds, *fdp;
128940dbba57SAssar Westerlund
1290e1ff74c0SDmitry Chagin error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1291e1ff74c0SDmitry Chagin if (error != 0)
1292ca26842eSHajimu UMEMOTO return (error);
1293ca26842eSHajimu UMEMOTO
1294e1ff74c0SDmitry Chagin error = linux_to_bsd_msghdr(msg, &linux_msg);
1295e1ff74c0SDmitry Chagin if (error != 0)
129674f5d680SKonstantin Belousov return (error);
129774f5d680SKonstantin Belousov
129874f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
1299e1ff74c0SDmitry Chagin error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
130074f5d680SKonstantin Belousov &iov, EMSGSIZE);
130174f5d680SKonstantin Belousov #else
1302e1ff74c0SDmitry Chagin error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
130374f5d680SKonstantin Belousov #endif
1304e1ff74c0SDmitry Chagin if (error != 0)
130574f5d680SKonstantin Belousov return (error);
130674f5d680SKonstantin Belousov
1307e1ff74c0SDmitry Chagin if (msg->msg_name) {
1308e1ff74c0SDmitry Chagin error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
1309e1ff74c0SDmitry Chagin msg->msg_namelen);
1310e1ff74c0SDmitry Chagin if (error != 0)
131174f5d680SKonstantin Belousov goto bad;
131284b11cd8SMitsuru IWASAKI }
131384b11cd8SMitsuru IWASAKI
1314e1ff74c0SDmitry Chagin uiov = msg->msg_iov;
1315e1ff74c0SDmitry Chagin msg->msg_iov = iov;
1316e1ff74c0SDmitry Chagin controlp = (msg->msg_control != NULL) ? &control : NULL;
1317e1ff74c0SDmitry Chagin error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
1318e1ff74c0SDmitry Chagin msg->msg_iov = uiov;
1319e1ff74c0SDmitry Chagin if (error != 0)
132074f5d680SKonstantin Belousov goto bad;
132174f5d680SKonstantin Belousov
1322e1ff74c0SDmitry Chagin error = bsd_to_linux_msghdr(msg, &linux_msg);
1323e1ff74c0SDmitry Chagin if (error != 0)
132474f5d680SKonstantin Belousov goto bad;
132574f5d680SKonstantin Belousov
132674f5d680SKonstantin Belousov if (linux_msg.msg_name) {
132774f5d680SKonstantin Belousov error = bsd_to_linux_sockaddr((struct sockaddr *)
132874f5d680SKonstantin Belousov PTRIN(linux_msg.msg_name));
1329e1ff74c0SDmitry Chagin if (error != 0)
133074f5d680SKonstantin Belousov goto bad;
133174f5d680SKonstantin Belousov }
133274f5d680SKonstantin Belousov if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
133374f5d680SKonstantin Belousov error = linux_sa_put(PTRIN(linux_msg.msg_name));
1334e1ff74c0SDmitry Chagin if (error != 0)
133574f5d680SKonstantin Belousov goto bad;
133674f5d680SKonstantin Belousov }
133774f5d680SKonstantin Belousov
1338c7902fbeSMark Johnston maxlen = linux_msg.msg_controllen;
1339c7902fbeSMark Johnston linux_msg.msg_controllen = 0;
1340605da56bSAndriy Gapon if (control) {
1341e0d3ea8cSDmitry Chagin linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
1342605da56bSAndriy Gapon
1343e1ff74c0SDmitry Chagin msg->msg_control = mtod(control, struct cmsghdr *);
1344e1ff74c0SDmitry Chagin msg->msg_controllen = control->m_len;
1345605da56bSAndriy Gapon
1346e1ff74c0SDmitry Chagin cm = CMSG_FIRSTHDR(msg);
1347c7902fbeSMark Johnston outbuf = PTRIN(linux_msg.msg_control);
1348c7902fbeSMark Johnston outlen = 0;
134974f5d680SKonstantin Belousov while (cm != NULL) {
1350605da56bSAndriy Gapon linux_cmsg->cmsg_type =
1351605da56bSAndriy Gapon bsd_to_linux_cmsg_type(cm->cmsg_type);
1352605da56bSAndriy Gapon linux_cmsg->cmsg_level =
1353605da56bSAndriy Gapon bsd_to_linux_sockopt_level(cm->cmsg_level);
1354c7902fbeSMark Johnston if (linux_cmsg->cmsg_type == -1 ||
1355c7902fbeSMark Johnston cm->cmsg_level != SOL_SOCKET) {
135674f5d680SKonstantin Belousov error = EINVAL;
135774f5d680SKonstantin Belousov goto bad;
135874f5d680SKonstantin Belousov }
1359605da56bSAndriy Gapon
136074f5d680SKonstantin Belousov data = CMSG_DATA(cm);
136174f5d680SKonstantin Belousov datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
136274f5d680SKonstantin Belousov
1363c7902fbeSMark Johnston switch (cm->cmsg_type) {
1364605da56bSAndriy Gapon case SCM_RIGHTS:
1365e1ff74c0SDmitry Chagin if (flags & LINUX_MSG_CMSG_CLOEXEC) {
1366605da56bSAndriy Gapon fds = datalen / sizeof(int);
1367605da56bSAndriy Gapon fdp = data;
1368605da56bSAndriy Gapon for (i = 0; i < fds; i++) {
1369605da56bSAndriy Gapon fd = *fdp++;
1370605da56bSAndriy Gapon (void)kern_fcntl(td, fd,
1371605da56bSAndriy Gapon F_SETFD, FD_CLOEXEC);
1372605da56bSAndriy Gapon }
1373605da56bSAndriy Gapon }
1374605da56bSAndriy Gapon break;
1375605da56bSAndriy Gapon
1376605da56bSAndriy Gapon case SCM_CREDS:
1377605da56bSAndriy Gapon /*
1378605da56bSAndriy Gapon * Currently LOCAL_CREDS is never in
1379605da56bSAndriy Gapon * effect for Linux so no need to worry
1380605da56bSAndriy Gapon * about sockcred
1381605da56bSAndriy Gapon */
1382605da56bSAndriy Gapon if (datalen != sizeof(*cmcred)) {
1383605da56bSAndriy Gapon error = EMSGSIZE;
1384605da56bSAndriy Gapon goto bad;
1385605da56bSAndriy Gapon }
1386605da56bSAndriy Gapon cmcred = (struct cmsgcred *)data;
1387605da56bSAndriy Gapon bzero(&linux_ucred, sizeof(linux_ucred));
1388605da56bSAndriy Gapon linux_ucred.pid = cmcred->cmcred_pid;
1389605da56bSAndriy Gapon linux_ucred.uid = cmcred->cmcred_uid;
1390605da56bSAndriy Gapon linux_ucred.gid = cmcred->cmcred_gid;
1391605da56bSAndriy Gapon data = &linux_ucred;
1392605da56bSAndriy Gapon datalen = sizeof(linux_ucred);
1393605da56bSAndriy Gapon break;
1394bbf392d5SDmitry Chagin
1395bbf392d5SDmitry Chagin case SCM_TIMESTAMP:
1396bbf392d5SDmitry Chagin if (datalen != sizeof(struct timeval)) {
1397bbf392d5SDmitry Chagin error = EMSGSIZE;
1398bbf392d5SDmitry Chagin goto bad;
1399bbf392d5SDmitry Chagin }
1400bbf392d5SDmitry Chagin ftmvl = (struct timeval *)data;
1401bbf392d5SDmitry Chagin ltmvl.tv_sec = ftmvl->tv_sec;
1402bbf392d5SDmitry Chagin ltmvl.tv_usec = ftmvl->tv_usec;
1403bbf392d5SDmitry Chagin data = <mvl;
1404bbf392d5SDmitry Chagin datalen = sizeof(ltmvl);
1405bbf392d5SDmitry Chagin break;
1406605da56bSAndriy Gapon }
1407605da56bSAndriy Gapon
1408c7902fbeSMark Johnston if (outlen + LINUX_CMSG_LEN(datalen) > maxlen) {
140974f5d680SKonstantin Belousov if (outlen == 0) {
141074f5d680SKonstantin Belousov error = EMSGSIZE;
141174f5d680SKonstantin Belousov goto bad;
141274f5d680SKonstantin Belousov } else {
1413c7902fbeSMark Johnston linux_msg.msg_flags |= LINUX_MSG_CTRUNC;
1414c7902fbeSMark Johnston m_dispose_extcontrolm(control);
141574f5d680SKonstantin Belousov goto out;
141674f5d680SKonstantin Belousov }
141774f5d680SKonstantin Belousov }
141874f5d680SKonstantin Belousov
141974f5d680SKonstantin Belousov linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
142074f5d680SKonstantin Belousov
142174f5d680SKonstantin Belousov error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
1422dddb7e7fSDmitry Chagin if (error != 0)
142374f5d680SKonstantin Belousov goto bad;
142474f5d680SKonstantin Belousov outbuf += L_CMSG_HDRSZ;
142574f5d680SKonstantin Belousov
142674f5d680SKonstantin Belousov error = copyout(data, outbuf, datalen);
1427dddb7e7fSDmitry Chagin if (error != 0)
142874f5d680SKonstantin Belousov goto bad;
142974f5d680SKonstantin Belousov
143074f5d680SKonstantin Belousov outbuf += LINUX_CMSG_ALIGN(datalen);
143174f5d680SKonstantin Belousov outlen += LINUX_CMSG_LEN(datalen);
143274f5d680SKonstantin Belousov
1433e1ff74c0SDmitry Chagin cm = CMSG_NXTHDR(msg, cm);
143474f5d680SKonstantin Belousov }
1435c7902fbeSMark Johnston linux_msg.msg_controllen = outlen;
143674f5d680SKonstantin Belousov }
143774f5d680SKonstantin Belousov
143874f5d680SKonstantin Belousov out:
1439e1ff74c0SDmitry Chagin error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
144074f5d680SKonstantin Belousov
144174f5d680SKonstantin Belousov bad:
1442c7902fbeSMark Johnston if (control != NULL) {
1443c7902fbeSMark Johnston if (error != 0)
1444c7902fbeSMark Johnston m_dispose_extcontrolm(control);
144574f5d680SKonstantin Belousov m_freem(control);
1446c7902fbeSMark Johnston }
1447c7902fbeSMark Johnston free(iov, M_IOV);
1448e0d3ea8cSDmitry Chagin free(linux_cmsg, M_LINUX);
144974f5d680SKonstantin Belousov
1450ca26842eSHajimu UMEMOTO return (error);
145140dbba57SAssar Westerlund }
145240dbba57SAssar Westerlund
1453a12b9b3dSDmitry Chagin int
linux_recvmsg(struct thread * td,struct linux_recvmsg_args * args)1454e1ff74c0SDmitry Chagin linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1455e1ff74c0SDmitry Chagin {
1456e1ff74c0SDmitry Chagin struct msghdr bsd_msg;
1457e1ff74c0SDmitry Chagin
1458e1ff74c0SDmitry Chagin return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
1459e1ff74c0SDmitry Chagin args->flags, &bsd_msg));
1460e1ff74c0SDmitry Chagin }
1461e1ff74c0SDmitry Chagin
1462e1ff74c0SDmitry Chagin int
linux_recvmmsg(struct thread * td,struct linux_recvmmsg_args * args)1463e1ff74c0SDmitry Chagin linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
1464e1ff74c0SDmitry Chagin {
1465e1ff74c0SDmitry Chagin struct l_mmsghdr *msg;
1466e1ff74c0SDmitry Chagin struct msghdr bsd_msg;
1467e1ff74c0SDmitry Chagin struct l_timespec lts;
1468e1ff74c0SDmitry Chagin struct timespec ts, tts;
1469e1ff74c0SDmitry Chagin l_uint retval;
1470e1ff74c0SDmitry Chagin int error, datagrams;
1471e1ff74c0SDmitry Chagin
1472e1ff74c0SDmitry Chagin if (args->timeout) {
1473e1ff74c0SDmitry Chagin error = copyin(args->timeout, <s, sizeof(struct l_timespec));
1474e1ff74c0SDmitry Chagin if (error != 0)
1475e1ff74c0SDmitry Chagin return (error);
1476e1ff74c0SDmitry Chagin error = linux_to_native_timespec(&ts, <s);
1477e1ff74c0SDmitry Chagin if (error != 0)
1478e1ff74c0SDmitry Chagin return (error);
1479e1ff74c0SDmitry Chagin getnanotime(&tts);
14806040822cSAlan Somers timespecadd(&tts, &ts, &tts);
1481e1ff74c0SDmitry Chagin }
1482e1ff74c0SDmitry Chagin
1483e1ff74c0SDmitry Chagin msg = PTRIN(args->msg);
1484e1ff74c0SDmitry Chagin datagrams = 0;
1485e1ff74c0SDmitry Chagin while (datagrams < args->vlen) {
1486e1ff74c0SDmitry Chagin error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
1487e1ff74c0SDmitry Chagin args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
1488e1ff74c0SDmitry Chagin if (error != 0)
1489e1ff74c0SDmitry Chagin break;
1490e1ff74c0SDmitry Chagin
1491e1ff74c0SDmitry Chagin retval = td->td_retval[0];
1492e1ff74c0SDmitry Chagin error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1493e1ff74c0SDmitry Chagin if (error != 0)
1494e1ff74c0SDmitry Chagin break;
1495e1ff74c0SDmitry Chagin ++msg;
1496e1ff74c0SDmitry Chagin ++datagrams;
1497e1ff74c0SDmitry Chagin
1498e1ff74c0SDmitry Chagin /*
1499e1ff74c0SDmitry Chagin * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
1500e1ff74c0SDmitry Chagin */
1501e1ff74c0SDmitry Chagin if (args->flags & LINUX_MSG_WAITFORONE)
1502e1ff74c0SDmitry Chagin args->flags |= LINUX_MSG_DONTWAIT;
1503e1ff74c0SDmitry Chagin
1504e1ff74c0SDmitry Chagin /*
1505e1ff74c0SDmitry Chagin * See BUGS section of recvmmsg(2).
1506e1ff74c0SDmitry Chagin */
1507e1ff74c0SDmitry Chagin if (args->timeout) {
1508e1ff74c0SDmitry Chagin getnanotime(&ts);
15096040822cSAlan Somers timespecsub(&ts, &tts, &ts);
1510e1ff74c0SDmitry Chagin if (!timespecisset(&ts) || ts.tv_sec > 0)
1511e1ff74c0SDmitry Chagin break;
1512e1ff74c0SDmitry Chagin }
1513e1ff74c0SDmitry Chagin /* Out of band data, return right away. */
1514e1ff74c0SDmitry Chagin if (bsd_msg.msg_flags & MSG_OOB)
1515e1ff74c0SDmitry Chagin break;
1516e1ff74c0SDmitry Chagin }
1517e1ff74c0SDmitry Chagin if (error == 0)
1518e1ff74c0SDmitry Chagin td->td_retval[0] = datagrams;
1519e1ff74c0SDmitry Chagin return (error);
1520e1ff74c0SDmitry Chagin }
1521e1ff74c0SDmitry Chagin
1522e1ff74c0SDmitry Chagin int
linux_shutdown(struct thread * td,struct linux_shutdown_args * args)1523b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1524c21dee17SSøren Schmidt {
1525c21dee17SSøren Schmidt
1526d293f35cSEdward Tomasz Napierala return (kern_shutdown(td, args->s, args->how));
1527c21dee17SSøren Schmidt }
1528c21dee17SSøren Schmidt
1529a12b9b3dSDmitry Chagin int
linux_setsockopt(struct thread * td,struct linux_setsockopt_args * args)1530b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1531c21dee17SSøren Schmidt {
1532ef04503dSPeter Wemm struct setsockopt_args /* {
1533c21dee17SSøren Schmidt int s;
1534c21dee17SSøren Schmidt int level;
1535c21dee17SSøren Schmidt int name;
1536c21dee17SSøren Schmidt caddr_t val;
1537c21dee17SSøren Schmidt int valsize;
1538ef04503dSPeter Wemm } */ bsd_args;
153903cc95d2SDmitry Chagin l_timeval linux_tv;
154003cc95d2SDmitry Chagin struct timeval tv;
1541c21dee17SSøren Schmidt int error, name;
1542c21dee17SSøren Schmidt
1543745aaef5SKonstantin Belousov bsd_args.s = args->s;
1544745aaef5SKonstantin Belousov bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1545c21dee17SSøren Schmidt switch (bsd_args.level) {
1546c21dee17SSøren Schmidt case SOL_SOCKET:
1547745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname);
154803cc95d2SDmitry Chagin switch (name) {
154903cc95d2SDmitry Chagin case SO_RCVTIMEO:
155003cc95d2SDmitry Chagin /* FALLTHROUGH */
155103cc95d2SDmitry Chagin case SO_SNDTIMEO:
155203cc95d2SDmitry Chagin error = copyin(PTRIN(args->optval), &linux_tv,
155303cc95d2SDmitry Chagin sizeof(linux_tv));
1554dddb7e7fSDmitry Chagin if (error != 0)
155503cc95d2SDmitry Chagin return (error);
155603cc95d2SDmitry Chagin tv.tv_sec = linux_tv.tv_sec;
155703cc95d2SDmitry Chagin tv.tv_usec = linux_tv.tv_usec;
155803cc95d2SDmitry Chagin return (kern_setsockopt(td, args->s, bsd_args.level,
155903cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, sizeof(tv)));
156003cc95d2SDmitry Chagin /* NOTREACHED */
156103cc95d2SDmitry Chagin default:
156203cc95d2SDmitry Chagin break;
156303cc95d2SDmitry Chagin }
1564c21dee17SSøren Schmidt break;
1565c21dee17SSøren Schmidt case IPPROTO_IP:
1566745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname);
1567c21dee17SSøren Schmidt break;
156886a9058bSAndrey V. Elsukov case IPPROTO_IPV6:
156986a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname);
157086a9058bSAndrey V. Elsukov break;
1571dad3b88aSMike Smith case IPPROTO_TCP:
1572fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname);
1573dad3b88aSMike Smith break;
1574c21dee17SSøren Schmidt default:
15753f3a4815SMarcel Moolenaar name = -1;
15763f3a4815SMarcel Moolenaar break;
1577c21dee17SSøren Schmidt }
1578c21dee17SSøren Schmidt if (name == -1)
1579d4b7423fSAlexander Leidinger return (ENOPROTOOPT);
15803f3a4815SMarcel Moolenaar
1581c21dee17SSøren Schmidt bsd_args.name = name;
1582745aaef5SKonstantin Belousov bsd_args.val = PTRIN(args->optval);
1583745aaef5SKonstantin Belousov bsd_args.valsize = args->optlen;
15845c8919adSAlexander Leidinger
15855c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) {
15865c8919adSAlexander Leidinger linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
15875c8919adSAlexander Leidinger bsd_args.valsize);
15888451d0ddSKip Macy error = sys_setsockopt(td, &bsd_args);
15895c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
15905c8919adSAlexander Leidinger } else
15918451d0ddSKip Macy error = sys_setsockopt(td, &bsd_args);
15925c8919adSAlexander Leidinger
15935c8919adSAlexander Leidinger return (error);
1594c21dee17SSøren Schmidt }
1595c21dee17SSøren Schmidt
1596a12b9b3dSDmitry Chagin int
linux_getsockopt(struct thread * td,struct linux_getsockopt_args * args)1597b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1598c21dee17SSøren Schmidt {
1599ef04503dSPeter Wemm struct getsockopt_args /* {
1600c21dee17SSøren Schmidt int s;
1601c21dee17SSøren Schmidt int level;
1602c21dee17SSøren Schmidt int name;
1603c21dee17SSøren Schmidt caddr_t val;
1604c21dee17SSøren Schmidt int *avalsize;
1605ef04503dSPeter Wemm } */ bsd_args;
160603cc95d2SDmitry Chagin l_timeval linux_tv;
160703cc95d2SDmitry Chagin struct timeval tv;
1608d56e689eSDmitry Chagin socklen_t tv_len, xulen, len;
1609d4dd69c4SDmitry Chagin struct xucred xu;
1610d4dd69c4SDmitry Chagin struct l_ucred lxu;
1611d56e689eSDmitry Chagin int error, name, newval;
1612c21dee17SSøren Schmidt
1613745aaef5SKonstantin Belousov bsd_args.s = args->s;
1614745aaef5SKonstantin Belousov bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1615c21dee17SSøren Schmidt switch (bsd_args.level) {
1616c21dee17SSøren Schmidt case SOL_SOCKET:
1617745aaef5SKonstantin Belousov name = linux_to_bsd_so_sockopt(args->optname);
161803cc95d2SDmitry Chagin switch (name) {
161903cc95d2SDmitry Chagin case SO_RCVTIMEO:
162003cc95d2SDmitry Chagin /* FALLTHROUGH */
162103cc95d2SDmitry Chagin case SO_SNDTIMEO:
162203cc95d2SDmitry Chagin tv_len = sizeof(tv);
162303cc95d2SDmitry Chagin error = kern_getsockopt(td, args->s, bsd_args.level,
162403cc95d2SDmitry Chagin name, &tv, UIO_SYSSPACE, &tv_len);
1625dddb7e7fSDmitry Chagin if (error != 0)
162603cc95d2SDmitry Chagin return (error);
162703cc95d2SDmitry Chagin linux_tv.tv_sec = tv.tv_sec;
162803cc95d2SDmitry Chagin linux_tv.tv_usec = tv.tv_usec;
162903cc95d2SDmitry Chagin return (copyout(&linux_tv, PTRIN(args->optval),
163003cc95d2SDmitry Chagin sizeof(linux_tv)));
163103cc95d2SDmitry Chagin /* NOTREACHED */
1632d4dd69c4SDmitry Chagin case LOCAL_PEERCRED:
1633cd92d27eSDmitry Chagin if (args->optlen < sizeof(lxu))
1634d4dd69c4SDmitry Chagin return (EINVAL);
1635*24403315SMark Johnston /*
1636*24403315SMark Johnston * LOCAL_PEERCRED is not served at the SOL_SOCKET level,
1637*24403315SMark Johnston * but by the Unix socket's level 0.
1638*24403315SMark Johnston */
1639*24403315SMark Johnston bsd_args.level = 0;
1640d4dd69c4SDmitry Chagin xulen = sizeof(xu);
1641d4dd69c4SDmitry Chagin error = kern_getsockopt(td, args->s, bsd_args.level,
1642d4dd69c4SDmitry Chagin name, &xu, UIO_SYSSPACE, &xulen);
1643dddb7e7fSDmitry Chagin if (error != 0)
1644d4dd69c4SDmitry Chagin return (error);
1645d4dd69c4SDmitry Chagin /*
1646d4dd69c4SDmitry Chagin * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1647d4dd69c4SDmitry Chagin */
1648d4dd69c4SDmitry Chagin lxu.pid = 0;
1649d4dd69c4SDmitry Chagin lxu.uid = xu.cr_uid;
1650d4dd69c4SDmitry Chagin lxu.gid = xu.cr_gid;
1651d4dd69c4SDmitry Chagin return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1652d4dd69c4SDmitry Chagin /* NOTREACHED */
1653d56e689eSDmitry Chagin case SO_ERROR:
1654d56e689eSDmitry Chagin len = sizeof(newval);
1655d56e689eSDmitry Chagin error = kern_getsockopt(td, args->s, bsd_args.level,
1656d56e689eSDmitry Chagin name, &newval, UIO_SYSSPACE, &len);
1657dddb7e7fSDmitry Chagin if (error != 0)
1658d56e689eSDmitry Chagin return (error);
1659d56e689eSDmitry Chagin newval = -SV_ABI_ERRNO(td->td_proc, newval);
1660d56e689eSDmitry Chagin return (copyout(&newval, PTRIN(args->optval), len));
1661d56e689eSDmitry Chagin /* NOTREACHED */
166203cc95d2SDmitry Chagin default:
166303cc95d2SDmitry Chagin break;
166403cc95d2SDmitry Chagin }
1665c21dee17SSøren Schmidt break;
1666c21dee17SSøren Schmidt case IPPROTO_IP:
1667745aaef5SKonstantin Belousov name = linux_to_bsd_ip_sockopt(args->optname);
1668c21dee17SSøren Schmidt break;
166986a9058bSAndrey V. Elsukov case IPPROTO_IPV6:
167086a9058bSAndrey V. Elsukov name = linux_to_bsd_ip6_sockopt(args->optname);
167186a9058bSAndrey V. Elsukov break;
1672dad3b88aSMike Smith case IPPROTO_TCP:
1673fb709557SJohn Baldwin name = linux_to_bsd_tcp_sockopt(args->optname);
1674dad3b88aSMike Smith break;
1675c21dee17SSøren Schmidt default:
16763f3a4815SMarcel Moolenaar name = -1;
16773f3a4815SMarcel Moolenaar break;
1678c21dee17SSøren Schmidt }
1679c21dee17SSøren Schmidt if (name == -1)
16803f3a4815SMarcel Moolenaar return (EINVAL);
16813f3a4815SMarcel Moolenaar
1682f2477ae1SMike Smith bsd_args.name = name;
1683745aaef5SKonstantin Belousov bsd_args.val = PTRIN(args->optval);
1684745aaef5SKonstantin Belousov bsd_args.avalsize = PTRIN(args->optlen);
16855c8919adSAlexander Leidinger
16865c8919adSAlexander Leidinger if (name == IPV6_NEXTHOP) {
16878451d0ddSKip Macy error = sys_getsockopt(td, &bsd_args);
16885c8919adSAlexander Leidinger bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
16895c8919adSAlexander Leidinger } else
16908451d0ddSKip Macy error = sys_getsockopt(td, &bsd_args);
16915c8919adSAlexander Leidinger
16925c8919adSAlexander Leidinger return (error);
1693c21dee17SSøren Schmidt }
1694c21dee17SSøren Schmidt
16957f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
16967f8f1d7fSDmitry Chagin
1697ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */
1698abf20e93SDmitry Chagin static const unsigned char lxs_args_cnt[] = {
1699abf20e93SDmitry Chagin 0 /* unused*/, 3 /* socket */,
1700abf20e93SDmitry Chagin 3 /* bind */, 3 /* connect */,
1701abf20e93SDmitry Chagin 2 /* listen */, 3 /* accept */,
1702abf20e93SDmitry Chagin 3 /* getsockname */, 3 /* getpeername */,
1703abf20e93SDmitry Chagin 4 /* socketpair */, 4 /* send */,
1704abf20e93SDmitry Chagin 4 /* recv */, 6 /* sendto */,
1705abf20e93SDmitry Chagin 6 /* recvfrom */, 2 /* shutdown */,
1706abf20e93SDmitry Chagin 5 /* setsockopt */, 5 /* getsockopt */,
1707abf20e93SDmitry Chagin 3 /* sendmsg */, 3 /* recvmsg */,
1708abf20e93SDmitry Chagin 4 /* accept4 */, 5 /* recvmmsg */,
1709abf20e93SDmitry Chagin 4 /* sendmmsg */
1710ea7b81d2SDmitry Chagin };
1711abf20e93SDmitry Chagin #define LINUX_ARGS_CNT (nitems(lxs_args_cnt) - 1)
1712abf20e93SDmitry Chagin #define LINUX_ARG_SIZE(x) (lxs_args_cnt[x] * sizeof(l_ulong))
1713ea7b81d2SDmitry Chagin
1714c21dee17SSøren Schmidt int
linux_socketcall(struct thread * td,struct linux_socketcall_args * args)1715b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1716c21dee17SSøren Schmidt {
1717ea7b81d2SDmitry Chagin l_ulong a[6];
1718abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32)
1719abf20e93SDmitry Chagin register_t l_args[6];
1720abf20e93SDmitry Chagin #endif
1721ea7b81d2SDmitry Chagin void *arg;
1722ea7b81d2SDmitry Chagin int error;
17233f3a4815SMarcel Moolenaar
1724abf20e93SDmitry Chagin if (args->what < LINUX_SOCKET || args->what > LINUX_ARGS_CNT)
1725ea7b81d2SDmitry Chagin return (EINVAL);
1726abf20e93SDmitry Chagin error = copyin(PTRIN(args->args), a, LINUX_ARG_SIZE(args->what));
1727abf20e93SDmitry Chagin if (error != 0)
1728ea7b81d2SDmitry Chagin return (error);
1729ea7b81d2SDmitry Chagin
1730abf20e93SDmitry Chagin #if defined(__amd64__) && defined(COMPAT_LINUX32)
1731abf20e93SDmitry Chagin for (int i = 0; i < lxs_args_cnt[args->what]; ++i)
1732abf20e93SDmitry Chagin l_args[i] = a[i];
1733abf20e93SDmitry Chagin arg = l_args;
1734abf20e93SDmitry Chagin #else
1735ea7b81d2SDmitry Chagin arg = a;
1736abf20e93SDmitry Chagin #endif
1737c21dee17SSøren Schmidt switch (args->what) {
1738c21dee17SSøren Schmidt case LINUX_SOCKET:
1739b40ce416SJulian Elischer return (linux_socket(td, arg));
1740c21dee17SSøren Schmidt case LINUX_BIND:
1741b40ce416SJulian Elischer return (linux_bind(td, arg));
1742c21dee17SSøren Schmidt case LINUX_CONNECT:
1743b40ce416SJulian Elischer return (linux_connect(td, arg));
1744c21dee17SSøren Schmidt case LINUX_LISTEN:
1745b40ce416SJulian Elischer return (linux_listen(td, arg));
1746c21dee17SSøren Schmidt case LINUX_ACCEPT:
1747b40ce416SJulian Elischer return (linux_accept(td, arg));
1748c21dee17SSøren Schmidt case LINUX_GETSOCKNAME:
1749b40ce416SJulian Elischer return (linux_getsockname(td, arg));
1750c21dee17SSøren Schmidt case LINUX_GETPEERNAME:
1751b40ce416SJulian Elischer return (linux_getpeername(td, arg));
1752c21dee17SSøren Schmidt case LINUX_SOCKETPAIR:
1753b40ce416SJulian Elischer return (linux_socketpair(td, arg));
1754c21dee17SSøren Schmidt case LINUX_SEND:
1755b40ce416SJulian Elischer return (linux_send(td, arg));
1756c21dee17SSøren Schmidt case LINUX_RECV:
1757b40ce416SJulian Elischer return (linux_recv(td, arg));
1758c21dee17SSøren Schmidt case LINUX_SENDTO:
1759b40ce416SJulian Elischer return (linux_sendto(td, arg));
1760c21dee17SSøren Schmidt case LINUX_RECVFROM:
1761b40ce416SJulian Elischer return (linux_recvfrom(td, arg));
1762c21dee17SSøren Schmidt case LINUX_SHUTDOWN:
1763b40ce416SJulian Elischer return (linux_shutdown(td, arg));
1764c21dee17SSøren Schmidt case LINUX_SETSOCKOPT:
1765b40ce416SJulian Elischer return (linux_setsockopt(td, arg));
1766c21dee17SSøren Schmidt case LINUX_GETSOCKOPT:
1767b40ce416SJulian Elischer return (linux_getsockopt(td, arg));
1768e76bba09SSøren Schmidt case LINUX_SENDMSG:
1769ca26842eSHajimu UMEMOTO return (linux_sendmsg(td, arg));
1770e76bba09SSøren Schmidt case LINUX_RECVMSG:
1771b40ce416SJulian Elischer return (linux_recvmsg(td, arg));
1772f8cd0af2SDmitry Chagin case LINUX_ACCEPT4:
1773f8cd0af2SDmitry Chagin return (linux_accept4(td, arg));
1774e1ff74c0SDmitry Chagin case LINUX_RECVMMSG:
1775e1ff74c0SDmitry Chagin return (linux_recvmmsg(td, arg));
1776e1ff74c0SDmitry Chagin case LINUX_SENDMMSG:
1777e1ff74c0SDmitry Chagin return (linux_sendmmsg(td, arg));
1778c21dee17SSøren Schmidt }
17793f3a4815SMarcel Moolenaar
17803f3a4815SMarcel Moolenaar uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
17813f3a4815SMarcel Moolenaar return (ENOSYS);
1782c21dee17SSøren Schmidt }
1783a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1784