xref: /netbsd-src/sys/rump/net/lib/libsockin/sockin.c (revision 97fd514741cb0308e7752e47d37b8784c4819a33)
1*97fd5147Sthorpej /*	$NetBSD: sockin.c,v 1.67 2022/09/03 02:53:18 thorpej Exp $	*/
2ad9bbd7bSpooka 
3ad9bbd7bSpooka /*
439cb5b51Spooka  * Copyright (c) 2008, 2009 Antti Kantee.  All Rights Reserved.
5ad9bbd7bSpooka  *
6ad9bbd7bSpooka  * Redistribution and use in source and binary forms, with or without
7ad9bbd7bSpooka  * modification, are permitted provided that the following conditions
8ad9bbd7bSpooka  * are met:
9ad9bbd7bSpooka  * 1. Redistributions of source code must retain the above copyright
10ad9bbd7bSpooka  *    notice, this list of conditions and the following disclaimer.
11ad9bbd7bSpooka  * 2. Redistributions in binary form must reproduce the above copyright
12ad9bbd7bSpooka  *    notice, this list of conditions and the following disclaimer in the
13ad9bbd7bSpooka  *    documentation and/or other materials provided with the distribution.
14ad9bbd7bSpooka  *
15ad9bbd7bSpooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16ad9bbd7bSpooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17ad9bbd7bSpooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18ad9bbd7bSpooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19ad9bbd7bSpooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20ad9bbd7bSpooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21ad9bbd7bSpooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22ad9bbd7bSpooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23ad9bbd7bSpooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24ad9bbd7bSpooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25ad9bbd7bSpooka  * SUCH DAMAGE.
26ad9bbd7bSpooka  */
27ad9bbd7bSpooka 
28a768afd6Spooka #include <sys/cdefs.h>
29*97fd5147Sthorpej __KERNEL_RCSID(0, "$NetBSD: sockin.c,v 1.67 2022/09/03 02:53:18 thorpej Exp $");
30a768afd6Spooka 
31ad9bbd7bSpooka #include <sys/param.h>
32ad9bbd7bSpooka #include <sys/condvar.h>
33ad9bbd7bSpooka #include <sys/domain.h>
34ad9bbd7bSpooka #include <sys/kmem.h>
35ad9bbd7bSpooka #include <sys/kthread.h>
36ad9bbd7bSpooka #include <sys/mbuf.h>
37ad9bbd7bSpooka #include <sys/mutex.h>
3853da9055Sstacktic #include <sys/once.h>
39ad9bbd7bSpooka #include <sys/poll.h>
40ad9bbd7bSpooka #include <sys/protosw.h>
41ad9bbd7bSpooka #include <sys/queue.h>
42ad9bbd7bSpooka #include <sys/socket.h>
43ad9bbd7bSpooka #include <sys/socketvar.h>
44ad9bbd7bSpooka #include <sys/time.h>
45ad9bbd7bSpooka 
463694a148Spooka #include <net/bpf.h>
473694a148Spooka #include <net/if.h>
48d6457e83Spooka #include <net/radix.h>
49d6457e83Spooka 
50ad9bbd7bSpooka #include <netinet/in.h>
51ad9bbd7bSpooka #include <netinet/in_systm.h>
52ad9bbd7bSpooka #include <netinet/ip.h>
53ad9bbd7bSpooka 
546bb51422Spooka #include <rump-sys/kern.h>
556bb51422Spooka 
56ad9bbd7bSpooka #include <rump/rumpuser.h>
57ad9bbd7bSpooka 
5800328592Spooka #include "sockin_user.h"
5939cb5b51Spooka 
60ad9bbd7bSpooka /*
61ad9bbd7bSpooka  * An inet communication domain which uses the socket interface.
6275b2fca2Spooka  * Supports IPv4 & IPv6 UDP/TCP.
63ad9bbd7bSpooka  */
64ad9bbd7bSpooka 
65ad9bbd7bSpooka DOMAIN_DEFINE(sockindomain);
663df1f0e3Sstacktic DOMAIN_DEFINE(sockin6domain);
673df1f0e3Sstacktic 
6853da9055Sstacktic static int	sockin_do_init(void);
69ad9bbd7bSpooka static void	sockin_init(void);
704ae03c18Srmind static int	sockin_attach(struct socket *, int);
714ae03c18Srmind static void	sockin_detach(struct socket *);
72eddf3af3Srtr static int	sockin_accept(struct socket *, struct sockaddr *);
738cf67cc6Srtr static int	sockin_connect2(struct socket *, struct socket *);
74a2ba5e69Srtr static int	sockin_bind(struct socket *, struct sockaddr *, struct lwp *);
75ce6a5ff6Srtr static int	sockin_listen(struct socket *, struct lwp *);
76fd12cf39Srtr static int	sockin_connect(struct socket *, struct sockaddr *, struct lwp *);
77892163b8Srtr static int	sockin_disconnect(struct socket *);
78892163b8Srtr static int	sockin_shutdown(struct socket *);
79892163b8Srtr static int	sockin_abort(struct socket *);
800dedd977Srtr static int	sockin_ioctl(struct socket *, u_long, void *, struct ifnet *);
810f199192Srtr static int	sockin_stat(struct socket *, struct stat *);
82eddf3af3Srtr static int	sockin_peeraddr(struct socket *, struct sockaddr *);
83eddf3af3Srtr static int	sockin_sockaddr(struct socket *, struct sockaddr *);
84822872eaSrtr static int	sockin_rcvd(struct socket *, int, struct lwp *);
8535b22fa9Srtr static int	sockin_recvoob(struct socket *, struct mbuf *, int);
86fd12cf39Srtr static int	sockin_send(struct socket *, struct mbuf *, struct sockaddr *,
87651e5bd3Srtr 			    struct mbuf *, struct lwp *);
8835b22fa9Srtr static int	sockin_sendoob(struct socket *, struct mbuf *, struct mbuf *);
898cf67cc6Srtr static int	sockin_purgeif(struct socket *, struct ifnet *);
90eaff187cSpooka static int	sockin_ctloutput(int op, struct socket *, struct sockopt *);
91ad9bbd7bSpooka 
9237af0cc7Srmind static const struct pr_usrreqs sockin_usrreqs = {
934ae03c18Srmind 	.pr_attach = sockin_attach,
944ae03c18Srmind 	.pr_detach = sockin_detach,
95d27b133dSrtr 	.pr_accept = sockin_accept,
966dd8eef0Srtr 	.pr_bind = sockin_bind,
976dd8eef0Srtr 	.pr_listen = sockin_listen,
98ad6ae402Srtr 	.pr_connect = sockin_connect,
998cf67cc6Srtr 	.pr_connect2 = sockin_connect2,
100892163b8Srtr 	.pr_disconnect = sockin_disconnect,
101892163b8Srtr 	.pr_shutdown = sockin_shutdown,
102892163b8Srtr 	.pr_abort = sockin_abort,
103d54d7ab2Srtr 	.pr_ioctl = sockin_ioctl,
1040f199192Srtr 	.pr_stat = sockin_stat,
105d575eb54Srtr 	.pr_peeraddr = sockin_peeraddr,
106d575eb54Srtr 	.pr_sockaddr = sockin_sockaddr,
107822872eaSrtr 	.pr_rcvd = sockin_rcvd,
10835b22fa9Srtr 	.pr_recvoob = sockin_recvoob,
109651e5bd3Srtr 	.pr_send = sockin_send,
11035b22fa9Srtr 	.pr_sendoob = sockin_sendoob,
1118cf67cc6Srtr 	.pr_purgeif = sockin_purgeif,
11237af0cc7Srmind };
11337af0cc7Srmind 
114ad9bbd7bSpooka const struct protosw sockinsw[] = {
1157dd6651aSpooka {
1167dd6651aSpooka 	.pr_type = SOCK_DGRAM,
117ad9bbd7bSpooka 	.pr_domain = &sockindomain,
118ad9bbd7bSpooka 	.pr_protocol = IPPROTO_UDP,
119ad9bbd7bSpooka 	.pr_flags = PR_ATOMIC|PR_ADDR,
12037af0cc7Srmind 	.pr_usrreqs = &sockin_usrreqs,
121eaff187cSpooka 	.pr_ctloutput = sockin_ctloutput,
1227dd6651aSpooka },
1237dd6651aSpooka {
1247dd6651aSpooka 	.pr_type = SOCK_STREAM,
1257dd6651aSpooka 	.pr_domain = &sockindomain,
1267dd6651aSpooka 	.pr_protocol = IPPROTO_TCP,
1277dd6651aSpooka 	.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS,
12837af0cc7Srmind 	.pr_usrreqs = &sockin_usrreqs,
129eaff187cSpooka 	.pr_ctloutput = sockin_ctloutput,
130ad9bbd7bSpooka }};
1313df1f0e3Sstacktic const struct protosw sockin6sw[] = {
1323df1f0e3Sstacktic {
1333df1f0e3Sstacktic 	.pr_type = SOCK_DGRAM,
1343df1f0e3Sstacktic 	.pr_domain = &sockin6domain,
1353df1f0e3Sstacktic 	.pr_protocol = IPPROTO_UDP,
1363df1f0e3Sstacktic 	.pr_flags = PR_ATOMIC|PR_ADDR,
13737af0cc7Srmind 	.pr_usrreqs = &sockin_usrreqs,
1383df1f0e3Sstacktic 	.pr_ctloutput = sockin_ctloutput,
1393df1f0e3Sstacktic },
1403df1f0e3Sstacktic {
1413df1f0e3Sstacktic 	.pr_type = SOCK_STREAM,
1423df1f0e3Sstacktic 	.pr_domain = &sockin6domain,
1433df1f0e3Sstacktic 	.pr_protocol = IPPROTO_TCP,
1443df1f0e3Sstacktic 	.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS,
14537af0cc7Srmind 	.pr_usrreqs = &sockin_usrreqs,
1463df1f0e3Sstacktic 	.pr_ctloutput = sockin_ctloutput,
1473df1f0e3Sstacktic }};
148ad9bbd7bSpooka 
149ad9bbd7bSpooka struct domain sockindomain = {
150ad9bbd7bSpooka 	.dom_family = PF_INET,
151ad9bbd7bSpooka 	.dom_name = "socket_inet",
1527dd6651aSpooka 	.dom_init = sockin_init,
153ad9bbd7bSpooka 	.dom_externalize = NULL,
154ad9bbd7bSpooka 	.dom_dispose = NULL,
155ad9bbd7bSpooka 	.dom_protosw = sockinsw,
1567dd6651aSpooka 	.dom_protoswNPROTOSW = &sockinsw[__arraycount(sockinsw)],
157060522deSdyoung 	.dom_rtattach = rt_inithead,
158d6457e83Spooka 	.dom_rtoffset = 32,
159d6457e83Spooka 	.dom_maxrtkey = sizeof(struct sockaddr_in),
160ad9bbd7bSpooka 	.dom_ifattach = NULL,
161ad9bbd7bSpooka 	.dom_ifdetach = NULL,
162ad9bbd7bSpooka 	.dom_link = { NULL },
163ad9bbd7bSpooka 	.dom_mowner = MOWNER_INIT("",""),
164ad9bbd7bSpooka 	.dom_sockaddr_cmp = NULL
165ad9bbd7bSpooka };
1663df1f0e3Sstacktic struct domain sockin6domain = {
1673df1f0e3Sstacktic 	.dom_family = PF_INET6,
1683df1f0e3Sstacktic 	.dom_name = "socket_inet6",
1693df1f0e3Sstacktic 	.dom_init = sockin_init,
1703df1f0e3Sstacktic 	.dom_externalize = NULL,
1713df1f0e3Sstacktic 	.dom_dispose = NULL,
1723df1f0e3Sstacktic 	.dom_protosw = sockin6sw,
1733df1f0e3Sstacktic 	.dom_protoswNPROTOSW = &sockin6sw[__arraycount(sockin6sw)],
1743df1f0e3Sstacktic 	.dom_rtattach = rt_inithead,
1753df1f0e3Sstacktic 	.dom_rtoffset = 32,
1763df1f0e3Sstacktic 	.dom_maxrtkey = sizeof(struct sockaddr_in6),
1773df1f0e3Sstacktic 	.dom_ifattach = NULL,
1783df1f0e3Sstacktic 	.dom_ifdetach = NULL,
1793df1f0e3Sstacktic 	.dom_link = { NULL },
1803df1f0e3Sstacktic 	.dom_mowner = MOWNER_INIT("",""),
1813df1f0e3Sstacktic 	.dom_sockaddr_cmp = NULL
1823df1f0e3Sstacktic };
183ad9bbd7bSpooka 
1848447026cSpooka #define SO2S(so) ((intptr_t)(so->so_internal))
1857dd6651aSpooka #define SOCKIN_SBSIZE 65536
186ad9bbd7bSpooka 
187eebcd280Spooka struct sockin_unit {
188eebcd280Spooka 	struct socket *su_so;
189eebcd280Spooka 
190eebcd280Spooka 	LIST_ENTRY(sockin_unit) su_entries;
191eebcd280Spooka };
192eebcd280Spooka static LIST_HEAD(, sockin_unit) su_ent = LIST_HEAD_INITIALIZER(su_ent);
193eebcd280Spooka static kmutex_t su_mtx;
194eebcd280Spooka static bool rebuild;
195eebcd280Spooka static int nsock;
196eebcd280Spooka 
1973694a148Spooka /* XXX: for the bpf hack */
1983694a148Spooka static struct ifnet sockin_if;
ifpromisc(struct ifnet * ifp,int pswitch)1993694a148Spooka int ifpromisc(struct ifnet *ifp, int pswitch) { return 0; }
2003694a148Spooka 
201eebcd280Spooka static int
registersock(struct socket * so,int news)202eebcd280Spooka registersock(struct socket *so, int news)
203eebcd280Spooka {
204eebcd280Spooka 	struct sockin_unit *su;
205eebcd280Spooka 
206eebcd280Spooka 	su = kmem_alloc(sizeof(*su), KM_NOSLEEP);
207eebcd280Spooka 	if (!su)
208eebcd280Spooka 		return ENOMEM;
209eebcd280Spooka 
210eebcd280Spooka 	so->so_internal = (void *)(intptr_t)news;
211eebcd280Spooka 	su->su_so = so;
212eebcd280Spooka 
213eebcd280Spooka 	mutex_enter(&su_mtx);
214eebcd280Spooka 	LIST_INSERT_HEAD(&su_ent, su, su_entries);
215eebcd280Spooka 	nsock++;
216eebcd280Spooka 	rebuild = true;
217eebcd280Spooka 	mutex_exit(&su_mtx);
218eebcd280Spooka 
219eebcd280Spooka 	return 0;
220eebcd280Spooka }
221eebcd280Spooka 
222ad9bbd7bSpooka static void
removesock(struct socket * so)223d1543896Spooka removesock(struct socket *so)
224d1543896Spooka {
225d1543896Spooka 	struct sockin_unit *su_iter;
226d1543896Spooka 
227d1543896Spooka 	mutex_enter(&su_mtx);
228d1543896Spooka 	LIST_FOREACH(su_iter, &su_ent, su_entries) {
229d1543896Spooka 		if (su_iter->su_so == so)
230d1543896Spooka 			break;
231d1543896Spooka 	}
232d1543896Spooka 	if (!su_iter)
233d1543896Spooka 		panic("no such socket");
234d1543896Spooka 
235d1543896Spooka 	LIST_REMOVE(su_iter, su_entries);
236d1543896Spooka 	nsock--;
237d1543896Spooka 	rebuild = true;
238d1543896Spooka 	mutex_exit(&su_mtx);
239d1543896Spooka 
24032a34307Spooka 	rumpuser_close(SO2S(su_iter->su_so));
241d1543896Spooka 	kmem_free(su_iter, sizeof(*su_iter));
242d1543896Spooka }
243d1543896Spooka 
244d1543896Spooka static void
sockin_process(struct socket * so)245ad9bbd7bSpooka sockin_process(struct socket *so)
246ad9bbd7bSpooka {
2473df1f0e3Sstacktic 	struct sockaddr_in6 from;
248ad9bbd7bSpooka 	struct iovec io;
249ad9bbd7bSpooka 	struct msghdr rmsg;
250ad9bbd7bSpooka 	struct mbuf *m;
251b062b6a6Spooka 	size_t n, plen;
252ad9bbd7bSpooka 	int error;
253ad9bbd7bSpooka 
254ad9bbd7bSpooka 	m = m_gethdr(M_WAIT, MT_DATA);
2558b70996eSpooka 	if (so->so_proto->pr_type == SOCK_DGRAM) {
2568b70996eSpooka 		plen = IP_MAXPACKET;
2578b70996eSpooka 		MEXTMALLOC(m, plen, M_DONTWAIT);
2588b70996eSpooka 	} else {
2598b70996eSpooka 		plen = MCLBYTES;
2608b70996eSpooka 		MCLGET(m, M_DONTWAIT);
2618b70996eSpooka 	}
2628b70996eSpooka 	if ((m->m_flags & M_EXT) == 0) {
2638b70996eSpooka 		m_freem(m);
2648b70996eSpooka 		return;
2658b70996eSpooka 	}
266ad9bbd7bSpooka 
267ad9bbd7bSpooka 	memset(&rmsg, 0, sizeof(rmsg));
268ad9bbd7bSpooka 	io.iov_base = mtod(m, void *);
269ad9bbd7bSpooka 	io.iov_len = plen;
270ad9bbd7bSpooka 	rmsg.msg_iov = &io;
271ad9bbd7bSpooka 	rmsg.msg_iovlen = 1;
272ad9bbd7bSpooka 	rmsg.msg_name = (struct sockaddr *)&from;
273ad9bbd7bSpooka 	rmsg.msg_namelen = sizeof(from);
274ad9bbd7bSpooka 
275b062b6a6Spooka 	error = rumpcomp_sockin_recvmsg(SO2S(so), &rmsg, 0, &n);
276b043cb36Spooka 	if (error || n == 0) {
277ad9bbd7bSpooka 		m_freem(m);
278d1543896Spooka 
279d1543896Spooka 		/* Treat a TCP socket a goner */
2804581312dSpooka 		if (error != EAGAIN && so->so_proto->pr_type == SOCK_STREAM) {
281afe25e20Spooka 			mutex_enter(softnet_lock);
282d1543896Spooka 			soisdisconnected(so);
283afe25e20Spooka 			mutex_exit(softnet_lock);
284d1543896Spooka 			removesock(so);
285d1543896Spooka 		}
286ad9bbd7bSpooka 		return;
287ad9bbd7bSpooka 	}
288ad9bbd7bSpooka 	m->m_len = m->m_pkthdr.len = n;
289ad9bbd7bSpooka 
2903cd62456Smsaitoh 	bpf_mtap_af(&sockin_if, AF_UNSPEC, m, BPF_D_IN);
2913694a148Spooka 
292afe25e20Spooka 	mutex_enter(softnet_lock);
2937dd6651aSpooka 	if (so->so_proto->pr_type == SOCK_DGRAM) {
294ad9bbd7bSpooka 		if (!sbappendaddr(&so->so_rcv, rmsg.msg_name, m, NULL)) {
295ad9bbd7bSpooka 			m_freem(m);
296ad9bbd7bSpooka 		}
2977dd6651aSpooka 	} else {
2987dd6651aSpooka 		sbappendstream(&so->so_rcv, m);
2997dd6651aSpooka 	}
3007dd6651aSpooka 
301ad9bbd7bSpooka 	sorwakeup(so);
302afe25e20Spooka 	mutex_exit(softnet_lock);
303ad9bbd7bSpooka }
304ad9bbd7bSpooka 
305eebcd280Spooka static void
sockin_waccept(struct socket * so)3064a86612dSrtr sockin_waccept(struct socket *so)
307eebcd280Spooka {
308eebcd280Spooka 	struct socket *nso;
3093df1f0e3Sstacktic 	struct sockaddr_in6 sin;
310eebcd280Spooka 	int news, error, slen;
311eebcd280Spooka 
312eebcd280Spooka 	slen = sizeof(sin);
31332a34307Spooka 	error = rumpcomp_sockin_accept(SO2S(so), (struct sockaddr *)&sin,
31432a34307Spooka 	    &slen, &news);
31532a34307Spooka 	if (error)
316eebcd280Spooka 		return;
317eebcd280Spooka 
318afe25e20Spooka 	mutex_enter(softnet_lock);
3198088e729Srmind 	nso = sonewconn(so, true);
320afe25e20Spooka 	if (nso == NULL)
321eebcd280Spooka 		goto errout;
322eebcd280Spooka 	if (registersock(nso, news) != 0)
323eebcd280Spooka 		goto errout;
324afe25e20Spooka 	mutex_exit(softnet_lock);
325eebcd280Spooka 	return;
326eebcd280Spooka 
327eebcd280Spooka  errout:
32832a34307Spooka 	rumpuser_close(news);
329eebcd280Spooka 	if (nso)
330eebcd280Spooka 		soclose(nso);
331afe25e20Spooka 	mutex_exit(softnet_lock);
332eebcd280Spooka }
333eebcd280Spooka 
334ad9bbd7bSpooka #define POLLTIMEOUT 100	/* check for new entries every 100ms */
335ad9bbd7bSpooka 
336ad9bbd7bSpooka /* XXX: doesn't handle socket (kernel) locking properly? */
337ad9bbd7bSpooka static void
sockinworker(void * arg)338ad9bbd7bSpooka sockinworker(void *arg)
339ad9bbd7bSpooka {
340ad9bbd7bSpooka 	struct pollfd *pfds = NULL, *npfds;
341ad9bbd7bSpooka 	struct sockin_unit *su_iter;
342eebcd280Spooka 	struct socket *so;
343ad9bbd7bSpooka 	int cursock = 0, i, rv, error;
344ad9bbd7bSpooka 
345ad9bbd7bSpooka 	/*
346ad9bbd7bSpooka 	 * Loop reading requests.  Check for new sockets periodically
347ad9bbd7bSpooka 	 * (could be smarter, but I'm lazy).
348ad9bbd7bSpooka 	 */
349ad9bbd7bSpooka 	for (;;) {
350ad9bbd7bSpooka 		if (rebuild) {
351ad9bbd7bSpooka 			npfds = NULL;
352ad9bbd7bSpooka 			mutex_enter(&su_mtx);
353ad9bbd7bSpooka 			if (nsock)
354ad9bbd7bSpooka 				npfds = kmem_alloc(nsock * sizeof(*npfds),
355ad9bbd7bSpooka 				    KM_NOSLEEP);
356ad9bbd7bSpooka 			if (npfds || nsock == 0) {
357ad9bbd7bSpooka 				if (pfds)
358ad9bbd7bSpooka 					kmem_free(pfds, cursock*sizeof(*pfds));
359ad9bbd7bSpooka 				pfds = npfds;
360ad9bbd7bSpooka 				cursock = nsock;
361ad9bbd7bSpooka 				rebuild = false;
362ad9bbd7bSpooka 
363ad9bbd7bSpooka 				i = 0;
364ad9bbd7bSpooka 				LIST_FOREACH(su_iter, &su_ent, su_entries) {
365ad9bbd7bSpooka 					pfds[i].fd = SO2S(su_iter->su_so);
366ad9bbd7bSpooka 					pfds[i].events = POLLIN;
367ad9bbd7bSpooka 					pfds[i].revents = 0;
368ad9bbd7bSpooka 					i++;
369ad9bbd7bSpooka 				}
370ad9bbd7bSpooka 				KASSERT(i == nsock);
371ad9bbd7bSpooka 			}
372ad9bbd7bSpooka 			mutex_exit(&su_mtx);
373ad9bbd7bSpooka 		}
374ad9bbd7bSpooka 
375ad9bbd7bSpooka 		/* find affected sockets & process */
37632a34307Spooka 		error = rumpcomp_sockin_poll(pfds, cursock, POLLTIMEOUT, &rv);
37732a34307Spooka 		for (i = 0; i < cursock && rv > 0 && error == 0; i++) {
378ad9bbd7bSpooka 			if (pfds[i].revents & POLLIN) {
379ad9bbd7bSpooka 				mutex_enter(&su_mtx);
380ad9bbd7bSpooka 				LIST_FOREACH(su_iter, &su_ent, su_entries) {
381ad9bbd7bSpooka 					if (SO2S(su_iter->su_so)==pfds[i].fd) {
382eebcd280Spooka 						so = su_iter->su_so;
383eebcd280Spooka 						mutex_exit(&su_mtx);
384eebcd280Spooka 						if(so->so_options&SO_ACCEPTCONN)
3854a86612dSrtr 							sockin_waccept(so);
386eebcd280Spooka 						else
387eebcd280Spooka 							sockin_process(so);
388eebcd280Spooka 						mutex_enter(&su_mtx);
389ad9bbd7bSpooka 						break;
390ad9bbd7bSpooka 					}
391ad9bbd7bSpooka 				}
392ad9bbd7bSpooka 				/* if we can't find it, just wing it */
393ad9bbd7bSpooka 				KASSERT(rebuild || su_iter);
394ad9bbd7bSpooka 				mutex_exit(&su_mtx);
395ad9bbd7bSpooka 				pfds[i].revents = 0;
396ad9bbd7bSpooka 				rv--;
397ad9bbd7bSpooka 				i = -1;
398ad9bbd7bSpooka 				continue;
399ad9bbd7bSpooka 			}
400ad9bbd7bSpooka 
401ad9bbd7bSpooka 			/* something else?  ignore */
402ad9bbd7bSpooka 			if (pfds[i].revents) {
403ad9bbd7bSpooka 				pfds[i].revents = 0;
404ad9bbd7bSpooka 				rv--;
405ad9bbd7bSpooka 			}
406ad9bbd7bSpooka 		}
407ad9bbd7bSpooka 		KASSERT(rv <= 0);
408ad9bbd7bSpooka 	}
409ad9bbd7bSpooka 
410ad9bbd7bSpooka }
411ad9bbd7bSpooka 
41253da9055Sstacktic static int
sockin_do_init(void)41353da9055Sstacktic sockin_do_init(void)
414ad9bbd7bSpooka {
415ad9bbd7bSpooka 	int rv;
416ad9bbd7bSpooka 
41739cb5b51Spooka 	if (rump_threads) {
418ad9bbd7bSpooka 		if ((rv = kthread_create(PRI_NONE, 0, NULL, sockinworker,
419ad9bbd7bSpooka 		    NULL, NULL, "sockwork")) != 0)
420ad9bbd7bSpooka 			panic("sockin_init: could not create worker thread\n");
42139cb5b51Spooka 	} else {
42239cb5b51Spooka 		printf("sockin_init: no threads => no worker thread\n");
42339cb5b51Spooka 	}
424ad9bbd7bSpooka 	mutex_init(&su_mtx, MUTEX_DEFAULT, IPL_NONE);
4253694a148Spooka 	strlcpy(sockin_if.if_xname, "sockin0", sizeof(sockin_if.if_xname));
42658e86755Sjoerg 	bpf_attach(&sockin_if, DLT_NULL, 0);
42753da9055Sstacktic 	return 0;
42853da9055Sstacktic }
42953da9055Sstacktic 
43053da9055Sstacktic static void
sockin_init(void)43153da9055Sstacktic sockin_init(void)
43253da9055Sstacktic {
43353da9055Sstacktic 	static ONCE_DECL(init);
43453da9055Sstacktic 
43553da9055Sstacktic 	RUN_ONCE(&init, sockin_do_init);
436ad9bbd7bSpooka }
437ad9bbd7bSpooka 
438ad9bbd7bSpooka static int
sockin_attach(struct socket * so,int proto)4394ae03c18Srmind sockin_attach(struct socket *so, int proto)
440ad9bbd7bSpooka {
4414ae03c18Srmind 	const int type = so->so_proto->pr_type;
4424ae03c18Srmind 	int error, news, family;
443ad9bbd7bSpooka 
444ad9bbd7bSpooka 	sosetlock(so);
4457dd6651aSpooka 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
4467dd6651aSpooka 		error = soreserve(so, SOCKIN_SBSIZE, SOCKIN_SBSIZE);
4477dd6651aSpooka 		if (error)
4484ae03c18Srmind 			return error;
4497dd6651aSpooka 	}
450ad9bbd7bSpooka 
4513731822aSpooka 	family = so->so_proto->pr_domain->dom_family;
4523731822aSpooka 	KASSERT(family == PF_INET || family == PF_INET6);
4534ae03c18Srmind 	error = rumpcomp_sockin_socket(family, type, 0, &news);
454b062b6a6Spooka 	if (error)
4554ae03c18Srmind 		return error;
456ad9bbd7bSpooka 
4574ae03c18Srmind 	/* For UDP sockets, make sure we can send/recv maximum. */
4584ae03c18Srmind 	if (type == SOCK_DGRAM) {
4594ae03c18Srmind 		int sbsize = SOCKIN_SBSIZE;
46032a34307Spooka 		error = rumpcomp_sockin_setsockopt(news,
461e3425032Spooka 		    SOL_SOCKET, SO_SNDBUF,
46232a34307Spooka 		    &sbsize, sizeof(sbsize));
463291f141cSpooka 		sbsize = SOCKIN_SBSIZE;
46432a34307Spooka 		error = rumpcomp_sockin_setsockopt(news,
465e3425032Spooka 		    SOL_SOCKET, SO_RCVBUF,
46632a34307Spooka 		    &sbsize, sizeof(sbsize));
467291f141cSpooka 	}
468291f141cSpooka 
469eebcd280Spooka 	if ((error = registersock(so, news)) != 0)
47032a34307Spooka 		rumpuser_close(news);
471eebcd280Spooka 
4724ae03c18Srmind 	return error;
473ad9bbd7bSpooka }
474ad9bbd7bSpooka 
4754ae03c18Srmind static void
sockin_detach(struct socket * so)4764ae03c18Srmind sockin_detach(struct socket *so)
4774ae03c18Srmind {
4784ae03c18Srmind 	panic("sockin_detach: IMPLEMENT ME\n");
4794ae03c18Srmind }
4804ae03c18Srmind 
4814ae03c18Srmind static int
sockin_accept(struct socket * so,struct sockaddr * nam)482eddf3af3Srtr sockin_accept(struct socket *so, struct sockaddr *nam)
483d27b133dSrtr {
484d27b133dSrtr 	KASSERT(solocked(so));
485d27b133dSrtr 
486d27b133dSrtr 	/* we do all the work in the worker thread */
487d27b133dSrtr 	return 0;
488d27b133dSrtr }
489d27b133dSrtr 
490d27b133dSrtr static int
sockin_bind(struct socket * so,struct sockaddr * nam,struct lwp * l)491a2ba5e69Srtr sockin_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
4926dd8eef0Srtr {
4936dd8eef0Srtr 	KASSERT(solocked(so));
4946dd8eef0Srtr 	KASSERT(nam != NULL);
4956dd8eef0Srtr 
496a2ba5e69Srtr 	return rumpcomp_sockin_bind(SO2S(so), nam, nam->sa_len);
4976dd8eef0Srtr }
4986dd8eef0Srtr 
4996dd8eef0Srtr static int
sockin_listen(struct socket * so,struct lwp * l)500ce6a5ff6Srtr sockin_listen(struct socket *so, struct lwp *l)
5016dd8eef0Srtr {
5026dd8eef0Srtr 	KASSERT(solocked(so));
5036dd8eef0Srtr 
5046dd8eef0Srtr 	return rumpcomp_sockin_listen(SO2S(so), so->so_qlimit);
5056dd8eef0Srtr }
5066dd8eef0Srtr 
5076dd8eef0Srtr static int
sockin_connect(struct socket * so,struct sockaddr * nam,struct lwp * l)508fd12cf39Srtr sockin_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
509ad6ae402Srtr {
510ad6ae402Srtr 	int error = 0;
511ad6ae402Srtr 
512ad6ae402Srtr 	KASSERT(solocked(so));
513ad6ae402Srtr 	KASSERT(nam != NULL);
514ad6ae402Srtr 
515fd12cf39Srtr 	error = rumpcomp_sockin_connect(SO2S(so), nam, nam->sa_len);
516ad6ae402Srtr 	if (error == 0)
517ad6ae402Srtr 		soisconnected(so);
518ad6ae402Srtr 
519ad6ae402Srtr 	return error;
520ad6ae402Srtr }
521ad6ae402Srtr 
522892163b8Srtr static int
sockin_connect2(struct socket * so,struct socket * so2)5238cf67cc6Srtr sockin_connect2(struct socket *so, struct socket *so2)
5248cf67cc6Srtr {
5258cf67cc6Srtr 	KASSERT(solocked(so));
5268cf67cc6Srtr 
5278cf67cc6Srtr 	panic("sockin_connect2: IMPLEMENT ME, connect2 not supported");
5288cf67cc6Srtr }
5298cf67cc6Srtr 
5308cf67cc6Srtr static int
sockin_disconnect(struct socket * so)531892163b8Srtr sockin_disconnect(struct socket *so)
532892163b8Srtr {
533892163b8Srtr 	KASSERT(solocked(so));
534892163b8Srtr 
535892163b8Srtr 	panic("sockin_disconnect: IMPLEMENT ME, disconnect not supported");
536892163b8Srtr }
537892163b8Srtr 
538892163b8Srtr static int
sockin_shutdown(struct socket * so)539892163b8Srtr sockin_shutdown(struct socket *so)
540892163b8Srtr {
541892163b8Srtr 	KASSERT(solocked(so));
542892163b8Srtr 
543892163b8Srtr 	removesock(so);
544892163b8Srtr 	return 0;
545892163b8Srtr }
546892163b8Srtr 
547892163b8Srtr static int
sockin_abort(struct socket * so)548892163b8Srtr sockin_abort(struct socket *so)
549892163b8Srtr {
550892163b8Srtr 	KASSERT(solocked(so));
551892163b8Srtr 
552892163b8Srtr 	panic("sockin_abort: IMPLEMENT ME, abort not supported");
553892163b8Srtr }
554ad6ae402Srtr 
555ad6ae402Srtr static int
sockin_ioctl(struct socket * so,u_long cmd,void * nam,struct ifnet * ifp)5560dedd977Srtr sockin_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
557d54d7ab2Srtr {
558d54d7ab2Srtr 	return ENOTTY;
559d54d7ab2Srtr }
560d54d7ab2Srtr 
561d54d7ab2Srtr static int
sockin_stat(struct socket * so,struct stat * ub)5620f199192Srtr sockin_stat(struct socket *so, struct stat *ub)
5630f199192Srtr {
564ff90c29dSrtr 	KASSERT(solocked(so));
565ff90c29dSrtr 
566909a1fc6Srtr 	return 0;
5670f199192Srtr }
5680f199192Srtr 
5690f199192Srtr static int
sockin_peeraddr(struct socket * so,struct sockaddr * nam)570eddf3af3Srtr sockin_peeraddr(struct socket *so, struct sockaddr *nam)
571d575eb54Srtr {
572d575eb54Srtr 	KASSERT(solocked(so));
573d575eb54Srtr 
574d575eb54Srtr 	int error = 0;
575eddf3af3Srtr 	int slen = nam->sa_len;
576d575eb54Srtr 
577d575eb54Srtr 	error = rumpcomp_sockin_getname(SO2S(so),
578eddf3af3Srtr 	    nam, &slen, RUMPCOMP_SOCKIN_PEERNAME);
579d575eb54Srtr 	if (error == 0)
580eddf3af3Srtr 		nam->sa_len = slen;
581d575eb54Srtr 	return error;
582d575eb54Srtr }
583d575eb54Srtr 
584d575eb54Srtr static int
sockin_sockaddr(struct socket * so,struct sockaddr * nam)585eddf3af3Srtr sockin_sockaddr(struct socket *so, struct sockaddr *nam)
586d575eb54Srtr {
587d575eb54Srtr 	KASSERT(solocked(so));
588d575eb54Srtr 
589d575eb54Srtr 	int error = 0;
590eddf3af3Srtr 	int slen = nam->sa_len;
591d575eb54Srtr 
592d575eb54Srtr 	error = rumpcomp_sockin_getname(SO2S(so),
593eddf3af3Srtr 	    nam, &slen, RUMPCOMP_SOCKIN_SOCKNAME);
594d575eb54Srtr 	if (error == 0)
595eddf3af3Srtr 		nam->sa_len = slen;
596d575eb54Srtr 	return error;
597d575eb54Srtr }
598d575eb54Srtr 
599d575eb54Srtr static int
sockin_rcvd(struct socket * so,int flags,struct lwp * l)600822872eaSrtr sockin_rcvd(struct socket *so, int flags, struct lwp *l)
601822872eaSrtr {
602822872eaSrtr 	KASSERT(solocked(so));
603822872eaSrtr 
604822872eaSrtr 	panic("sockin_rcvd: IMPLEMENT ME, rcvd not supported");
605822872eaSrtr }
606822872eaSrtr 
607822872eaSrtr static int
sockin_recvoob(struct socket * so,struct mbuf * m,int flags)60835b22fa9Srtr sockin_recvoob(struct socket *so, struct mbuf *m, int flags)
60935b22fa9Srtr {
610892163b8Srtr 	KASSERT(solocked(so));
611892163b8Srtr 
61235b22fa9Srtr 	panic("sockin_recvoob: IMPLEMENT ME, recvoob not supported");
61335b22fa9Srtr }
61435b22fa9Srtr 
61535b22fa9Srtr static int
sockin_send(struct socket * so,struct mbuf * m,struct sockaddr * saddr,struct mbuf * control,struct lwp * l)616fd12cf39Srtr sockin_send(struct socket *so, struct mbuf *m, struct sockaddr *saddr,
6174ae03c18Srmind     struct mbuf *control, struct lwp *l)
6184ae03c18Srmind {
619ad9bbd7bSpooka 	struct msghdr mhdr;
6208cd44ca8Stron 	size_t iov_max, i;
6213ad0ebd5Stron 	struct iovec iov_buf[32], *iov;
622ad9bbd7bSpooka 	struct mbuf *m2;
623b062b6a6Spooka 	size_t tot, n;
624651e5bd3Srtr 	int error = 0;
6258cd44ca8Stron 	int s;
626ad9bbd7bSpooka 
6273cd62456Smsaitoh 	bpf_mtap_af(&sockin_if, AF_UNSPEC, m, BPF_D_OUT);
6283694a148Spooka 
629ad9bbd7bSpooka 	memset(&mhdr, 0, sizeof(mhdr));
630ad9bbd7bSpooka 
6318cd44ca8Stron 	iov_max = 0;
6328cd44ca8Stron 	for (m2 = m; m2 != NULL; m2 = m2->m_next) {
6338cd44ca8Stron 		iov_max++;
6348cd44ca8Stron 	}
6358cd44ca8Stron 
6363ad0ebd5Stron 	if (iov_max <= __arraycount(iov_buf)) {
6373ad0ebd5Stron 		iov = iov_buf;
6383ad0ebd5Stron 	} else {
6393ad0ebd5Stron 		iov = kmem_alloc(sizeof(struct iovec) * iov_max,
6403ad0ebd5Stron 		    KM_SLEEP);
6413ad0ebd5Stron 	}
6428cd44ca8Stron 
643ad9bbd7bSpooka 	tot = 0;
6448cd44ca8Stron 	for (i = 0, m2 = m; m2 != NULL; m2 = m2->m_next, i++) {
645ad9bbd7bSpooka 		iov[i].iov_base = m2->m_data;
646ad9bbd7bSpooka 		iov[i].iov_len = m2->m_len;
647ad9bbd7bSpooka 		tot += m2->m_len;
648ad9bbd7bSpooka 	}
6497dd6651aSpooka 	mhdr.msg_iov = iov;
6507dd6651aSpooka 	mhdr.msg_iovlen = i;
6518447026cSpooka 	s = SO2S(so);
6527dd6651aSpooka 
653fd12cf39Srtr 	if (saddr != NULL) {
654bcf80a6fSpooka 		mhdr.msg_name = saddr;
655bcf80a6fSpooka 		mhdr.msg_namelen = saddr->sa_len;
656bcf80a6fSpooka 	}
657bcf80a6fSpooka 
658b062b6a6Spooka 	rumpcomp_sockin_sendmsg(s, &mhdr, 0, &n);
6597dd6651aSpooka 
6603ad0ebd5Stron 	if (iov != iov_buf)
6618cd44ca8Stron 		kmem_free(iov, sizeof(struct iovec) * iov_max);
6628cd44ca8Stron 
663ad9bbd7bSpooka 	m_freem(m);
664ad9bbd7bSpooka 	m_freem(control);
66539cb5b51Spooka 
666ad9bbd7bSpooka 	/* this assumes too many things to list.. buthey, testing */
66739cb5b51Spooka 	if (!rump_threads)
668ad9bbd7bSpooka 		sockin_process(so);
669ad9bbd7bSpooka 
670651e5bd3Srtr 	return error;
671651e5bd3Srtr }
672651e5bd3Srtr 
673651e5bd3Srtr static int
sockin_sendoob(struct socket * so,struct mbuf * m,struct mbuf * control)674651e5bd3Srtr sockin_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
675651e5bd3Srtr {
676651e5bd3Srtr 	KASSERT(solocked(so));
677651e5bd3Srtr 
678651e5bd3Srtr 	panic("sockin_sendoob: IMPLEMENT ME, sendoob not supported");
679651e5bd3Srtr }
680651e5bd3Srtr 
681651e5bd3Srtr static int
sockin_purgeif(struct socket * so,struct ifnet * ifp)6828cf67cc6Srtr sockin_purgeif(struct socket *so, struct ifnet *ifp)
6838cf67cc6Srtr {
6848cf67cc6Srtr 
6858cf67cc6Srtr 	panic("sockin_purgeif: IMPLEMENT ME, purgeif not supported");
6868cf67cc6Srtr }
6878cf67cc6Srtr 
6888cf67cc6Srtr static int
sockin_ctloutput(int op,struct socket * so,struct sockopt * sopt)689eaff187cSpooka sockin_ctloutput(int op, struct socket *so, struct sockopt *sopt)
690eaff187cSpooka {
691eaff187cSpooka 
69232a34307Spooka 	return rumpcomp_sockin_setsockopt(SO2S(so), sopt->sopt_level,
69332a34307Spooka 	    sopt->sopt_name, sopt->sopt_data, sopt->sopt_size);
694eaff187cSpooka }
695cd5f3c7dSpooka 
696cd5f3c7dSpooka int sockin_unavailable(void);
697cd5f3c7dSpooka int
sockin_unavailable(void)698cd5f3c7dSpooka sockin_unavailable(void)
699cd5f3c7dSpooka {
700cd5f3c7dSpooka 
701cd5f3c7dSpooka         panic("interface not available in with sockin");
702cd5f3c7dSpooka }
703cd5f3c7dSpooka __strong_alias(rtrequest,sockin_unavailable);
704cd5f3c7dSpooka __strong_alias(ifunit,sockin_unavailable);
705cd5f3c7dSpooka __strong_alias(ifreq_setaddr,sockin_unavailable);
706aeb231ccSozaki-r __strong_alias(rt_delete_matched_entries,sockin_unavailable);
707