xref: /minix3/minix/servers/vfs/sdev.c (revision 491d647a3b6c5e781017a8842cade543fc0b74a3)
1e3b8d4bbSDavid van Moolenbroek /*
2e3b8d4bbSDavid van Moolenbroek  * This file implements the lower socket layer of VFS: communication with
3e3b8d4bbSDavid van Moolenbroek  * socket drivers.  Socket driver communication evolved out of character driver
4e3b8d4bbSDavid van Moolenbroek  * communication, and the two have many similarities between them.  Most
5e3b8d4bbSDavid van Moolenbroek  * importantly, socket driver communication also has the distinction between
6e3b8d4bbSDavid van Moolenbroek  * short-lived and long-lived requests.
7e3b8d4bbSDavid van Moolenbroek  *
8e3b8d4bbSDavid van Moolenbroek  * Short-lived requests are expected to be replied to by the socket driver
9e3b8d4bbSDavid van Moolenbroek  * immediately in all cases.  For such requests, VFS keeps the worker thread
10e3b8d4bbSDavid van Moolenbroek  * for the calling process alive until the reply arrives.  In contrast,
11e3b8d4bbSDavid van Moolenbroek  * long-lived requests may block.  For such requests, VFS suspends the calling
12e3b8d4bbSDavid van Moolenbroek  * process until a reply comes in, or until a signal interrupts the request.
13e3b8d4bbSDavid van Moolenbroek  * Both short-lived and long-lived requests may be aborted if VFS finds that
14e3b8d4bbSDavid van Moolenbroek  * the corresponding socket driver has died.  Even though long-lived requests
15e3b8d4bbSDavid van Moolenbroek  * may be marked as nonblocking, nonblocking calls are still handled as
16e3b8d4bbSDavid van Moolenbroek  * long-lived in terms of VFS processing.
17e3b8d4bbSDavid van Moolenbroek  *
18e3b8d4bbSDavid van Moolenbroek  * For an overview of the socket driver requests and replies, message layouts,
19e3b8d4bbSDavid van Moolenbroek  * and which requests are long-lived or short-lived (i.e. may suspend or not),
20e3b8d4bbSDavid van Moolenbroek  * please refer to the corresponding table in the libsockdriver source code.
21e3b8d4bbSDavid van Moolenbroek  *
22e3b8d4bbSDavid van Moolenbroek  * For most long-lived socket requests, the main VFS thread processes the reply
23e3b8d4bbSDavid van Moolenbroek  * from the socket driver.  This typically consists of waking up the user
24e3b8d4bbSDavid van Moolenbroek  * process that originally issued the system call on the socket by simply
25e3b8d4bbSDavid van Moolenbroek  * relaying the call's result code.  Some socket calls require a specific reply
26e3b8d4bbSDavid van Moolenbroek  * message and/or additional post-call actions; for those, resume_*() calls are
27e3b8d4bbSDavid van Moolenbroek  * made back into the upper socket layer.
28e3b8d4bbSDavid van Moolenbroek  *
29e3b8d4bbSDavid van Moolenbroek  * If a process is interrupted by a signal, any ongoing long-lived socket
30e3b8d4bbSDavid van Moolenbroek  * request must be canceled.  This is done by sending a one-way cancel request
31e3b8d4bbSDavid van Moolenbroek  * to the socket driver, and waiting for it to reply to the original request.
32e3b8d4bbSDavid van Moolenbroek  * In this case, the reply will be processed from the worker thread that is
33e3b8d4bbSDavid van Moolenbroek  * handling the cancel operation.  Canceling does not imply call failure: the
34e3b8d4bbSDavid van Moolenbroek  * cancellation may result in a partial I/O reply, and a successful reply may
35e3b8d4bbSDavid van Moolenbroek  * cross the cancel request.
36e3b8d4bbSDavid van Moolenbroek  *
37e3b8d4bbSDavid van Moolenbroek  * One main exception is the reply to an accept request.  Once a connection has
38e3b8d4bbSDavid van Moolenbroek  * been accepted, a new socket has to be created for it.  This requires actions
39e3b8d4bbSDavid van Moolenbroek  * that require the ability to block the current thread, and so, a worker
40e3b8d4bbSDavid van Moolenbroek  * thread is spawned for processing successful accept replies, unless the reply
41e3b8d4bbSDavid van Moolenbroek  * was received from a worker thread already (as may be the case if the accept
42e3b8d4bbSDavid van Moolenbroek  * request was being canceled).
43e3b8d4bbSDavid van Moolenbroek  */
44e3b8d4bbSDavid van Moolenbroek 
45e3b8d4bbSDavid van Moolenbroek #include "fs.h"
46e3b8d4bbSDavid van Moolenbroek #include <sys/socket.h>
47e3b8d4bbSDavid van Moolenbroek #include <minix/callnr.h>
48e3b8d4bbSDavid van Moolenbroek 
49e3b8d4bbSDavid van Moolenbroek /*
50e3b8d4bbSDavid van Moolenbroek  * Send a short-lived request message to the given socket driver, and suspend
51e3b8d4bbSDavid van Moolenbroek  * the current worker thread until a reply message has been received.  On
52e3b8d4bbSDavid van Moolenbroek  * success, the function will return OK, and the reply message will be stored
53e3b8d4bbSDavid van Moolenbroek  * in the message structure pointed to by 'm_ptr'.  The function may fail if
54e3b8d4bbSDavid van Moolenbroek  * the socket driver dies before sending a reply.  In that case, the function
55e3b8d4bbSDavid van Moolenbroek  * will return a negative error code, and also store the same negative error
56e3b8d4bbSDavid van Moolenbroek  * code in the m_type field of the 'm_ptr' message structure.
57e3b8d4bbSDavid van Moolenbroek  */
58e3b8d4bbSDavid van Moolenbroek static int
sdev_sendrec(struct smap * sp,message * m_ptr)59e3b8d4bbSDavid van Moolenbroek sdev_sendrec(struct smap * sp, message * m_ptr)
60e3b8d4bbSDavid van Moolenbroek {
61e3b8d4bbSDavid van Moolenbroek 	int r;
62e3b8d4bbSDavid van Moolenbroek 
63e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
64e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, m_ptr, AMF_NOREPLY)) != OK)
65e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_sendrec failed: %d", r);
66e3b8d4bbSDavid van Moolenbroek 
67e3b8d4bbSDavid van Moolenbroek 	/* Suspend this thread until we have received the response. */
68e3b8d4bbSDavid van Moolenbroek 	self->w_task = sp->smap_endpt;
69e3b8d4bbSDavid van Moolenbroek 	self->w_drv_sendrec = m_ptr;
70e3b8d4bbSDavid van Moolenbroek 
71e3b8d4bbSDavid van Moolenbroek 	worker_wait();
72e3b8d4bbSDavid van Moolenbroek 
73e3b8d4bbSDavid van Moolenbroek 	self->w_task = NONE;
74e3b8d4bbSDavid van Moolenbroek 	assert(self->w_drv_sendrec == NULL);
75e3b8d4bbSDavid van Moolenbroek 
76e3b8d4bbSDavid van Moolenbroek 	return (!IS_SDEV_RS(m_ptr->m_type)) ? m_ptr->m_type : OK;
77e3b8d4bbSDavid van Moolenbroek }
78e3b8d4bbSDavid van Moolenbroek 
79e3b8d4bbSDavid van Moolenbroek /*
80e3b8d4bbSDavid van Moolenbroek  * Suspend the current process for later completion of its system call.
81e3b8d4bbSDavid van Moolenbroek  */
82e3b8d4bbSDavid van Moolenbroek int
sdev_suspend(dev_t dev,cp_grant_id_t grant0,cp_grant_id_t grant1,cp_grant_id_t grant2,int fd,vir_bytes buf)83e3b8d4bbSDavid van Moolenbroek sdev_suspend(dev_t dev, cp_grant_id_t grant0, cp_grant_id_t grant1,
84e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant2, int fd, vir_bytes buf)
85e3b8d4bbSDavid van Moolenbroek {
86e3b8d4bbSDavid van Moolenbroek 
87e3b8d4bbSDavid van Moolenbroek 	fp->fp_sdev.dev = dev;
88e3b8d4bbSDavid van Moolenbroek 	fp->fp_sdev.callnr = job_call_nr;
89e3b8d4bbSDavid van Moolenbroek 	fp->fp_sdev.grant[0] = grant0;
90e3b8d4bbSDavid van Moolenbroek 	fp->fp_sdev.grant[1] = grant1;
91e3b8d4bbSDavid van Moolenbroek 	fp->fp_sdev.grant[2] = grant2;
92e3b8d4bbSDavid van Moolenbroek 
93e3b8d4bbSDavid van Moolenbroek 	if (job_call_nr == VFS_ACCEPT) {
94e3b8d4bbSDavid van Moolenbroek 		assert(fd != -1);
95e3b8d4bbSDavid van Moolenbroek 		assert(buf == 0);
96e3b8d4bbSDavid van Moolenbroek 		fp->fp_sdev.aux.fd = fd;
97e3b8d4bbSDavid van Moolenbroek 	} else if (job_call_nr == VFS_RECVMSG) {
98e3b8d4bbSDavid van Moolenbroek 		assert(fd == -1);
99e3b8d4bbSDavid van Moolenbroek 		/*
100e3b8d4bbSDavid van Moolenbroek 		 * TODO: we are not yet consistent enough in dealing with
101e3b8d4bbSDavid van Moolenbroek 		 * mapped NULL pages to have an assert(buf != 0) here..
102e3b8d4bbSDavid van Moolenbroek 		 */
103e3b8d4bbSDavid van Moolenbroek 		fp->fp_sdev.aux.buf = buf;
104e3b8d4bbSDavid van Moolenbroek 	} else {
105e3b8d4bbSDavid van Moolenbroek 		assert(fd == -1);
106e3b8d4bbSDavid van Moolenbroek 		assert(buf == 0);
107e3b8d4bbSDavid van Moolenbroek 	}
108e3b8d4bbSDavid van Moolenbroek 
109e3b8d4bbSDavid van Moolenbroek 	suspend(FP_BLOCKED_ON_SDEV);
110e3b8d4bbSDavid van Moolenbroek 	return SUSPEND;
111e3b8d4bbSDavid van Moolenbroek }
112e3b8d4bbSDavid van Moolenbroek 
113e3b8d4bbSDavid van Moolenbroek /*
114e3b8d4bbSDavid van Moolenbroek  * Create a socket or socket pair.  Return OK on success, with the new socket
115e3b8d4bbSDavid van Moolenbroek  * device identifier(s) stored in the 'dev' array.  Return an error code upon
116e3b8d4bbSDavid van Moolenbroek  * failure.
117e3b8d4bbSDavid van Moolenbroek  */
118e3b8d4bbSDavid van Moolenbroek int
sdev_socket(int domain,int type,int protocol,dev_t * dev,int pair)119e3b8d4bbSDavid van Moolenbroek sdev_socket(int domain, int type, int protocol, dev_t * dev, int pair)
120e3b8d4bbSDavid van Moolenbroek {
121e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
122e3b8d4bbSDavid van Moolenbroek 	message m;
123e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id, sock_id2;
124e3b8d4bbSDavid van Moolenbroek 	int r;
125e3b8d4bbSDavid van Moolenbroek 
126e3b8d4bbSDavid van Moolenbroek 	/* We could return EAFNOSUPPORT, but the caller should have checked. */
127e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_domain(domain)) == NULL)
128e3b8d4bbSDavid van Moolenbroek 		panic("VFS: sdev_socket for unknown domain");
129e3b8d4bbSDavid van Moolenbroek 
130e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
131e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
132e3b8d4bbSDavid van Moolenbroek 	m.m_type = pair ? SDEV_SOCKETPAIR : SDEV_SOCKET;
133e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_socket.req_id = (sockid_t)who_e;
134e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_socket.domain = domain;
135e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_socket.type = type;
136e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_socket.protocol = protocol;
137e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_socket.user_endpt = who_e;
138e3b8d4bbSDavid van Moolenbroek 
139e3b8d4bbSDavid van Moolenbroek 	/* Send the request, and wait for the reply. */
140e3b8d4bbSDavid van Moolenbroek 	if ((r = sdev_sendrec(sp, &m)) != OK)
141e3b8d4bbSDavid van Moolenbroek 		return r;	/* socket driver died */
142e3b8d4bbSDavid van Moolenbroek 
143e3b8d4bbSDavid van Moolenbroek 	/* Parse the reply message, and check for protocol errors. */
144e3b8d4bbSDavid van Moolenbroek 	if (m.m_type != SDEV_SOCKET_REPLY) {
145e3b8d4bbSDavid van Moolenbroek 		printf("VFS: %d sent bad reply type %d for call %d\n",
146e3b8d4bbSDavid van Moolenbroek 		    sp->smap_endpt, m.m_type, job_call_nr);
147e3b8d4bbSDavid van Moolenbroek 		return EIO;
148e3b8d4bbSDavid van Moolenbroek 	}
149e3b8d4bbSDavid van Moolenbroek 
150e3b8d4bbSDavid van Moolenbroek 	sock_id = m.m_lsockdriver_vfs_socket_reply.sock_id;
151e3b8d4bbSDavid van Moolenbroek 	sock_id2 = m.m_lsockdriver_vfs_socket_reply.sock_id2;
152e3b8d4bbSDavid van Moolenbroek 
153e3b8d4bbSDavid van Moolenbroek 	/* Check for regular errors.  Upon success, return the socket(s). */
154e3b8d4bbSDavid van Moolenbroek 	if (sock_id < 0)
155e3b8d4bbSDavid van Moolenbroek 		return sock_id;
156e3b8d4bbSDavid van Moolenbroek 
157e3b8d4bbSDavid van Moolenbroek 	dev[0] = make_smap_dev(sp, sock_id);
158e3b8d4bbSDavid van Moolenbroek 
159e3b8d4bbSDavid van Moolenbroek 	if (pair) {
160e3b8d4bbSDavid van Moolenbroek 		/* Okay, one more protocol error. */
161e3b8d4bbSDavid van Moolenbroek 		if (sock_id2 < 0) {
162e3b8d4bbSDavid van Moolenbroek 			printf("VFS: %d sent bad SOCKETPAIR socket ID %d\n",
163e3b8d4bbSDavid van Moolenbroek 			    sp->smap_endpt, sock_id2);
164*491d647aSDavid van Moolenbroek 			(void)sdev_close(dev[0], FALSE /*may_suspend*/);
165e3b8d4bbSDavid van Moolenbroek 			return EIO;
166e3b8d4bbSDavid van Moolenbroek 		}
167e3b8d4bbSDavid van Moolenbroek 
168e3b8d4bbSDavid van Moolenbroek 		dev[1] = make_smap_dev(sp, sock_id2);
169e3b8d4bbSDavid van Moolenbroek 	}
170e3b8d4bbSDavid van Moolenbroek 
171e3b8d4bbSDavid van Moolenbroek 	return OK;
172e3b8d4bbSDavid van Moolenbroek }
173e3b8d4bbSDavid van Moolenbroek 
174e3b8d4bbSDavid van Moolenbroek /*
175e3b8d4bbSDavid van Moolenbroek  * Bind or connect a socket to a particular address.  These calls may block, so
176e3b8d4bbSDavid van Moolenbroek  * suspend the current process instead of making the thread wait for the reply.
177e3b8d4bbSDavid van Moolenbroek  */
178e3b8d4bbSDavid van Moolenbroek static int
sdev_bindconn(dev_t dev,int type,vir_bytes addr,unsigned int addr_len,int filp_flags)179e3b8d4bbSDavid van Moolenbroek sdev_bindconn(dev_t dev, int type, vir_bytes addr, unsigned int addr_len,
180e3b8d4bbSDavid van Moolenbroek 	int filp_flags)
181e3b8d4bbSDavid van Moolenbroek {
182e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
183e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
184e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant;
185e3b8d4bbSDavid van Moolenbroek 	message m;
186e3b8d4bbSDavid van Moolenbroek 	int r;
187e3b8d4bbSDavid van Moolenbroek 
188e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
189e3b8d4bbSDavid van Moolenbroek 		return EIO;
190e3b8d4bbSDavid van Moolenbroek 
191e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
192e3b8d4bbSDavid van Moolenbroek 	grant = cpf_grant_magic(sp->smap_endpt, who_e, addr, addr_len,
193e3b8d4bbSDavid van Moolenbroek 	    CPF_READ);
194e3b8d4bbSDavid van Moolenbroek 	if (!GRANT_VALID(grant))
195e3b8d4bbSDavid van Moolenbroek 		panic("VFS: cpf_grant_magic failed");
196e3b8d4bbSDavid van Moolenbroek 
197e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
198e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
199e3b8d4bbSDavid van Moolenbroek 	m.m_type = type;
200e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.req_id = (sockid_t)who_e;
201e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.sock_id = sock_id;
202e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.grant = grant;
203e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.len = addr_len;
204e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.user_endpt = who_e;
205e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.sflags =
206e3b8d4bbSDavid van Moolenbroek 	    (filp_flags & O_NONBLOCK) ? SDEV_NONBLOCK : 0;
207e3b8d4bbSDavid van Moolenbroek 
208e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
209e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
210e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_bindconn failed: %d", r);
211e3b8d4bbSDavid van Moolenbroek 
212e3b8d4bbSDavid van Moolenbroek 	/* Suspend the process until the reply arrives. */
213e3b8d4bbSDavid van Moolenbroek 	return sdev_suspend(dev, grant, GRANT_INVALID, GRANT_INVALID, -1, 0);
214e3b8d4bbSDavid van Moolenbroek }
215e3b8d4bbSDavid van Moolenbroek 
216e3b8d4bbSDavid van Moolenbroek /*
217e3b8d4bbSDavid van Moolenbroek  * Bind a socket to a local address.
218e3b8d4bbSDavid van Moolenbroek  */
219e3b8d4bbSDavid van Moolenbroek int
sdev_bind(dev_t dev,vir_bytes addr,unsigned int addr_len,int filp_flags)220e3b8d4bbSDavid van Moolenbroek sdev_bind(dev_t dev, vir_bytes addr, unsigned int addr_len, int filp_flags)
221e3b8d4bbSDavid van Moolenbroek {
222e3b8d4bbSDavid van Moolenbroek 
223e3b8d4bbSDavid van Moolenbroek 	return sdev_bindconn(dev, SDEV_BIND, addr, addr_len, filp_flags);
224e3b8d4bbSDavid van Moolenbroek }
225e3b8d4bbSDavid van Moolenbroek 
226e3b8d4bbSDavid van Moolenbroek /*
227e3b8d4bbSDavid van Moolenbroek  * Connect a socket to a remote address.
228e3b8d4bbSDavid van Moolenbroek  */
229e3b8d4bbSDavid van Moolenbroek int
sdev_connect(dev_t dev,vir_bytes addr,unsigned int addr_len,int filp_flags)230e3b8d4bbSDavid van Moolenbroek sdev_connect(dev_t dev, vir_bytes addr, unsigned int addr_len, int filp_flags)
231e3b8d4bbSDavid van Moolenbroek {
232e3b8d4bbSDavid van Moolenbroek 
233e3b8d4bbSDavid van Moolenbroek 	return sdev_bindconn(dev, SDEV_CONNECT, addr, addr_len, filp_flags);
234e3b8d4bbSDavid van Moolenbroek }
235e3b8d4bbSDavid van Moolenbroek 
236e3b8d4bbSDavid van Moolenbroek /*
237e3b8d4bbSDavid van Moolenbroek  * Send and receive a "simple" request: listen, shutdown, or close.  Note that
238e3b8d4bbSDavid van Moolenbroek  * while cancel requests use the same request format, they require a different
239e3b8d4bbSDavid van Moolenbroek  * way of handling their replies.
240e3b8d4bbSDavid van Moolenbroek  */
241e3b8d4bbSDavid van Moolenbroek static int
sdev_simple(dev_t dev,int type,int param)242e3b8d4bbSDavid van Moolenbroek sdev_simple(dev_t dev, int type, int param)
243e3b8d4bbSDavid van Moolenbroek {
244e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
245e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
246e3b8d4bbSDavid van Moolenbroek 	message m;
247e3b8d4bbSDavid van Moolenbroek 	int r;
248e3b8d4bbSDavid van Moolenbroek 
249e3b8d4bbSDavid van Moolenbroek 	assert(type == SDEV_LISTEN || type == SDEV_SHUTDOWN ||
250e3b8d4bbSDavid van Moolenbroek 	    type == SDEV_CLOSE);
251e3b8d4bbSDavid van Moolenbroek 
252e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
253e3b8d4bbSDavid van Moolenbroek 		return EIO;
254e3b8d4bbSDavid van Moolenbroek 
255e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
256e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
257e3b8d4bbSDavid van Moolenbroek 	m.m_type = type;
258e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_simple.req_id = (sockid_t)who_e;
259e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_simple.sock_id = sock_id;
260e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_simple.param = param;
261e3b8d4bbSDavid van Moolenbroek 
262e3b8d4bbSDavid van Moolenbroek 	/* Send the request, and wait for the reply. */
263e3b8d4bbSDavid van Moolenbroek 	if ((r = sdev_sendrec(sp, &m)) != OK)
264e3b8d4bbSDavid van Moolenbroek 		return r;	/* socket driver died */
265e3b8d4bbSDavid van Moolenbroek 
266e3b8d4bbSDavid van Moolenbroek 	/* Parse and return the reply. */
267e3b8d4bbSDavid van Moolenbroek 	if (m.m_type != SDEV_REPLY) {
268e3b8d4bbSDavid van Moolenbroek 		printf("VFS: %d sent bad reply type %d for call %d\n",
269e3b8d4bbSDavid van Moolenbroek 		    sp->smap_endpt, m.m_type, job_call_nr);
270e3b8d4bbSDavid van Moolenbroek 		return EIO;
271e3b8d4bbSDavid van Moolenbroek 	}
272e3b8d4bbSDavid van Moolenbroek 
273e3b8d4bbSDavid van Moolenbroek 	return m.m_lsockdriver_vfs_reply.status;
274e3b8d4bbSDavid van Moolenbroek }
275e3b8d4bbSDavid van Moolenbroek 
276e3b8d4bbSDavid van Moolenbroek /*
277e3b8d4bbSDavid van Moolenbroek  * Put a socket in listening mode.
278e3b8d4bbSDavid van Moolenbroek  */
279e3b8d4bbSDavid van Moolenbroek int
sdev_listen(dev_t dev,int backlog)280e3b8d4bbSDavid van Moolenbroek sdev_listen(dev_t dev, int backlog)
281e3b8d4bbSDavid van Moolenbroek {
282e3b8d4bbSDavid van Moolenbroek 
283e3b8d4bbSDavid van Moolenbroek 	assert(backlog >= 0);
284e3b8d4bbSDavid van Moolenbroek 
285e3b8d4bbSDavid van Moolenbroek 	return sdev_simple(dev, SDEV_LISTEN, backlog);
286e3b8d4bbSDavid van Moolenbroek }
287e3b8d4bbSDavid van Moolenbroek 
288e3b8d4bbSDavid van Moolenbroek /*
289e3b8d4bbSDavid van Moolenbroek  * Accept a new connection on a socket.
290e3b8d4bbSDavid van Moolenbroek  */
291e3b8d4bbSDavid van Moolenbroek int
sdev_accept(dev_t dev,vir_bytes addr,unsigned int addr_len,int filp_flags,int listen_fd)292e3b8d4bbSDavid van Moolenbroek sdev_accept(dev_t dev, vir_bytes addr, unsigned int addr_len, int filp_flags,
293e3b8d4bbSDavid van Moolenbroek 	int listen_fd)
294e3b8d4bbSDavid van Moolenbroek {
295e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
296e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
297e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant;
298e3b8d4bbSDavid van Moolenbroek 	message m;
299e3b8d4bbSDavid van Moolenbroek 	int r;
300e3b8d4bbSDavid van Moolenbroek 
301e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
302e3b8d4bbSDavid van Moolenbroek 		return EIO;
303e3b8d4bbSDavid van Moolenbroek 
304e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
305e3b8d4bbSDavid van Moolenbroek 	if (addr != 0) {
306e3b8d4bbSDavid van Moolenbroek 		grant = cpf_grant_magic(sp->smap_endpt, who_e, addr, addr_len,
307e3b8d4bbSDavid van Moolenbroek 		    CPF_WRITE);
308e3b8d4bbSDavid van Moolenbroek 		if (!GRANT_VALID(grant))
309e3b8d4bbSDavid van Moolenbroek 			panic("VFS: cpf_grant_magic failed");
310e3b8d4bbSDavid van Moolenbroek 	} else
311e3b8d4bbSDavid van Moolenbroek 		grant = GRANT_INVALID;
312e3b8d4bbSDavid van Moolenbroek 
313e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
314e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
315e3b8d4bbSDavid van Moolenbroek 	m.m_type = SDEV_ACCEPT;
316e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.req_id = (sockid_t)who_e;
317e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.sock_id = sock_id;
318e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.grant = grant;
319e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.len = addr_len;
320e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.user_endpt = who_e;
321e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_addr.sflags =
322e3b8d4bbSDavid van Moolenbroek 	    (filp_flags & O_NONBLOCK) ? SDEV_NONBLOCK : 0;
323e3b8d4bbSDavid van Moolenbroek 
324e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
325e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
326e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_accept failed: %d", r);
327e3b8d4bbSDavid van Moolenbroek 
328e3b8d4bbSDavid van Moolenbroek 	/* Suspend the process until the reply arrives. */
329e3b8d4bbSDavid van Moolenbroek 	return sdev_suspend(dev, grant, GRANT_INVALID, GRANT_INVALID,
330e3b8d4bbSDavid van Moolenbroek 	    listen_fd, 0);
331e3b8d4bbSDavid van Moolenbroek }
332e3b8d4bbSDavid van Moolenbroek 
333e3b8d4bbSDavid van Moolenbroek /*
334e3b8d4bbSDavid van Moolenbroek  * Send or receive a message on a socket.  All read (read(2), recvfrom(2), and
335e3b8d4bbSDavid van Moolenbroek  * recvmsg(2)) and write (write(2), sendto(2), sendmsg(2)) system calls on
336e3b8d4bbSDavid van Moolenbroek  * sockets pass through this function.  The function is named sdev_readwrite
337e3b8d4bbSDavid van Moolenbroek  * rather than sdev_sendrecv to avoid confusion with sdev_sendrec.
338e3b8d4bbSDavid van Moolenbroek  */
339e3b8d4bbSDavid van Moolenbroek int
sdev_readwrite(dev_t dev,vir_bytes data_buf,size_t data_len,vir_bytes ctl_buf,unsigned int ctl_len,vir_bytes addr_buf,unsigned int addr_len,int flags,int rw_flag,int filp_flags,vir_bytes user_buf)340e3b8d4bbSDavid van Moolenbroek sdev_readwrite(dev_t dev, vir_bytes data_buf, size_t data_len,
341e3b8d4bbSDavid van Moolenbroek 	vir_bytes ctl_buf, unsigned int ctl_len, vir_bytes addr_buf,
342e3b8d4bbSDavid van Moolenbroek 	unsigned int addr_len, int flags, int rw_flag, int filp_flags,
343e3b8d4bbSDavid van Moolenbroek 	vir_bytes user_buf)
344e3b8d4bbSDavid van Moolenbroek {
345e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
346e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
347e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t data_grant, ctl_grant, addr_grant;
348e3b8d4bbSDavid van Moolenbroek 	message m;
349e3b8d4bbSDavid van Moolenbroek 	int r, bits;
350e3b8d4bbSDavid van Moolenbroek 
351e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
352e3b8d4bbSDavid van Moolenbroek 		return EIO;
353e3b8d4bbSDavid van Moolenbroek 
354e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
355e3b8d4bbSDavid van Moolenbroek 	data_grant = GRANT_INVALID;
356e3b8d4bbSDavid van Moolenbroek 	ctl_grant = GRANT_INVALID;
357e3b8d4bbSDavid van Moolenbroek 	addr_grant = GRANT_INVALID;
358e3b8d4bbSDavid van Moolenbroek 	bits = (rw_flag == WRITING) ? CPF_READ : CPF_WRITE;
359e3b8d4bbSDavid van Moolenbroek 
360e3b8d4bbSDavid van Moolenbroek 	/*
361e3b8d4bbSDavid van Moolenbroek 	 * Supposedly it is allowed to send or receive zero data bytes, even
362e3b8d4bbSDavid van Moolenbroek 	 * though it is a bad idea as the return value will then be zero, which
363e3b8d4bbSDavid van Moolenbroek 	 * may also indicate EOF (as per W. Richard Stevens).
364e3b8d4bbSDavid van Moolenbroek 	 */
365e3b8d4bbSDavid van Moolenbroek 	if (data_buf != 0) {
366e3b8d4bbSDavid van Moolenbroek 		data_grant = cpf_grant_magic(sp->smap_endpt, who_e, data_buf,
367e3b8d4bbSDavid van Moolenbroek 		    data_len, bits);
368e3b8d4bbSDavid van Moolenbroek 		if (!GRANT_VALID(data_grant))
369e3b8d4bbSDavid van Moolenbroek 			panic("VFS: cpf_grant_magic failed");
370e3b8d4bbSDavid van Moolenbroek 	}
371e3b8d4bbSDavid van Moolenbroek 
372e3b8d4bbSDavid van Moolenbroek 	if (ctl_buf != 0) {
373e3b8d4bbSDavid van Moolenbroek 		ctl_grant = cpf_grant_magic(sp->smap_endpt, who_e, ctl_buf,
374e3b8d4bbSDavid van Moolenbroek 		    ctl_len, bits);
375e3b8d4bbSDavid van Moolenbroek 		if (!GRANT_VALID(ctl_grant))
376e3b8d4bbSDavid van Moolenbroek 			panic("VFS: cpf_grant_magic failed");
377e3b8d4bbSDavid van Moolenbroek 	}
378e3b8d4bbSDavid van Moolenbroek 
379e3b8d4bbSDavid van Moolenbroek 	if (addr_buf != 0) {
380e3b8d4bbSDavid van Moolenbroek 		addr_grant = cpf_grant_magic(sp->smap_endpt, who_e, addr_buf,
381e3b8d4bbSDavid van Moolenbroek 		    addr_len, bits);
382e3b8d4bbSDavid van Moolenbroek 		if (!GRANT_VALID(addr_grant))
383e3b8d4bbSDavid van Moolenbroek 			panic("VFS: cpf_grant_magic failed");
384e3b8d4bbSDavid van Moolenbroek 	}
385e3b8d4bbSDavid van Moolenbroek 
386e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
387e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
388e3b8d4bbSDavid van Moolenbroek 	m.m_type = (rw_flag == WRITING) ? SDEV_SEND : SDEV_RECV;
389e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.req_id = (sockid_t)who_e;
390e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.sock_id = sock_id;
391e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.data_grant = data_grant;
392e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.data_len = data_len;
393e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.ctl_grant = ctl_grant;
394e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.ctl_len = ctl_len;
395e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.addr_grant = addr_grant;
396e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.addr_len = addr_len;
397e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.user_endpt = who_e;
398e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_sendrecv.flags = flags;
399e3b8d4bbSDavid van Moolenbroek 	if (filp_flags & O_NONBLOCK)
400e3b8d4bbSDavid van Moolenbroek 		m.m_vfs_lsockdriver_sendrecv.flags |= MSG_DONTWAIT;
401e3b8d4bbSDavid van Moolenbroek 	if (rw_flag == WRITING && (filp_flags & O_NOSIGPIPE))
402e3b8d4bbSDavid van Moolenbroek 		m.m_vfs_lsockdriver_sendrecv.flags |= MSG_NOSIGNAL;
403e3b8d4bbSDavid van Moolenbroek 
404e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
405e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
406e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_readwrite failed: %d", r);
407e3b8d4bbSDavid van Moolenbroek 
408e3b8d4bbSDavid van Moolenbroek 	/* Suspend the process until the reply arrives. */
409e3b8d4bbSDavid van Moolenbroek 	return sdev_suspend(dev, data_grant, ctl_grant, addr_grant, -1,
410e3b8d4bbSDavid van Moolenbroek 	    user_buf);
411e3b8d4bbSDavid van Moolenbroek }
412e3b8d4bbSDavid van Moolenbroek 
413e3b8d4bbSDavid van Moolenbroek /*
414e3b8d4bbSDavid van Moolenbroek  * Perform I/O control.
415e3b8d4bbSDavid van Moolenbroek  */
416e3b8d4bbSDavid van Moolenbroek int
sdev_ioctl(dev_t dev,unsigned long request,vir_bytes buf,int filp_flags)417e3b8d4bbSDavid van Moolenbroek sdev_ioctl(dev_t dev, unsigned long request, vir_bytes buf, int filp_flags)
418e3b8d4bbSDavid van Moolenbroek {
419e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
420e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
421e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant;
422e3b8d4bbSDavid van Moolenbroek 	message m;
423e3b8d4bbSDavid van Moolenbroek 	int r;
424e3b8d4bbSDavid van Moolenbroek 
425e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
426e3b8d4bbSDavid van Moolenbroek 		return EIO;
427e3b8d4bbSDavid van Moolenbroek 
428e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
429e3b8d4bbSDavid van Moolenbroek 	grant = make_ioctl_grant(sp->smap_endpt, who_e, buf, request);
430e3b8d4bbSDavid van Moolenbroek 
431e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
432e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
433e3b8d4bbSDavid van Moolenbroek 	m.m_type = SDEV_IOCTL;
434e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.req_id = (sockid_t)who_e;
435e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.sock_id = sock_id;
436e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.request = request;
437e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.grant = grant;
438e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.user_endpt = who_e;
439e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_ioctl.sflags =
440e3b8d4bbSDavid van Moolenbroek 	    (filp_flags & O_NONBLOCK) ? SDEV_NONBLOCK : 0;
441e3b8d4bbSDavid van Moolenbroek 
442e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
443e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
444e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_ioctl failed: %d", r);
445e3b8d4bbSDavid van Moolenbroek 
446e3b8d4bbSDavid van Moolenbroek 	/* Suspend the process until the reply arrives. */
447e3b8d4bbSDavid van Moolenbroek 	return sdev_suspend(dev, grant, GRANT_INVALID, GRANT_INVALID, -1, 0);
448e3b8d4bbSDavid van Moolenbroek }
449e3b8d4bbSDavid van Moolenbroek 
450e3b8d4bbSDavid van Moolenbroek /*
451e3b8d4bbSDavid van Moolenbroek  * Set socket options.
452e3b8d4bbSDavid van Moolenbroek  */
453e3b8d4bbSDavid van Moolenbroek int
sdev_setsockopt(dev_t dev,int level,int name,vir_bytes addr,unsigned int len)454e3b8d4bbSDavid van Moolenbroek sdev_setsockopt(dev_t dev, int level, int name, vir_bytes addr,
455e3b8d4bbSDavid van Moolenbroek 	unsigned int len)
456e3b8d4bbSDavid van Moolenbroek {
457e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
458e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
459e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant;
460e3b8d4bbSDavid van Moolenbroek 	message m;
461e3b8d4bbSDavid van Moolenbroek 	int r;
462e3b8d4bbSDavid van Moolenbroek 
463e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
464e3b8d4bbSDavid van Moolenbroek 		return EIO;
465e3b8d4bbSDavid van Moolenbroek 
466e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
467e3b8d4bbSDavid van Moolenbroek 	grant = cpf_grant_magic(sp->smap_endpt, who_e, addr, len, CPF_READ);
468e3b8d4bbSDavid van Moolenbroek 	if (!GRANT_VALID(grant))
469e3b8d4bbSDavid van Moolenbroek 		panic("VFS: cpf_grant_magic failed");
470e3b8d4bbSDavid van Moolenbroek 
471e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
472e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
473e3b8d4bbSDavid van Moolenbroek 	m.m_type = SDEV_SETSOCKOPT;
474e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.req_id = (sockid_t)who_e;
475e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.sock_id = sock_id;
476e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.level = level;
477e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.name = name;
478e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.grant = grant;
479e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.len = len;
480e3b8d4bbSDavid van Moolenbroek 
481e3b8d4bbSDavid van Moolenbroek 	/* Send the request, and wait for the reply. */
482e3b8d4bbSDavid van Moolenbroek 	r = sdev_sendrec(sp, &m);
483e3b8d4bbSDavid van Moolenbroek 
484e3b8d4bbSDavid van Moolenbroek 	/* Free resources. */
485e3b8d4bbSDavid van Moolenbroek 	(void)cpf_revoke(grant);
486e3b8d4bbSDavid van Moolenbroek 
487e3b8d4bbSDavid van Moolenbroek 	if (r != OK)
488e3b8d4bbSDavid van Moolenbroek 		return r;	/* socket driver died */
489e3b8d4bbSDavid van Moolenbroek 
490e3b8d4bbSDavid van Moolenbroek 	/* Parse and return the reply. */
491e3b8d4bbSDavid van Moolenbroek 	if (m.m_type != SDEV_REPLY) {
492e3b8d4bbSDavid van Moolenbroek 		printf("VFS: %d sent bad reply type %d for call %d\n",
493e3b8d4bbSDavid van Moolenbroek 		    sp->smap_endpt, m.m_type, job_call_nr);
494e3b8d4bbSDavid van Moolenbroek 		return EIO;
495e3b8d4bbSDavid van Moolenbroek 	}
496e3b8d4bbSDavid van Moolenbroek 
497e3b8d4bbSDavid van Moolenbroek 	return m.m_lsockdriver_vfs_reply.status;
498e3b8d4bbSDavid van Moolenbroek }
499e3b8d4bbSDavid van Moolenbroek 
500e3b8d4bbSDavid van Moolenbroek /*
501e3b8d4bbSDavid van Moolenbroek  * Send and receive a "get" request: getsockopt, getsockname, or getpeername.
502e3b8d4bbSDavid van Moolenbroek  */
503e3b8d4bbSDavid van Moolenbroek static int
sdev_get(dev_t dev,int type,int level,int name,vir_bytes addr,unsigned int * len)504e3b8d4bbSDavid van Moolenbroek sdev_get(dev_t dev, int type, int level, int name, vir_bytes addr,
505e3b8d4bbSDavid van Moolenbroek 	unsigned int * len)
506e3b8d4bbSDavid van Moolenbroek {
507e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
508e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
509e3b8d4bbSDavid van Moolenbroek 	cp_grant_id_t grant;
510e3b8d4bbSDavid van Moolenbroek 	message m;
511e3b8d4bbSDavid van Moolenbroek 	int r;
512e3b8d4bbSDavid van Moolenbroek 
513e3b8d4bbSDavid van Moolenbroek 	assert(type == SDEV_GETSOCKOPT || type == SDEV_GETSOCKNAME ||
514e3b8d4bbSDavid van Moolenbroek 	    type == SDEV_GETPEERNAME);
515e3b8d4bbSDavid van Moolenbroek 
516e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
517e3b8d4bbSDavid van Moolenbroek 		return EIO;
518e3b8d4bbSDavid van Moolenbroek 
519e3b8d4bbSDavid van Moolenbroek 	/* Allocate resources. */
520e3b8d4bbSDavid van Moolenbroek 	grant = cpf_grant_magic(sp->smap_endpt, who_e, addr, *len, CPF_WRITE);
521e3b8d4bbSDavid van Moolenbroek 	if (!GRANT_VALID(grant))
522e3b8d4bbSDavid van Moolenbroek 		panic("VFS: cpf_grant_magic failed");
523e3b8d4bbSDavid van Moolenbroek 
524e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
525e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
526e3b8d4bbSDavid van Moolenbroek 	m.m_type = type;
527e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.req_id = (sockid_t)who_e;
528e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.sock_id = sock_id;
529e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.level = level;
530e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.name = name;
531e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.grant = grant;
532e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_getset.len = *len;
533e3b8d4bbSDavid van Moolenbroek 
534e3b8d4bbSDavid van Moolenbroek 	/* Send the request, and wait for the reply. */
535e3b8d4bbSDavid van Moolenbroek 	r = sdev_sendrec(sp, &m);
536e3b8d4bbSDavid van Moolenbroek 
537e3b8d4bbSDavid van Moolenbroek 	/* Free resources. */
538e3b8d4bbSDavid van Moolenbroek 	(void)cpf_revoke(grant);
539e3b8d4bbSDavid van Moolenbroek 
540e3b8d4bbSDavid van Moolenbroek 	if (r != OK)
541e3b8d4bbSDavid van Moolenbroek 		return r;	/* socket driver died */
542e3b8d4bbSDavid van Moolenbroek 
543e3b8d4bbSDavid van Moolenbroek 	/* Parse and return the reply. */
544e3b8d4bbSDavid van Moolenbroek 	if (m.m_type != SDEV_REPLY) {
545e3b8d4bbSDavid van Moolenbroek 		printf("VFS: %d sent bad reply type %d for call %d\n",
546e3b8d4bbSDavid van Moolenbroek 		    sp->smap_endpt, m.m_type, job_call_nr);
547e3b8d4bbSDavid van Moolenbroek 		return EIO;
548e3b8d4bbSDavid van Moolenbroek 	}
549e3b8d4bbSDavid van Moolenbroek 
550e3b8d4bbSDavid van Moolenbroek 	if ((r = m.m_lsockdriver_vfs_reply.status) < 0)
551e3b8d4bbSDavid van Moolenbroek 		return r;
552e3b8d4bbSDavid van Moolenbroek 
553e3b8d4bbSDavid van Moolenbroek 	*len = (unsigned int)r;
554e3b8d4bbSDavid van Moolenbroek 	return OK;
555e3b8d4bbSDavid van Moolenbroek }
556e3b8d4bbSDavid van Moolenbroek 
557e3b8d4bbSDavid van Moolenbroek /*
558e3b8d4bbSDavid van Moolenbroek  * Get socket options.
559e3b8d4bbSDavid van Moolenbroek  */
560e3b8d4bbSDavid van Moolenbroek int
sdev_getsockopt(dev_t dev,int level,int name,vir_bytes addr,unsigned int * len)561e3b8d4bbSDavid van Moolenbroek sdev_getsockopt(dev_t dev, int level, int name, vir_bytes addr,
562e3b8d4bbSDavid van Moolenbroek 	unsigned int * len)
563e3b8d4bbSDavid van Moolenbroek {
564e3b8d4bbSDavid van Moolenbroek 
565e3b8d4bbSDavid van Moolenbroek 	return sdev_get(dev, SDEV_GETSOCKOPT, level, name, addr, len);
566e3b8d4bbSDavid van Moolenbroek }
567e3b8d4bbSDavid van Moolenbroek 
568e3b8d4bbSDavid van Moolenbroek /*
569e3b8d4bbSDavid van Moolenbroek  * Get the local address of a socket.
570e3b8d4bbSDavid van Moolenbroek  */
571e3b8d4bbSDavid van Moolenbroek int
sdev_getsockname(dev_t dev,vir_bytes addr,unsigned int * addr_len)572e3b8d4bbSDavid van Moolenbroek sdev_getsockname(dev_t dev, vir_bytes addr, unsigned int * addr_len)
573e3b8d4bbSDavid van Moolenbroek {
574e3b8d4bbSDavid van Moolenbroek 
575e3b8d4bbSDavid van Moolenbroek 	return sdev_get(dev, SDEV_GETSOCKNAME, 0, 0, addr, addr_len);
576e3b8d4bbSDavid van Moolenbroek }
577e3b8d4bbSDavid van Moolenbroek 
578e3b8d4bbSDavid van Moolenbroek /*
579e3b8d4bbSDavid van Moolenbroek  * Get the remote address of a socket.
580e3b8d4bbSDavid van Moolenbroek  */
581e3b8d4bbSDavid van Moolenbroek int
sdev_getpeername(dev_t dev,vir_bytes addr,unsigned int * addr_len)582e3b8d4bbSDavid van Moolenbroek sdev_getpeername(dev_t dev, vir_bytes addr, unsigned int * addr_len)
583e3b8d4bbSDavid van Moolenbroek {
584e3b8d4bbSDavid van Moolenbroek 
585e3b8d4bbSDavid van Moolenbroek 	return sdev_get(dev, SDEV_GETPEERNAME, 0, 0, addr, addr_len);
586e3b8d4bbSDavid van Moolenbroek }
587e3b8d4bbSDavid van Moolenbroek 
588e3b8d4bbSDavid van Moolenbroek /*
589e3b8d4bbSDavid van Moolenbroek  * Shut down socket send and receive operations.
590e3b8d4bbSDavid van Moolenbroek  */
591e3b8d4bbSDavid van Moolenbroek int
sdev_shutdown(dev_t dev,int how)592e3b8d4bbSDavid van Moolenbroek sdev_shutdown(dev_t dev, int how)
593e3b8d4bbSDavid van Moolenbroek {
594e3b8d4bbSDavid van Moolenbroek 
595e3b8d4bbSDavid van Moolenbroek 	assert(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR);
596e3b8d4bbSDavid van Moolenbroek 
597e3b8d4bbSDavid van Moolenbroek 	return sdev_simple(dev, SDEV_SHUTDOWN, how);
598e3b8d4bbSDavid van Moolenbroek }
599e3b8d4bbSDavid van Moolenbroek 
600e3b8d4bbSDavid van Moolenbroek /*
601e3b8d4bbSDavid van Moolenbroek  * Close the socket identified by the given socket device number.
602e3b8d4bbSDavid van Moolenbroek  */
603e3b8d4bbSDavid van Moolenbroek int
sdev_close(dev_t dev,int may_suspend)604*491d647aSDavid van Moolenbroek sdev_close(dev_t dev, int may_suspend)
605e3b8d4bbSDavid van Moolenbroek {
606*491d647aSDavid van Moolenbroek 	struct smap *sp;
607*491d647aSDavid van Moolenbroek 	sockid_t sock_id;
608*491d647aSDavid van Moolenbroek 	message m;
609*491d647aSDavid van Moolenbroek 	int r;
610e3b8d4bbSDavid van Moolenbroek 
611e3b8d4bbSDavid van Moolenbroek 	/*
612*491d647aSDavid van Moolenbroek 	 * Originally, all close requests were blocking the calling thread, but
613*491d647aSDavid van Moolenbroek 	 * the new support for SO_LINGER has changed that.  In a very strictly
614*491d647aSDavid van Moolenbroek 	 * limited subset of cases - namely, the user process calling close(2),
615*491d647aSDavid van Moolenbroek 	 * we suspend the close request and handle it asynchronously.  In all
616*491d647aSDavid van Moolenbroek 	 * other cases, including close-on-exit, close-on-exec, and even dup2,
617*491d647aSDavid van Moolenbroek 	 * the close is issued as a thread-synchronous request instead.
618e3b8d4bbSDavid van Moolenbroek 	 */
619*491d647aSDavid van Moolenbroek 	if (may_suspend) {
620*491d647aSDavid van Moolenbroek 		if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
621*491d647aSDavid van Moolenbroek 			return EIO;
622*491d647aSDavid van Moolenbroek 
623*491d647aSDavid van Moolenbroek 		/* Prepare the request message. */
624*491d647aSDavid van Moolenbroek 		memset(&m, 0, sizeof(m));
625*491d647aSDavid van Moolenbroek 		m.m_type = SDEV_CLOSE;
626*491d647aSDavid van Moolenbroek 		m.m_vfs_lsockdriver_simple.req_id = (sockid_t)who_e;
627*491d647aSDavid van Moolenbroek 		m.m_vfs_lsockdriver_simple.sock_id = sock_id;
628*491d647aSDavid van Moolenbroek 		m.m_vfs_lsockdriver_simple.param = 0;
629*491d647aSDavid van Moolenbroek 
630*491d647aSDavid van Moolenbroek 		/* Send the request to the driver. */
631*491d647aSDavid van Moolenbroek 		if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
632*491d647aSDavid van Moolenbroek 			panic("VFS: asynsend in sdev_bindconn failed: %d", r);
633*491d647aSDavid van Moolenbroek 
634*491d647aSDavid van Moolenbroek 		/* Suspend the process until the reply arrives. */
635*491d647aSDavid van Moolenbroek 		return sdev_suspend(dev, GRANT_INVALID, GRANT_INVALID,
636*491d647aSDavid van Moolenbroek 		    GRANT_INVALID, -1, 0);
637*491d647aSDavid van Moolenbroek 	} else
638*491d647aSDavid van Moolenbroek 		/* Block the calling thread until the socket is closed. */
639e3b8d4bbSDavid van Moolenbroek 		return sdev_simple(dev, SDEV_CLOSE, SDEV_NONBLOCK);
640e3b8d4bbSDavid van Moolenbroek }
641e3b8d4bbSDavid van Moolenbroek 
642e3b8d4bbSDavid van Moolenbroek /*
643e3b8d4bbSDavid van Moolenbroek  * Initiate a select call on a socket device.  Return OK iff the request was
644e3b8d4bbSDavid van Moolenbroek  * sent, without suspending the process.
645e3b8d4bbSDavid van Moolenbroek  */
646e3b8d4bbSDavid van Moolenbroek int
sdev_select(dev_t dev,int ops)647e3b8d4bbSDavid van Moolenbroek sdev_select(dev_t dev, int ops)
648e3b8d4bbSDavid van Moolenbroek {
649e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
650e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
651e3b8d4bbSDavid van Moolenbroek 	message m;
652e3b8d4bbSDavid van Moolenbroek 	int r;
653e3b8d4bbSDavid van Moolenbroek 
654e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(dev, &sock_id)) == NULL)
655e3b8d4bbSDavid van Moolenbroek 		return EIO;
656e3b8d4bbSDavid van Moolenbroek 
657e3b8d4bbSDavid van Moolenbroek 	/* Prepare the request message. */
658e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
659e3b8d4bbSDavid van Moolenbroek 	m.m_type = SDEV_SELECT;
660e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_select.sock_id = sock_id;
661e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lsockdriver_select.ops = ops;
662e3b8d4bbSDavid van Moolenbroek 
663e3b8d4bbSDavid van Moolenbroek 	/* Send the request to the driver. */
664e3b8d4bbSDavid van Moolenbroek 	if ((r = asynsend3(sp->smap_endpt, &m, AMF_NOREPLY)) != OK)
665e3b8d4bbSDavid van Moolenbroek 		panic("VFS: asynsend in sdev_select failed: %d", r);
666e3b8d4bbSDavid van Moolenbroek 
667e3b8d4bbSDavid van Moolenbroek 	return OK;
668e3b8d4bbSDavid van Moolenbroek }
669e3b8d4bbSDavid van Moolenbroek 
670e3b8d4bbSDavid van Moolenbroek /*
671e3b8d4bbSDavid van Moolenbroek  * A reply has arrived for a previous socket accept request, and the reply
672e3b8d4bbSDavid van Moolenbroek  * indicates that a socket has been accepted.  A status is also returned;
673e3b8d4bbSDavid van Moolenbroek  * usually, this status is OK, but if not, the newly accepted socket must be
674e3b8d4bbSDavid van Moolenbroek  * closed immediately again.  Process the low-level aspects of the reply, and
675e3b8d4bbSDavid van Moolenbroek  * call resume_accept() to let the upper socket layer handle the rest.  This
676e3b8d4bbSDavid van Moolenbroek  * function is always called from a worker thread, and may thus block.
677e3b8d4bbSDavid van Moolenbroek  */
678e3b8d4bbSDavid van Moolenbroek static void
sdev_finish_accept(struct fproc * rfp,message * m_ptr)679e3b8d4bbSDavid van Moolenbroek sdev_finish_accept(struct fproc * rfp, message * m_ptr)
680e3b8d4bbSDavid van Moolenbroek {
681e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
682e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
683e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
684e3b8d4bbSDavid van Moolenbroek 	unsigned int len;
685e3b8d4bbSDavid van Moolenbroek 	int status;
686e3b8d4bbSDavid van Moolenbroek 
687e3b8d4bbSDavid van Moolenbroek 	assert(rfp->fp_sdev.callnr == VFS_ACCEPT);
688e3b8d4bbSDavid van Moolenbroek 	assert(m_ptr->m_type == SDEV_ACCEPT_REPLY);
689e3b8d4bbSDavid van Moolenbroek 	assert(m_ptr->m_lsockdriver_vfs_accept_reply.sock_id >= 0);
690e3b8d4bbSDavid van Moolenbroek 
691e3b8d4bbSDavid van Moolenbroek 	/* Free resources.  Accept requests use up to one grant. */
692e3b8d4bbSDavid van Moolenbroek 	if (GRANT_VALID(rfp->fp_sdev.grant[0]))
693e3b8d4bbSDavid van Moolenbroek 		cpf_revoke(rfp->fp_sdev.grant[0]);
694e3b8d4bbSDavid van Moolenbroek 	assert(!GRANT_VALID(rfp->fp_sdev.grant[1]));
695e3b8d4bbSDavid van Moolenbroek 	assert(!GRANT_VALID(rfp->fp_sdev.grant[2]));
696e3b8d4bbSDavid van Moolenbroek 
697e3b8d4bbSDavid van Moolenbroek 	sock_id = m_ptr->m_lsockdriver_vfs_accept_reply.sock_id;
698e3b8d4bbSDavid van Moolenbroek 	status = m_ptr->m_lsockdriver_vfs_accept_reply.status;
699e3b8d4bbSDavid van Moolenbroek 	len = m_ptr->m_lsockdriver_vfs_accept_reply.len;
700e3b8d4bbSDavid van Moolenbroek 
701e3b8d4bbSDavid van Moolenbroek 	/*
702e3b8d4bbSDavid van Moolenbroek 	 * We do not want the upper socket layer (socket.c) to deal with smap
703e3b8d4bbSDavid van Moolenbroek 	 * and socket ID details, so we construct the new socket device number
704e3b8d4bbSDavid van Moolenbroek 	 * here.  We won't use the saved listen FD to determine the smap entry
705e3b8d4bbSDavid van Moolenbroek 	 * here, since that involves file pointers and other upper-layer-only
706e3b8d4bbSDavid van Moolenbroek 	 * stuff.  So we have to look it up by the source endpoint.  As a
707e3b8d4bbSDavid van Moolenbroek 	 * result, we detect some driver deaths here (but not all: see below).
708e3b8d4bbSDavid van Moolenbroek 	 */
709e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_endpt(m_ptr->m_source)) != NULL) {
710e3b8d4bbSDavid van Moolenbroek 		/* Leave 'status' as is, regardless of whether it is OK. */
711e3b8d4bbSDavid van Moolenbroek 		dev = make_smap_dev(sp, sock_id);
712e3b8d4bbSDavid van Moolenbroek 	} else {
713e3b8d4bbSDavid van Moolenbroek 		/*
714e3b8d4bbSDavid van Moolenbroek 		 * The driver must have died while the thread was blocked on
715e3b8d4bbSDavid van Moolenbroek 		 * activation.  Extremely rare, but theoretically possible.
716e3b8d4bbSDavid van Moolenbroek 		 * Some driver deaths are indicated only by a driver-up
717e3b8d4bbSDavid van Moolenbroek 		 * announcement though; resume_accept() will detect this by
718e3b8d4bbSDavid van Moolenbroek 		 * checking that the listening socket has not been invalidated.
719e3b8d4bbSDavid van Moolenbroek 		 */
720e3b8d4bbSDavid van Moolenbroek 		status = EIO;
721e3b8d4bbSDavid van Moolenbroek 		dev = NO_DEV;
722e3b8d4bbSDavid van Moolenbroek 	}
723e3b8d4bbSDavid van Moolenbroek 
724e3b8d4bbSDavid van Moolenbroek 	/* Let the upper socket layer handle the rest. */
725e3b8d4bbSDavid van Moolenbroek 	resume_accept(rfp, status, dev, len, rfp->fp_sdev.aux.fd);
726e3b8d4bbSDavid van Moolenbroek }
727e3b8d4bbSDavid van Moolenbroek 
728e3b8d4bbSDavid van Moolenbroek /*
729e3b8d4bbSDavid van Moolenbroek  * Worker thread stub for finishing successful accept requests.
730e3b8d4bbSDavid van Moolenbroek  */
731e3b8d4bbSDavid van Moolenbroek static void
do_accept_reply(void)732e3b8d4bbSDavid van Moolenbroek do_accept_reply(void)
733e3b8d4bbSDavid van Moolenbroek {
734e3b8d4bbSDavid van Moolenbroek 
735e3b8d4bbSDavid van Moolenbroek 	sdev_finish_accept(fp, &job_m_in);
736e3b8d4bbSDavid van Moolenbroek }
737e3b8d4bbSDavid van Moolenbroek 
738e3b8d4bbSDavid van Moolenbroek /*
739e3b8d4bbSDavid van Moolenbroek  * With the exception of successful accept requests, this function is called
740e3b8d4bbSDavid van Moolenbroek  * whenever a reply is received for a socket driver request for which the
741e3b8d4bbSDavid van Moolenbroek  * corresponding user process was suspended (as opposed to requests which just
742e3b8d4bbSDavid van Moolenbroek  * suspend the worker thread), i.e., for long-lasting socket calls.  This
743e3b8d4bbSDavid van Moolenbroek  * function is also called if the socket driver has died during a long-lasting
744e3b8d4bbSDavid van Moolenbroek  * socket call, in which case the given message's m_type is a negative error
745e3b8d4bbSDavid van Moolenbroek  * code.
746e3b8d4bbSDavid van Moolenbroek  *
747e3b8d4bbSDavid van Moolenbroek  * The division between the upper socket layer (socket.c) and the lower socket
748e3b8d4bbSDavid van Moolenbroek  * layer (this file) here is roughly: if resuming the system call involves no
749e3b8d4bbSDavid van Moolenbroek  * more than a simple replycode() call, do that here; otherwise call into the
750e3b8d4bbSDavid van Moolenbroek  * upper socket layer to handle the details.  In any case, do not ever let the
751e3b8d4bbSDavid van Moolenbroek  * upper socket layer deal with reply message parsing or suspension state.
752e3b8d4bbSDavid van Moolenbroek  *
753e3b8d4bbSDavid van Moolenbroek  * This function may or may not be called from a worker thread; as such, it
754e3b8d4bbSDavid van Moolenbroek  * MUST NOT block its calling thread.  This function is called for failed
755e3b8d4bbSDavid van Moolenbroek  * accept requests; successful accept requests have their replies routed
756e3b8d4bbSDavid van Moolenbroek  * through sdev_finish_accept() instead, because those require a worker thread.
757e3b8d4bbSDavid van Moolenbroek  */
758e3b8d4bbSDavid van Moolenbroek static void
sdev_finish(struct fproc * rfp,message * m_ptr)759e3b8d4bbSDavid van Moolenbroek sdev_finish(struct fproc * rfp, message * m_ptr)
760e3b8d4bbSDavid van Moolenbroek {
761e3b8d4bbSDavid van Moolenbroek 	unsigned int ctl_len, addr_len;
762e3b8d4bbSDavid van Moolenbroek 	int callnr, status, flags;
763e3b8d4bbSDavid van Moolenbroek 
764e3b8d4bbSDavid van Moolenbroek 	/* The suspension status must just have been cleared by the caller. */
765e3b8d4bbSDavid van Moolenbroek 	assert(rfp->fp_blocked_on == FP_BLOCKED_ON_NONE);
766e3b8d4bbSDavid van Moolenbroek 
767e3b8d4bbSDavid van Moolenbroek 	/*
768e3b8d4bbSDavid van Moolenbroek 	 * Free resources.  Every suspending call sets all grant fields, so we
769e3b8d4bbSDavid van Moolenbroek 	 * can safely revoke all of them without testing the original call.
770e3b8d4bbSDavid van Moolenbroek 	 */
771e3b8d4bbSDavid van Moolenbroek 	if (GRANT_VALID(rfp->fp_sdev.grant[0]))
772e3b8d4bbSDavid van Moolenbroek 		cpf_revoke(rfp->fp_sdev.grant[0]);
773e3b8d4bbSDavid van Moolenbroek 	if (GRANT_VALID(rfp->fp_sdev.grant[1]))
774e3b8d4bbSDavid van Moolenbroek 		cpf_revoke(rfp->fp_sdev.grant[1]);
775e3b8d4bbSDavid van Moolenbroek 	if (GRANT_VALID(rfp->fp_sdev.grant[2]))
776e3b8d4bbSDavid van Moolenbroek 		cpf_revoke(rfp->fp_sdev.grant[2]);
777e3b8d4bbSDavid van Moolenbroek 
778e3b8d4bbSDavid van Moolenbroek 	/*
779e3b8d4bbSDavid van Moolenbroek 	 * Now that the socket driver call has finished (or been stopped due to
780e3b8d4bbSDavid van Moolenbroek 	 * driver death), we need to finish the corresponding system call from
781e3b8d4bbSDavid van Moolenbroek 	 * the user process.  The action to take depends on the system call.
782e3b8d4bbSDavid van Moolenbroek 	 */
783e3b8d4bbSDavid van Moolenbroek 	callnr = rfp->fp_sdev.callnr;
784e3b8d4bbSDavid van Moolenbroek 
785e3b8d4bbSDavid van Moolenbroek 	switch (callnr) {
786e3b8d4bbSDavid van Moolenbroek 	case VFS_BIND:
787e3b8d4bbSDavid van Moolenbroek 	case VFS_CONNECT:
788e3b8d4bbSDavid van Moolenbroek 	case VFS_WRITE:
789e3b8d4bbSDavid van Moolenbroek 	case VFS_SENDTO:
790e3b8d4bbSDavid van Moolenbroek 	case VFS_SENDMSG:
791e3b8d4bbSDavid van Moolenbroek 	case VFS_IOCTL:
792*491d647aSDavid van Moolenbroek 	case VFS_CLOSE:
793e3b8d4bbSDavid van Moolenbroek 		/*
794e3b8d4bbSDavid van Moolenbroek 		 * These calls all use the same SDEV_REPLY reply type and only
795e3b8d4bbSDavid van Moolenbroek 		 * need to reply an OK-or-error status code back to userland.
796e3b8d4bbSDavid van Moolenbroek 		 */
797e3b8d4bbSDavid van Moolenbroek 		if (m_ptr->m_type == SDEV_REPLY) {
798e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_lsockdriver_vfs_reply.status;
799*491d647aSDavid van Moolenbroek 
800*491d647aSDavid van Moolenbroek 			/*
801*491d647aSDavid van Moolenbroek 			 * For close(2) calls, the return value must indicate
802*491d647aSDavid van Moolenbroek 			 * that the file descriptor has been closed.
803*491d647aSDavid van Moolenbroek 			 */
804*491d647aSDavid van Moolenbroek 			if (callnr == VFS_CLOSE &&
805*491d647aSDavid van Moolenbroek 			    status != OK && status != EINPROGRESS)
806*491d647aSDavid van Moolenbroek 				status = OK;
807e3b8d4bbSDavid van Moolenbroek 		} else if (m_ptr->m_type < 0) {
808e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_type;
809e3b8d4bbSDavid van Moolenbroek 		} else {
810e3b8d4bbSDavid van Moolenbroek 			printf("VFS: %d sent bad reply type %d for call %d\n",
811e3b8d4bbSDavid van Moolenbroek 			    m_ptr->m_source, m_ptr->m_type, callnr);
812e3b8d4bbSDavid van Moolenbroek 			status = EIO;
813e3b8d4bbSDavid van Moolenbroek 		}
814e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, status);
815e3b8d4bbSDavid van Moolenbroek 		break;
816e3b8d4bbSDavid van Moolenbroek 
817e3b8d4bbSDavid van Moolenbroek 	case VFS_READ:
818e3b8d4bbSDavid van Moolenbroek 	case VFS_RECVFROM:
819e3b8d4bbSDavid van Moolenbroek 	case VFS_RECVMSG:
820e3b8d4bbSDavid van Moolenbroek 		/*
821e3b8d4bbSDavid van Moolenbroek 		 * These calls use SDEV_RECV_REPLY.  The action to take depends
822e3b8d4bbSDavid van Moolenbroek 		 * on the exact call.
823e3b8d4bbSDavid van Moolenbroek 		 */
824e3b8d4bbSDavid van Moolenbroek 		ctl_len = addr_len = 0;
825e3b8d4bbSDavid van Moolenbroek 		flags = 0;
826e3b8d4bbSDavid van Moolenbroek 		if (m_ptr->m_type == SDEV_RECV_REPLY) {
827e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_lsockdriver_vfs_recv_reply.status;
828e3b8d4bbSDavid van Moolenbroek 			ctl_len = m_ptr->m_lsockdriver_vfs_recv_reply.ctl_len;
829e3b8d4bbSDavid van Moolenbroek 			addr_len =
830e3b8d4bbSDavid van Moolenbroek 			    m_ptr->m_lsockdriver_vfs_recv_reply.addr_len;
831e3b8d4bbSDavid van Moolenbroek 			flags = m_ptr->m_lsockdriver_vfs_recv_reply.flags;
832e3b8d4bbSDavid van Moolenbroek 		} else if (m_ptr->m_type < 0) {
833e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_type;
834e3b8d4bbSDavid van Moolenbroek 		} else {
835e3b8d4bbSDavid van Moolenbroek 			printf("VFS: %d sent bad reply type %d for call %d\n",
836e3b8d4bbSDavid van Moolenbroek 			    m_ptr->m_source, m_ptr->m_type, callnr);
837e3b8d4bbSDavid van Moolenbroek 			status = EIO;
838e3b8d4bbSDavid van Moolenbroek 		}
839e3b8d4bbSDavid van Moolenbroek 
840e3b8d4bbSDavid van Moolenbroek 		switch (callnr) {
841e3b8d4bbSDavid van Moolenbroek 		case VFS_READ:
842e3b8d4bbSDavid van Moolenbroek 			replycode(rfp->fp_endpoint, status);
843e3b8d4bbSDavid van Moolenbroek 			break;
844e3b8d4bbSDavid van Moolenbroek 		case VFS_RECVFROM:
845e3b8d4bbSDavid van Moolenbroek 			resume_recvfrom(rfp, status, addr_len);
846e3b8d4bbSDavid van Moolenbroek 			break;
847e3b8d4bbSDavid van Moolenbroek 		case VFS_RECVMSG:
848e3b8d4bbSDavid van Moolenbroek 			resume_recvmsg(rfp, status, ctl_len, addr_len, flags,
849e3b8d4bbSDavid van Moolenbroek 			    rfp->fp_sdev.aux.buf);
850e3b8d4bbSDavid van Moolenbroek 			break;
851e3b8d4bbSDavid van Moolenbroek 		}
852e3b8d4bbSDavid van Moolenbroek 		break;
853e3b8d4bbSDavid van Moolenbroek 
854e3b8d4bbSDavid van Moolenbroek 	case VFS_ACCEPT:
855e3b8d4bbSDavid van Moolenbroek 		/*
856e3b8d4bbSDavid van Moolenbroek 		 * This call uses SDEV_ACCEPT_REPLY.  We only get here if the
857e3b8d4bbSDavid van Moolenbroek 		 * accept call has failed without creating a new socket, in
858e3b8d4bbSDavid van Moolenbroek 		 * which case we can simply call replycode() with the error.
859e3b8d4bbSDavid van Moolenbroek 		 * For nothing other than consistency, we let resume_accept()
860e3b8d4bbSDavid van Moolenbroek 		 * handle this case too.
861e3b8d4bbSDavid van Moolenbroek 		 */
862e3b8d4bbSDavid van Moolenbroek 		addr_len = 0;
863e3b8d4bbSDavid van Moolenbroek 		if (m_ptr->m_type == SDEV_ACCEPT_REPLY) {
864e3b8d4bbSDavid van Moolenbroek 			assert(m_ptr->m_lsockdriver_vfs_accept_reply.sock_id <
865e3b8d4bbSDavid van Moolenbroek 			    0);
866e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_lsockdriver_vfs_accept_reply.status;
867e3b8d4bbSDavid van Moolenbroek 			addr_len = m_ptr->m_lsockdriver_vfs_accept_reply.len;
868e3b8d4bbSDavid van Moolenbroek 		} else if (m_ptr->m_type < 0) {
869e3b8d4bbSDavid van Moolenbroek 			status = m_ptr->m_type;
870e3b8d4bbSDavid van Moolenbroek 		} else {
871e3b8d4bbSDavid van Moolenbroek 			printf("VFS: %d sent bad reply type %d for call %d\n",
872e3b8d4bbSDavid van Moolenbroek 			    m_ptr->m_source, m_ptr->m_type, callnr);
873e3b8d4bbSDavid van Moolenbroek 			status = EIO;
874e3b8d4bbSDavid van Moolenbroek 		}
875e3b8d4bbSDavid van Moolenbroek 		/*
876e3b8d4bbSDavid van Moolenbroek 		 * Quick rundown of m_lsockdriver_vfs_accept_reply cases:
877e3b8d4bbSDavid van Moolenbroek 		 *
878e3b8d4bbSDavid van Moolenbroek 		 * - sock_id >= 0, status == OK: new socket accepted
879e3b8d4bbSDavid van Moolenbroek 		 * - sock_id >= 0, status != OK: new socket must be closed
880e3b8d4bbSDavid van Moolenbroek 		 * - sock_id < 0, status != OK: failure accepting socket
881e3b8d4bbSDavid van Moolenbroek 		 * - sock_id < 0, status == OK: invalid, covered right here
882e3b8d4bbSDavid van Moolenbroek 		 *
883e3b8d4bbSDavid van Moolenbroek 		 * See libsockdriver for why there are two reply fields at all.
884e3b8d4bbSDavid van Moolenbroek 		 */
885e3b8d4bbSDavid van Moolenbroek 		if (status >= 0) {
886e3b8d4bbSDavid van Moolenbroek 			printf("VFS: %d sent bad status %d for call %d\n",
887e3b8d4bbSDavid van Moolenbroek 			    m_ptr->m_source, status, callnr);
888e3b8d4bbSDavid van Moolenbroek 			status = EIO;
889e3b8d4bbSDavid van Moolenbroek 		}
890e3b8d4bbSDavid van Moolenbroek 		resume_accept(rfp, status, NO_DEV, addr_len,
891e3b8d4bbSDavid van Moolenbroek 		    rfp->fp_sdev.aux.fd);
892e3b8d4bbSDavid van Moolenbroek 		break;
893e3b8d4bbSDavid van Moolenbroek 
894e3b8d4bbSDavid van Moolenbroek 	default:
895e3b8d4bbSDavid van Moolenbroek 		/*
896e3b8d4bbSDavid van Moolenbroek 		 * Ultimately, enumerating all system calls that may cause
897e3b8d4bbSDavid van Moolenbroek 		 * socket I/O may prove too cumbersome.  In that case, the
898e3b8d4bbSDavid van Moolenbroek 		 * callnr field could be replaced by a field that stores the
899e3b8d4bbSDavid van Moolenbroek 		 * combination of the expected reply type and the action to
900e3b8d4bbSDavid van Moolenbroek 		 * take, for example.
901e3b8d4bbSDavid van Moolenbroek 		 */
902e3b8d4bbSDavid van Moolenbroek 		panic("VFS: socket reply %d for unknown call %d from %d",
903e3b8d4bbSDavid van Moolenbroek 		    m_ptr->m_type, callnr, rfp->fp_endpoint);
904e3b8d4bbSDavid van Moolenbroek 	}
905e3b8d4bbSDavid van Moolenbroek }
906e3b8d4bbSDavid van Moolenbroek 
907e3b8d4bbSDavid van Moolenbroek /*
908e3b8d4bbSDavid van Moolenbroek  * Abort the suspended socket call for the given process, because the
909e3b8d4bbSDavid van Moolenbroek  * corresponding socket driver has died.
910e3b8d4bbSDavid van Moolenbroek  */
911e3b8d4bbSDavid van Moolenbroek void
sdev_stop(struct fproc * rfp)912e3b8d4bbSDavid van Moolenbroek sdev_stop(struct fproc * rfp)
913e3b8d4bbSDavid van Moolenbroek {
914e3b8d4bbSDavid van Moolenbroek 	message m;
915e3b8d4bbSDavid van Moolenbroek 
916e3b8d4bbSDavid van Moolenbroek 	assert(rfp->fp_blocked_on == FP_BLOCKED_ON_SDEV);
917e3b8d4bbSDavid van Moolenbroek 
918e3b8d4bbSDavid van Moolenbroek 	rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
919e3b8d4bbSDavid van Moolenbroek 
920e3b8d4bbSDavid van Moolenbroek 	/*
921e3b8d4bbSDavid van Moolenbroek 	 * We use one single approach both here and when stopping worker
922e3b8d4bbSDavid van Moolenbroek 	 * threads: the reply message's m_type is set to an error code (always
923e3b8d4bbSDavid van Moolenbroek 	 * EIO for now) instead of an actual SDEV_ reply code.  We test for
924e3b8d4bbSDavid van Moolenbroek 	 * this case in non-suspending calls as well as in sdev_finish().
925e3b8d4bbSDavid van Moolenbroek 	 */
926e3b8d4bbSDavid van Moolenbroek 	m.m_type = EIO;
927e3b8d4bbSDavid van Moolenbroek 	sdev_finish(rfp, &m);
928e3b8d4bbSDavid van Moolenbroek }
929e3b8d4bbSDavid van Moolenbroek 
930e3b8d4bbSDavid van Moolenbroek /*
931e3b8d4bbSDavid van Moolenbroek  * Cancel the ongoing long-lasting socket call, because the calling process has
932e3b8d4bbSDavid van Moolenbroek  * received a caught or terminating signal.  This function is always called
933e3b8d4bbSDavid van Moolenbroek  * from a worker thread (as part of PM) work, with 'fp' set to the process that
934e3b8d4bbSDavid van Moolenbroek  * issued the original system call.  The calling function has just unsuspended
935e3b8d4bbSDavid van Moolenbroek  * the process out of _SDEV blocking state.  The job of this function is to
936e3b8d4bbSDavid van Moolenbroek  * issue a cancel request and then block until a reply comes in; the reply may
937e3b8d4bbSDavid van Moolenbroek  * indicate success, in which case it must be handled accordingly.
938e3b8d4bbSDavid van Moolenbroek  */
939e3b8d4bbSDavid van Moolenbroek void
sdev_cancel(void)940e3b8d4bbSDavid van Moolenbroek sdev_cancel(void)
941e3b8d4bbSDavid van Moolenbroek {
942e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
943e3b8d4bbSDavid van Moolenbroek 	message m;
944e3b8d4bbSDavid van Moolenbroek 	sockid_t sock_id;
945e3b8d4bbSDavid van Moolenbroek 
946e3b8d4bbSDavid van Moolenbroek 	/* The suspension status must just have been cleared by the caller. */
947e3b8d4bbSDavid van Moolenbroek 	assert(fp->fp_blocked_on == FP_BLOCKED_ON_NONE);
948e3b8d4bbSDavid van Moolenbroek 
949e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_dev(fp->fp_sdev.dev, &sock_id)) != NULL) {
950e3b8d4bbSDavid van Moolenbroek 		/* Prepare the request message. */
951e3b8d4bbSDavid van Moolenbroek 		memset(&m, 0, sizeof(m));
952e3b8d4bbSDavid van Moolenbroek 		m.m_type = SDEV_CANCEL;
953e3b8d4bbSDavid van Moolenbroek 		m.m_vfs_lsockdriver_simple.req_id = (sockid_t)who_e;
954e3b8d4bbSDavid van Moolenbroek 		m.m_vfs_lsockdriver_simple.sock_id = sock_id;
955e3b8d4bbSDavid van Moolenbroek 
956e3b8d4bbSDavid van Moolenbroek 		/*
957e3b8d4bbSDavid van Moolenbroek 		 * Send the cancel request, and wait for a reply.  The reply
958e3b8d4bbSDavid van Moolenbroek 		 * will be for the original request and must be processed
959e3b8d4bbSDavid van Moolenbroek 		 * accordingly.  It is possible that the original request
960e3b8d4bbSDavid van Moolenbroek 		 * actually succeeded, because 1) the cancel request resulted
961e3b8d4bbSDavid van Moolenbroek 		 * in partial success or 2) the original reply and the cancel
962e3b8d4bbSDavid van Moolenbroek 		 * request crossed each other.  It is because of the second
963e3b8d4bbSDavid van Moolenbroek 		 * case that a socket driver must not respond at all to a
964e3b8d4bbSDavid van Moolenbroek 		 * cancel operation for an unknown request.
965e3b8d4bbSDavid van Moolenbroek 		 */
966e3b8d4bbSDavid van Moolenbroek 		sdev_sendrec(sp, &m);
967e3b8d4bbSDavid van Moolenbroek 	} else
968e3b8d4bbSDavid van Moolenbroek 		m.m_type = EIO;
969e3b8d4bbSDavid van Moolenbroek 
970e3b8d4bbSDavid van Moolenbroek 	/*
971e3b8d4bbSDavid van Moolenbroek 	 * Successful accept requests require special processing, but since we
972e3b8d4bbSDavid van Moolenbroek 	 * are already operating from a working thread here, we need not spawn
973e3b8d4bbSDavid van Moolenbroek 	 * an additional worker thread for this case.
974e3b8d4bbSDavid van Moolenbroek 	 */
975e3b8d4bbSDavid van Moolenbroek 	if (m.m_type == SDEV_ACCEPT_REPLY &&
976e3b8d4bbSDavid van Moolenbroek 	    m.m_lsockdriver_vfs_accept_reply.sock_id >= 0)
977e3b8d4bbSDavid van Moolenbroek 		sdev_finish_accept(fp, &m);
978e3b8d4bbSDavid van Moolenbroek 	else
979e3b8d4bbSDavid van Moolenbroek 		sdev_finish(fp, &m);
980e3b8d4bbSDavid van Moolenbroek }
981e3b8d4bbSDavid van Moolenbroek 
982e3b8d4bbSDavid van Moolenbroek /*
983e3b8d4bbSDavid van Moolenbroek  * A socket driver has sent a reply to a socket request.  Process it, by either
984e3b8d4bbSDavid van Moolenbroek  * waking up an active worker thread, finishing the system call from here, or
985e3b8d4bbSDavid van Moolenbroek  * (in the exceptional case of accept calls) spawning a new worker thread to
986e3b8d4bbSDavid van Moolenbroek  * process the reply.  This function MUST NOT block its calling thread.
987e3b8d4bbSDavid van Moolenbroek  */
988e3b8d4bbSDavid van Moolenbroek void
sdev_reply(void)989e3b8d4bbSDavid van Moolenbroek sdev_reply(void)
990e3b8d4bbSDavid van Moolenbroek {
991e3b8d4bbSDavid van Moolenbroek 	struct fproc *rfp;
992e3b8d4bbSDavid van Moolenbroek 	struct smap *sp;
993e3b8d4bbSDavid van Moolenbroek 	struct worker_thread *wp;
994e3b8d4bbSDavid van Moolenbroek 	sockid_t req_id = -1;
995e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
996e3b8d4bbSDavid van Moolenbroek 	int slot;
997e3b8d4bbSDavid van Moolenbroek 
998e3b8d4bbSDavid van Moolenbroek 	if ((sp = get_smap_by_endpt(who_e)) == NULL) {
999e3b8d4bbSDavid van Moolenbroek 		printf("VFS: ignoring sock dev reply from unknown driver %d\n",
1000e3b8d4bbSDavid van Moolenbroek 		    who_e);
1001e3b8d4bbSDavid van Moolenbroek 		return;
1002e3b8d4bbSDavid van Moolenbroek 	}
1003e3b8d4bbSDavid van Moolenbroek 
1004e3b8d4bbSDavid van Moolenbroek 	switch (call_nr) {
1005e3b8d4bbSDavid van Moolenbroek 	case SDEV_REPLY:
1006e3b8d4bbSDavid van Moolenbroek 		req_id = m_in.m_lsockdriver_vfs_reply.req_id;
1007e3b8d4bbSDavid van Moolenbroek 		break;
1008e3b8d4bbSDavid van Moolenbroek 	case SDEV_SOCKET_REPLY:
1009e3b8d4bbSDavid van Moolenbroek 		req_id = m_in.m_lsockdriver_vfs_socket_reply.req_id;
1010e3b8d4bbSDavid van Moolenbroek 		break;
1011e3b8d4bbSDavid van Moolenbroek 	case SDEV_ACCEPT_REPLY:
1012e3b8d4bbSDavid van Moolenbroek 		req_id = m_in.m_lsockdriver_vfs_accept_reply.req_id;
1013e3b8d4bbSDavid van Moolenbroek 		break;
1014e3b8d4bbSDavid van Moolenbroek 	case SDEV_RECV_REPLY:
1015e3b8d4bbSDavid van Moolenbroek 		req_id = m_in.m_lsockdriver_vfs_recv_reply.req_id;
1016e3b8d4bbSDavid van Moolenbroek 		break;
1017e3b8d4bbSDavid van Moolenbroek 	case SDEV_SELECT1_REPLY:
1018e3b8d4bbSDavid van Moolenbroek 		dev = make_smap_dev(sp,
1019e3b8d4bbSDavid van Moolenbroek 		    m_in.m_lsockdriver_vfs_select_reply.sock_id);
1020e3b8d4bbSDavid van Moolenbroek 		select_sdev_reply1(dev,
1021e3b8d4bbSDavid van Moolenbroek 		    m_in.m_lsockdriver_vfs_select_reply.status);
1022e3b8d4bbSDavid van Moolenbroek 		return;
1023e3b8d4bbSDavid van Moolenbroek 	case SDEV_SELECT2_REPLY:
1024e3b8d4bbSDavid van Moolenbroek 		dev = make_smap_dev(sp,
1025e3b8d4bbSDavid van Moolenbroek 		    m_in.m_lsockdriver_vfs_select_reply.sock_id);
1026e3b8d4bbSDavid van Moolenbroek 		select_sdev_reply2(dev,
1027e3b8d4bbSDavid van Moolenbroek 		    m_in.m_lsockdriver_vfs_select_reply.status);
1028e3b8d4bbSDavid van Moolenbroek 		return;
1029e3b8d4bbSDavid van Moolenbroek 	default:
1030e3b8d4bbSDavid van Moolenbroek 		printf("VFS: ignoring unknown sock dev reply %d from %d\n",
1031e3b8d4bbSDavid van Moolenbroek 		    call_nr, who_e);
1032e3b8d4bbSDavid van Moolenbroek 		return;
1033e3b8d4bbSDavid van Moolenbroek 	}
1034e3b8d4bbSDavid van Moolenbroek 
1035e3b8d4bbSDavid van Moolenbroek 	if (isokendpt((endpoint_t)req_id, &slot) != OK) {
1036e3b8d4bbSDavid van Moolenbroek 		printf("VFS: ignoring sock dev reply from %d for unknown %d\n",
1037e3b8d4bbSDavid van Moolenbroek 		    who_e, req_id);
1038e3b8d4bbSDavid van Moolenbroek 		return;
1039e3b8d4bbSDavid van Moolenbroek 	}
1040e3b8d4bbSDavid van Moolenbroek 
1041e3b8d4bbSDavid van Moolenbroek 	rfp = &fproc[slot];
1042e3b8d4bbSDavid van Moolenbroek 	wp = rfp->fp_worker;
1043e3b8d4bbSDavid van Moolenbroek 	if (wp != NULL && wp->w_task == who_e && wp->w_drv_sendrec != NULL) {
1044e3b8d4bbSDavid van Moolenbroek 		assert(!fp_is_blocked(rfp));
1045e3b8d4bbSDavid van Moolenbroek 		*wp->w_drv_sendrec = m_in;
1046e3b8d4bbSDavid van Moolenbroek 		wp->w_drv_sendrec = NULL;
1047e3b8d4bbSDavid van Moolenbroek 		worker_signal(wp);	/* resume suspended thread */
1048e3b8d4bbSDavid van Moolenbroek 		/*
1049e3b8d4bbSDavid van Moolenbroek 		 * It is up to the worker thread to 1) check that the reply is
1050e3b8d4bbSDavid van Moolenbroek 		 * of the right type for the request, and 2) keep in mind that
1051e3b8d4bbSDavid van Moolenbroek 		 * the reply type may be EIO in case the socket driver died.
1052e3b8d4bbSDavid van Moolenbroek 		 */
1053e3b8d4bbSDavid van Moolenbroek 	} else if (rfp->fp_blocked_on != FP_BLOCKED_ON_SDEV ||
1054e3b8d4bbSDavid van Moolenbroek 	    get_smap_by_dev(rfp->fp_sdev.dev, NULL) != sp) {
1055e3b8d4bbSDavid van Moolenbroek 		printf("VFS: ignoring sock dev reply, %d not blocked on %d\n",
1056e3b8d4bbSDavid van Moolenbroek 		    rfp->fp_endpoint, who_e);
1057e3b8d4bbSDavid van Moolenbroek 		return;
1058e3b8d4bbSDavid van Moolenbroek 	} else if (call_nr == SDEV_ACCEPT_REPLY &&
1059e3b8d4bbSDavid van Moolenbroek 	    m_in.m_lsockdriver_vfs_accept_reply.sock_id >= 0) {
1060e3b8d4bbSDavid van Moolenbroek 		/*
1061e3b8d4bbSDavid van Moolenbroek 		 * For accept replies that return a new socket, we need to
1062e3b8d4bbSDavid van Moolenbroek 		 * spawn a worker thread, because accept calls may block (so
1063e3b8d4bbSDavid van Moolenbroek 		 * there will no longer be a worker thread) and processing the
1064e3b8d4bbSDavid van Moolenbroek 		 * reply requires additional blocking calls (which we cannot
1065e3b8d4bbSDavid van Moolenbroek 		 * issue from the main thread).  This is tricky.  Under no
1066e3b8d4bbSDavid van Moolenbroek 		 * circumstances may we "lose" a legitimate reply, because this
1067e3b8d4bbSDavid van Moolenbroek 		 * would lead to resource leaks in the socket driver.  To this
1068e3b8d4bbSDavid van Moolenbroek 		 * end, we rely on the current worker thread model to
1069e3b8d4bbSDavid van Moolenbroek 		 * prioritize regular work over PM work.  Still, sdev_cancel()
1070e3b8d4bbSDavid van Moolenbroek 		 * may end up receiving the accept reply if it was already
1071e3b8d4bbSDavid van Moolenbroek 		 * blocked waiting for the reply message, and it must then
1072e3b8d4bbSDavid van Moolenbroek 		 * perform the same tasks.
1073e3b8d4bbSDavid van Moolenbroek 		 */
1074e3b8d4bbSDavid van Moolenbroek 		/*
1075e3b8d4bbSDavid van Moolenbroek 		 * It is possible that if all threads are in use, there is a
1076e3b8d4bbSDavid van Moolenbroek 		 * "gap" between starting the thread and its activation.  The
1077e3b8d4bbSDavid van Moolenbroek 		 * main problem for this case is that the socket driver dies
1078e3b8d4bbSDavid van Moolenbroek 		 * within that gap.  For accepts, we address this with no less
1079e3b8d4bbSDavid van Moolenbroek 		 * than two checks: 1) in this file, by looking up the smap
1080e3b8d4bbSDavid van Moolenbroek 		 * entry by the reply source endpoint again - if the entry is
1081e3b8d4bbSDavid van Moolenbroek 		 * no longer valid, the socket driver must have died; 2) in
1082e3b8d4bbSDavid van Moolenbroek 		 * socket.c, by revalidating the original listening socket - if
1083e3b8d4bbSDavid van Moolenbroek 		 * the listening socket has been invalidated, the driver died.
1084e3b8d4bbSDavid van Moolenbroek 		 *
1085e3b8d4bbSDavid van Moolenbroek 		 * Since we unsuspend the process now, a socket driver sending
1086e3b8d4bbSDavid van Moolenbroek 		 * two accept replies in a row may never cause VFS to attempt
1087e3b8d4bbSDavid van Moolenbroek 		 * spawning two threads; the second reply should be ignored.
1088e3b8d4bbSDavid van Moolenbroek 		 */
1089e3b8d4bbSDavid van Moolenbroek 		assert(fp->fp_func == NULL);
1090e3b8d4bbSDavid van Moolenbroek 
1091e3b8d4bbSDavid van Moolenbroek 		worker_start(rfp, do_accept_reply, &m_in, FALSE /*use_spare*/);
1092e3b8d4bbSDavid van Moolenbroek 
1093e3b8d4bbSDavid van Moolenbroek 		/*
1094e3b8d4bbSDavid van Moolenbroek 		 * TODO: I just introduced the notion of not using the fp_u
1095e3b8d4bbSDavid van Moolenbroek 		 * union across yields after unsuspension, but for socket calls
1096e3b8d4bbSDavid van Moolenbroek 		 * we have a lot of socket state to carry over, so I'm now
1097e3b8d4bbSDavid van Moolenbroek 		 * immediately violating my own rule again here.  Possible
1098e3b8d4bbSDavid van Moolenbroek 		 * solutions: 1) introduce another blocking state just to mark
1099e3b8d4bbSDavid van Moolenbroek 		 * the fp_u union in use (this has side effects though), 2)
1100e3b8d4bbSDavid van Moolenbroek 		 * introduce a pseudo message type which covers both the accept
1101e3b8d4bbSDavid van Moolenbroek 		 * reply fields and the fp_u state (do_pending_pipe does this),
1102e3b8d4bbSDavid van Moolenbroek 		 * or 3) add a fp_flags flag for this purpose.  In any case,
1103e3b8d4bbSDavid van Moolenbroek 		 * the whole point is that we catch any attempts to reuse fp_u
1104e3b8d4bbSDavid van Moolenbroek 		 * for other purposes and thus cause state corruption. This
1105e3b8d4bbSDavid van Moolenbroek 		 * should not happen anyway, but it's too dangerous to leave
1106e3b8d4bbSDavid van Moolenbroek 		 * entirely unchecked.  --dcvmoole
1107e3b8d4bbSDavid van Moolenbroek 		 */
1108e3b8d4bbSDavid van Moolenbroek 		rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
1109e3b8d4bbSDavid van Moolenbroek 	} else {
1110e3b8d4bbSDavid van Moolenbroek 		rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
1111e3b8d4bbSDavid van Moolenbroek 
1112e3b8d4bbSDavid van Moolenbroek 		sdev_finish(rfp, &m_in);
1113e3b8d4bbSDavid van Moolenbroek 	}
1114e3b8d4bbSDavid van Moolenbroek }
1115