xref: /minix3/minix/lib/libsockdriver/sockdriver.c (revision 85723df033e1d687d5a1c1504bdc35063a74cc78)
1*85723df0SDavid van Moolenbroek /* The protocol family independent socket driver framework. */
2*85723df0SDavid van Moolenbroek /*
3*85723df0SDavid van Moolenbroek  * The table below lists all supported socket driver requests, along with
4*85723df0SDavid van Moolenbroek  * information on whether the request handler may suspend the call for later
5*85723df0SDavid van Moolenbroek  * processing, and which message layout is to be used for the request and reply
6*85723df0SDavid van Moolenbroek  * messages for each call.
7*85723df0SDavid van Moolenbroek  *
8*85723df0SDavid van Moolenbroek  * Type			May suspend	Request	layout	Reply layout
9*85723df0SDavid van Moolenbroek  * ----			-----------	--------------	------------
10*85723df0SDavid van Moolenbroek  * SDEV_SOCKET		no		socket		socket_reply
11*85723df0SDavid van Moolenbroek  * SDEV_SOCKETPAIR	no		socket		socket_reply
12*85723df0SDavid van Moolenbroek  * SDEV_BIND		yes		addr		reply
13*85723df0SDavid van Moolenbroek  * SDEV_CONNECT		yes		addr		reply
14*85723df0SDavid van Moolenbroek  * SDEV_LISTEN		no		simple		reply
15*85723df0SDavid van Moolenbroek  * SDEV_ACCEPT		yes		addr		accept_reply
16*85723df0SDavid van Moolenbroek  * SDEV_SEND		yes		sendrecv	reply
17*85723df0SDavid van Moolenbroek  * SDEV_RECV		yes		sendrecv	recv_reply
18*85723df0SDavid van Moolenbroek  * SDEV_IOCTL		yes		ioctl		reply
19*85723df0SDavid van Moolenbroek  * SDEV_SETSOCKOPT	no		getset		reply
20*85723df0SDavid van Moolenbroek  * SDEV_GETSOCKOPT	no		getset		reply
21*85723df0SDavid van Moolenbroek  * SDEV_GETSOCKNAME	no		getset		reply
22*85723df0SDavid van Moolenbroek  * SDEV_GETPEERNAME	no		getset		reply
23*85723df0SDavid van Moolenbroek  * SDEV_SHUTDOWN	no		simple		reply
24*85723df0SDavid van Moolenbroek  * SDEV_CLOSE		yes		simple		reply
25*85723df0SDavid van Moolenbroek  * SDEV_CANCEL		n/a		simple		-
26*85723df0SDavid van Moolenbroek  * SDEV_SELECT		yes (special)	select		select_reply
27*85723df0SDavid van Moolenbroek  *
28*85723df0SDavid van Moolenbroek  * The request message layouts are prefixed with "m_vfs_lsockdriver_".  The
29*85723df0SDavid van Moolenbroek  * reply message layouts are prefixed with "m_lsockdriver_vfs_", and use
30*85723df0SDavid van Moolenbroek  * message types of the format SDEV_{,SOCKET_,ACCEPT_,RECV_}REPLY, matching the
31*85723df0SDavid van Moolenbroek  * listed reply layout.  One exception is SDEV_CANCEL, which itself has no
32*85723df0SDavid van Moolenbroek  * reply at all.  The other exception is SDEV_SELECT, which has two reply
33*85723df0SDavid van Moolenbroek  * codes: SDEV_SELECT1_REPLY (for immediate replies) and SDEV_SELECT2_REPLY
34*85723df0SDavid van Moolenbroek  * (for late replies), both using the select_reply reply layout.
35*85723df0SDavid van Moolenbroek  */
36*85723df0SDavid van Moolenbroek 
37*85723df0SDavid van Moolenbroek #include <minix/drivers.h>
38*85723df0SDavid van Moolenbroek #include <minix/sockdriver.h>
39*85723df0SDavid van Moolenbroek #include <sys/ioctl.h>
40*85723df0SDavid van Moolenbroek 
41*85723df0SDavid van Moolenbroek static int running;
42*85723df0SDavid van Moolenbroek 
43*85723df0SDavid van Moolenbroek /*
44*85723df0SDavid van Moolenbroek  * Announce that we are up and running, after a fresh start or a restart.
45*85723df0SDavid van Moolenbroek  */
46*85723df0SDavid van Moolenbroek void
sockdriver_announce(void)47*85723df0SDavid van Moolenbroek sockdriver_announce(void)
48*85723df0SDavid van Moolenbroek {
49*85723df0SDavid van Moolenbroek 	static const char *sockdriver_prefix = "drv.sck.";
50*85723df0SDavid van Moolenbroek 	char key[DS_MAX_KEYLEN], label[DS_MAX_KEYLEN];
51*85723df0SDavid van Moolenbroek 	int r;
52*85723df0SDavid van Moolenbroek 
53*85723df0SDavid van Moolenbroek 	/* Publish a driver up event. */
54*85723df0SDavid van Moolenbroek 	if ((r = ds_retrieve_label_name(label, sef_self())) != OK)
55*85723df0SDavid van Moolenbroek 		panic("sockdriver: unable to get own label: %d", r);
56*85723df0SDavid van Moolenbroek 
57*85723df0SDavid van Moolenbroek 	snprintf(key, sizeof(key), "%s%s", sockdriver_prefix, label);
58*85723df0SDavid van Moolenbroek 	if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK)
59*85723df0SDavid van Moolenbroek 		panic("sockdriver: unable to publish driver up event: %d", r);
60*85723df0SDavid van Moolenbroek }
61*85723df0SDavid van Moolenbroek 
62*85723df0SDavid van Moolenbroek /*
63*85723df0SDavid van Moolenbroek  * Copy data from the caller into the local address space.  Return OK or a
64*85723df0SDavid van Moolenbroek  * negative error code.
65*85723df0SDavid van Moolenbroek  */
66*85723df0SDavid van Moolenbroek int
sockdriver_copyin(const struct sockdriver_data * __restrict data,size_t off,void * __restrict ptr,size_t len)67*85723df0SDavid van Moolenbroek sockdriver_copyin(const struct sockdriver_data * __restrict data, size_t off,
68*85723df0SDavid van Moolenbroek 	void * __restrict ptr, size_t len)
69*85723df0SDavid van Moolenbroek {
70*85723df0SDavid van Moolenbroek 
71*85723df0SDavid van Moolenbroek 	assert(data != NULL);
72*85723df0SDavid van Moolenbroek 	assert(off + len <= data->_sd_len);
73*85723df0SDavid van Moolenbroek 	assert(data->_sd_endpt != SELF);
74*85723df0SDavid van Moolenbroek 	assert(GRANT_VALID(data->_sd_grant));
75*85723df0SDavid van Moolenbroek 
76*85723df0SDavid van Moolenbroek 	return sys_safecopyfrom(data->_sd_endpt, data->_sd_grant, off,
77*85723df0SDavid van Moolenbroek 	    (vir_bytes)ptr, len);
78*85723df0SDavid van Moolenbroek }
79*85723df0SDavid van Moolenbroek 
80*85723df0SDavid van Moolenbroek /*
81*85723df0SDavid van Moolenbroek  * Copy data from the local address space to the caller.  Return OK or a
82*85723df0SDavid van Moolenbroek  * negative error code.
83*85723df0SDavid van Moolenbroek  */
84*85723df0SDavid van Moolenbroek int
sockdriver_copyout(const struct sockdriver_data * __restrict data,size_t off,const void * __restrict ptr,size_t len)85*85723df0SDavid van Moolenbroek sockdriver_copyout(const struct sockdriver_data * __restrict data, size_t off,
86*85723df0SDavid van Moolenbroek 	const void * __restrict ptr, size_t len)
87*85723df0SDavid van Moolenbroek {
88*85723df0SDavid van Moolenbroek 
89*85723df0SDavid van Moolenbroek 	assert(data != NULL);
90*85723df0SDavid van Moolenbroek 	assert(off + len <= data->_sd_len);
91*85723df0SDavid van Moolenbroek 	assert(data->_sd_endpt != SELF);
92*85723df0SDavid van Moolenbroek 	assert(GRANT_VALID(data->_sd_grant));
93*85723df0SDavid van Moolenbroek 
94*85723df0SDavid van Moolenbroek 	return sys_safecopyto(data->_sd_endpt, data->_sd_grant, off,
95*85723df0SDavid van Moolenbroek 	    (vir_bytes)ptr, len);
96*85723df0SDavid van Moolenbroek }
97*85723df0SDavid van Moolenbroek 
98*85723df0SDavid van Moolenbroek /*
99*85723df0SDavid van Moolenbroek  * Copy data between the caller and the local address space, using a vector of
100*85723df0SDavid van Moolenbroek  * at most SOCKDRIVER_IOV_MAX buffers.  Return OK or an error code.
101*85723df0SDavid van Moolenbroek  */
102*85723df0SDavid van Moolenbroek static int
sockdriver_vcopy(const struct sockdriver_data * __restrict data,size_t off,const iovec_t * __restrict iov,unsigned int iovcnt,int copyin)103*85723df0SDavid van Moolenbroek sockdriver_vcopy(const struct sockdriver_data * __restrict data, size_t off,
104*85723df0SDavid van Moolenbroek 	const iovec_t * __restrict iov, unsigned int iovcnt, int copyin)
105*85723df0SDavid van Moolenbroek {
106*85723df0SDavid van Moolenbroek 	static struct vscp_vec vec[SOCKDRIVER_IOV_MAX];
107*85723df0SDavid van Moolenbroek 	unsigned int i;
108*85723df0SDavid van Moolenbroek 
109*85723df0SDavid van Moolenbroek 	assert(iov != NULL);
110*85723df0SDavid van Moolenbroek 	assert(iovcnt <= __arraycount(vec));
111*85723df0SDavid van Moolenbroek 
112*85723df0SDavid van Moolenbroek 	/* We allow zero-element vectors, because we are nice. */
113*85723df0SDavid van Moolenbroek 	if (iovcnt == 0)
114*85723df0SDavid van Moolenbroek 		return OK;
115*85723df0SDavid van Moolenbroek 
116*85723df0SDavid van Moolenbroek 	/*
117*85723df0SDavid van Moolenbroek 	 * Do not use a vector copy operation for single-element copies, as
118*85723df0SDavid van Moolenbroek 	 * this saves the kernel from having to copy in the vector itself.
119*85723df0SDavid van Moolenbroek 	 */
120*85723df0SDavid van Moolenbroek 	if (iovcnt == 1) {
121*85723df0SDavid van Moolenbroek 		if (copyin)
122*85723df0SDavid van Moolenbroek 			return sockdriver_copyin(data, off,
123*85723df0SDavid van Moolenbroek 			    (void *)iov->iov_addr, iov->iov_size);
124*85723df0SDavid van Moolenbroek 		else
125*85723df0SDavid van Moolenbroek 			return sockdriver_copyout(data, off,
126*85723df0SDavid van Moolenbroek 			    (const void *)iov->iov_addr, iov->iov_size);
127*85723df0SDavid van Moolenbroek 	}
128*85723df0SDavid van Moolenbroek 
129*85723df0SDavid van Moolenbroek 	assert(data != NULL);
130*85723df0SDavid van Moolenbroek 	assert(data->_sd_endpt != SELF);
131*85723df0SDavid van Moolenbroek 	assert(GRANT_VALID(data->_sd_grant));
132*85723df0SDavid van Moolenbroek 
133*85723df0SDavid van Moolenbroek 	for (i = 0; i < iovcnt; i++, iov++) {
134*85723df0SDavid van Moolenbroek 		if (copyin) {
135*85723df0SDavid van Moolenbroek 			vec[i].v_from = data->_sd_endpt;
136*85723df0SDavid van Moolenbroek 			vec[i].v_to = SELF;
137*85723df0SDavid van Moolenbroek 		} else {
138*85723df0SDavid van Moolenbroek 			vec[i].v_from = SELF;
139*85723df0SDavid van Moolenbroek 			vec[i].v_to = data->_sd_endpt;
140*85723df0SDavid van Moolenbroek 		}
141*85723df0SDavid van Moolenbroek 		vec[i].v_gid = data->_sd_grant;
142*85723df0SDavid van Moolenbroek 		vec[i].v_offset = off;
143*85723df0SDavid van Moolenbroek 		vec[i].v_addr = iov->iov_addr;
144*85723df0SDavid van Moolenbroek 		vec[i].v_bytes = iov->iov_size;
145*85723df0SDavid van Moolenbroek 
146*85723df0SDavid van Moolenbroek 		off += iov->iov_size;
147*85723df0SDavid van Moolenbroek 	}
148*85723df0SDavid van Moolenbroek 
149*85723df0SDavid van Moolenbroek 	assert(off <= data->_sd_len);
150*85723df0SDavid van Moolenbroek 
151*85723df0SDavid van Moolenbroek 	return sys_vsafecopy(vec, iovcnt);
152*85723df0SDavid van Moolenbroek }
153*85723df0SDavid van Moolenbroek 
154*85723df0SDavid van Moolenbroek /*
155*85723df0SDavid van Moolenbroek  * Copy data from the caller into the local address space, using a vector of
156*85723df0SDavid van Moolenbroek  * buffers.  Return OK or a negative error code.
157*85723df0SDavid van Moolenbroek  */
158*85723df0SDavid van Moolenbroek int
sockdriver_vcopyin(const struct sockdriver_data * __restrict data,size_t off,const iovec_t * __restrict iov,unsigned int iovcnt)159*85723df0SDavid van Moolenbroek sockdriver_vcopyin(const struct sockdriver_data * __restrict data, size_t off,
160*85723df0SDavid van Moolenbroek 	const iovec_t * __restrict iov, unsigned int iovcnt)
161*85723df0SDavid van Moolenbroek {
162*85723df0SDavid van Moolenbroek 
163*85723df0SDavid van Moolenbroek 	return sockdriver_vcopy(data, off, iov, iovcnt, TRUE /*copyin*/);
164*85723df0SDavid van Moolenbroek }
165*85723df0SDavid van Moolenbroek 
166*85723df0SDavid van Moolenbroek /*
167*85723df0SDavid van Moolenbroek  * Copy data from the local address space to the caller, using a vector of
168*85723df0SDavid van Moolenbroek  * buffers.  Return OK or a negative error code.
169*85723df0SDavid van Moolenbroek  */
170*85723df0SDavid van Moolenbroek int
sockdriver_vcopyout(const struct sockdriver_data * __restrict data,size_t off,const iovec_t * __restrict iov,unsigned int iovcnt)171*85723df0SDavid van Moolenbroek sockdriver_vcopyout(const struct sockdriver_data * __restrict data, size_t off,
172*85723df0SDavid van Moolenbroek 	const iovec_t * __restrict iov, unsigned int iovcnt)
173*85723df0SDavid van Moolenbroek {
174*85723df0SDavid van Moolenbroek 
175*85723df0SDavid van Moolenbroek 	return sockdriver_vcopy(data, off, iov, iovcnt, FALSE /*copyin*/);
176*85723df0SDavid van Moolenbroek }
177*85723df0SDavid van Moolenbroek 
178*85723df0SDavid van Moolenbroek /*
179*85723df0SDavid van Moolenbroek  * Copy data from the caller into the local address space, using socket option
180*85723df0SDavid van Moolenbroek  * semantics: fail the call with EINVAL if the given 'optlen' is not equal to
181*85723df0SDavid van Moolenbroek  * the given 'len'.  Return OK or a negative error code.
182*85723df0SDavid van Moolenbroek  */
183*85723df0SDavid van Moolenbroek int
sockdriver_copyin_opt(const struct sockdriver_data * __restrict data,void * __restrict ptr,size_t len,socklen_t optlen)184*85723df0SDavid van Moolenbroek sockdriver_copyin_opt(const struct sockdriver_data * __restrict data,
185*85723df0SDavid van Moolenbroek 	void * __restrict ptr, size_t len, socklen_t optlen)
186*85723df0SDavid van Moolenbroek {
187*85723df0SDavid van Moolenbroek 
188*85723df0SDavid van Moolenbroek 	if (len != optlen)
189*85723df0SDavid van Moolenbroek 		return EINVAL;
190*85723df0SDavid van Moolenbroek 	else
191*85723df0SDavid van Moolenbroek 		return sockdriver_copyin(data, 0, ptr, len);
192*85723df0SDavid van Moolenbroek }
193*85723df0SDavid van Moolenbroek 
194*85723df0SDavid van Moolenbroek /*
195*85723df0SDavid van Moolenbroek  * Copy data from the local address space to the caller, using socket option
196*85723df0SDavid van Moolenbroek  * semantics: limit the size of the copied-out data to the size pointed to by
197*85723df0SDavid van Moolenbroek  * 'optlen', and return the possibly truncated size in 'optlen' on success.
198*85723df0SDavid van Moolenbroek  * Return OK or a negative error code.
199*85723df0SDavid van Moolenbroek  */
200*85723df0SDavid van Moolenbroek int
sockdriver_copyout_opt(const struct sockdriver_data * __restrict data,const void * __restrict ptr,size_t len,socklen_t * __restrict optlen)201*85723df0SDavid van Moolenbroek sockdriver_copyout_opt(const struct sockdriver_data * __restrict data,
202*85723df0SDavid van Moolenbroek 	const void * __restrict ptr, size_t len, socklen_t * __restrict optlen)
203*85723df0SDavid van Moolenbroek {
204*85723df0SDavid van Moolenbroek 	int r;
205*85723df0SDavid van Moolenbroek 
206*85723df0SDavid van Moolenbroek 	if (len > *optlen)
207*85723df0SDavid van Moolenbroek 		len = *optlen;
208*85723df0SDavid van Moolenbroek 
209*85723df0SDavid van Moolenbroek 	if ((r = sockdriver_copyout(data, 0, ptr, len)) == OK)
210*85723df0SDavid van Moolenbroek 		*optlen = len;
211*85723df0SDavid van Moolenbroek 
212*85723df0SDavid van Moolenbroek 	return r;
213*85723df0SDavid van Moolenbroek }
214*85723df0SDavid van Moolenbroek 
215*85723df0SDavid van Moolenbroek /*
216*85723df0SDavid van Moolenbroek  * Compress a sockdriver_data structure to a smaller variant that stores only
217*85723df0SDavid van Moolenbroek  * the fields that are not already stored redundantly in/as the given 'call'
218*85723df0SDavid van Moolenbroek  * and 'len' parameters.  The typical use case here this call suspension.  In
219*85723df0SDavid van Moolenbroek  * that case, the caller will already store 'call' and 'len' as is, and can
220*85723df0SDavid van Moolenbroek  * save memory by storing a packed version of 'data' rather than that structure
221*85723df0SDavid van Moolenbroek  * itself.  Return OK on success, with 'pack' containing a compressed version
222*85723df0SDavid van Moolenbroek  * of 'data'.  Return EINVAL if the given parameters do not match; this would
223*85723df0SDavid van Moolenbroek  * typically be a sign that the calling application messed up badly.
224*85723df0SDavid van Moolenbroek  */
225*85723df0SDavid van Moolenbroek int
sockdriver_pack_data(struct sockdriver_packed_data * pack,const struct sockdriver_call * call,const struct sockdriver_data * data,size_t len)226*85723df0SDavid van Moolenbroek sockdriver_pack_data(struct sockdriver_packed_data * pack,
227*85723df0SDavid van Moolenbroek 	const struct sockdriver_call * call,
228*85723df0SDavid van Moolenbroek 	const struct sockdriver_data * data, size_t len)
229*85723df0SDavid van Moolenbroek {
230*85723df0SDavid van Moolenbroek 
231*85723df0SDavid van Moolenbroek 	if (data->_sd_endpt != call->sc_endpt)
232*85723df0SDavid van Moolenbroek 		return EINVAL;
233*85723df0SDavid van Moolenbroek 	if (data->_sd_len != len)
234*85723df0SDavid van Moolenbroek 		return EINVAL;
235*85723df0SDavid van Moolenbroek 
236*85723df0SDavid van Moolenbroek 	pack->_spd_grant = data->_sd_grant;
237*85723df0SDavid van Moolenbroek 	return OK;
238*85723df0SDavid van Moolenbroek }
239*85723df0SDavid van Moolenbroek 
240*85723df0SDavid van Moolenbroek /*
241*85723df0SDavid van Moolenbroek  * Decompress a previously packed sockdriver data structure into a full
242*85723df0SDavid van Moolenbroek  * sockdriver_data structure, with the help of the given 'call' and 'len'
243*85723df0SDavid van Moolenbroek  * parameters.  Return the unpacked version of 'pack' in 'data'.  This function
244*85723df0SDavid van Moolenbroek  * always succeeds.
245*85723df0SDavid van Moolenbroek  */
246*85723df0SDavid van Moolenbroek void
sockdriver_unpack_data(struct sockdriver_data * data,const struct sockdriver_call * call,const struct sockdriver_packed_data * pack,size_t len)247*85723df0SDavid van Moolenbroek sockdriver_unpack_data(struct sockdriver_data * data,
248*85723df0SDavid van Moolenbroek 	const struct sockdriver_call * call,
249*85723df0SDavid van Moolenbroek 	const struct sockdriver_packed_data * pack, size_t len)
250*85723df0SDavid van Moolenbroek {
251*85723df0SDavid van Moolenbroek 
252*85723df0SDavid van Moolenbroek 	data->_sd_endpt = call->sc_endpt;
253*85723df0SDavid van Moolenbroek 	data->_sd_grant = pack->_spd_grant;
254*85723df0SDavid van Moolenbroek 	data->_sd_len = len;
255*85723df0SDavid van Moolenbroek }
256*85723df0SDavid van Moolenbroek 
257*85723df0SDavid van Moolenbroek /*
258*85723df0SDavid van Moolenbroek  * Send a reply to a request.
259*85723df0SDavid van Moolenbroek  */
260*85723df0SDavid van Moolenbroek static void
send_reply(endpoint_t endpt,int type,message * m_ptr)261*85723df0SDavid van Moolenbroek send_reply(endpoint_t endpt, int type, message * m_ptr)
262*85723df0SDavid van Moolenbroek {
263*85723df0SDavid van Moolenbroek 	int r;
264*85723df0SDavid van Moolenbroek 
265*85723df0SDavid van Moolenbroek 	m_ptr->m_type = type;
266*85723df0SDavid van Moolenbroek 
267*85723df0SDavid van Moolenbroek 	if ((r = asynsend(endpt, m_ptr)) != OK)
268*85723df0SDavid van Moolenbroek 		printf("sockdriver: sending reply to %d failed (%d)\n",
269*85723df0SDavid van Moolenbroek 		    endpt, r);
270*85723df0SDavid van Moolenbroek }
271*85723df0SDavid van Moolenbroek 
272*85723df0SDavid van Moolenbroek /*
273*85723df0SDavid van Moolenbroek  * Send a reply which takes only a result code and no additional reply fields.
274*85723df0SDavid van Moolenbroek  */
275*85723df0SDavid van Moolenbroek static void
send_generic_reply(endpoint_t endpt,sockreq_t req,int reply)276*85723df0SDavid van Moolenbroek send_generic_reply(endpoint_t endpt, sockreq_t req, int reply)
277*85723df0SDavid van Moolenbroek {
278*85723df0SDavid van Moolenbroek 	message m;
279*85723df0SDavid van Moolenbroek 
280*85723df0SDavid van Moolenbroek 	assert(reply != SUSPEND && reply != EDONTREPLY);
281*85723df0SDavid van Moolenbroek 
282*85723df0SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
283*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_reply.req_id = req;
284*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_reply.status = reply;
285*85723df0SDavid van Moolenbroek 
286*85723df0SDavid van Moolenbroek 	send_reply(endpt, SDEV_REPLY, &m);
287*85723df0SDavid van Moolenbroek }
288*85723df0SDavid van Moolenbroek 
289*85723df0SDavid van Moolenbroek /*
290*85723df0SDavid van Moolenbroek  * Send a reply to an earlier suspended request which takes only a result code
291*85723df0SDavid van Moolenbroek  * and no additional reply fields.
292*85723df0SDavid van Moolenbroek  */
293*85723df0SDavid van Moolenbroek void
sockdriver_reply_generic(const struct sockdriver_call * call,int reply)294*85723df0SDavid van Moolenbroek sockdriver_reply_generic(const struct sockdriver_call * call, int reply)
295*85723df0SDavid van Moolenbroek {
296*85723df0SDavid van Moolenbroek 
297*85723df0SDavid van Moolenbroek 	send_generic_reply(call->sc_endpt, call->sc_req, reply);
298*85723df0SDavid van Moolenbroek }
299*85723df0SDavid van Moolenbroek 
300*85723df0SDavid van Moolenbroek /*
301*85723df0SDavid van Moolenbroek  * Send a reply to a socket or a socketpair request.  Since these calls may not
302*85723df0SDavid van Moolenbroek  * be suspended, this function is used internally only.
303*85723df0SDavid van Moolenbroek  */
304*85723df0SDavid van Moolenbroek static void
send_socket_reply(endpoint_t endpt,sockreq_t req,sockid_t reply,sockid_t reply2)305*85723df0SDavid van Moolenbroek send_socket_reply(endpoint_t endpt, sockreq_t req, sockid_t reply,
306*85723df0SDavid van Moolenbroek 	sockid_t reply2)
307*85723df0SDavid van Moolenbroek {
308*85723df0SDavid van Moolenbroek 	message m;
309*85723df0SDavid van Moolenbroek 
310*85723df0SDavid van Moolenbroek 	assert(reply != SUSPEND && reply != EDONTREPLY);
311*85723df0SDavid van Moolenbroek 
312*85723df0SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
313*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_socket_reply.req_id = req;
314*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_socket_reply.sock_id = reply;
315*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_socket_reply.sock_id2 = reply2;
316*85723df0SDavid van Moolenbroek 
317*85723df0SDavid van Moolenbroek 	send_reply(endpt, SDEV_SOCKET_REPLY, &m);
318*85723df0SDavid van Moolenbroek }
319*85723df0SDavid van Moolenbroek 
320*85723df0SDavid van Moolenbroek /*
321*85723df0SDavid van Moolenbroek  * Send a reply to an earlier suspended accept request.  The given reply is
322*85723df0SDavid van Moolenbroek  * either a socket identifier (>= 0) or an error code (< 0).  On success, an
323*85723df0SDavid van Moolenbroek  * address must be given as 'addr', and its nonzero length must be given as
324*85723df0SDavid van Moolenbroek  * 'addr_len'.
325*85723df0SDavid van Moolenbroek  */
326*85723df0SDavid van Moolenbroek void
sockdriver_reply_accept(const struct sockdriver_call * __restrict call,sockid_t reply,struct sockaddr * __restrict addr,socklen_t addr_len)327*85723df0SDavid van Moolenbroek sockdriver_reply_accept(const struct sockdriver_call * __restrict call,
328*85723df0SDavid van Moolenbroek 	sockid_t reply, struct sockaddr * __restrict addr, socklen_t addr_len)
329*85723df0SDavid van Moolenbroek {
330*85723df0SDavid van Moolenbroek 	sockid_t id;
331*85723df0SDavid van Moolenbroek 	message m;
332*85723df0SDavid van Moolenbroek 
333*85723df0SDavid van Moolenbroek 	assert(reply != SUSPEND && reply != EDONTREPLY);
334*85723df0SDavid van Moolenbroek 
335*85723df0SDavid van Moolenbroek 	/*
336*85723df0SDavid van Moolenbroek 	 * If the accept was successful, copy out the address, if requested.
337*85723df0SDavid van Moolenbroek 	 * If the copy fails, send both a valid socket ID and an error to VFS.
338*85723df0SDavid van Moolenbroek 	 * VFS will then close the newly created socket immediately, and return
339*85723df0SDavid van Moolenbroek 	 * the error to the caller.
340*85723df0SDavid van Moolenbroek 	 *
341*85723df0SDavid van Moolenbroek 	 * While not particularly nice, the general behavior of closing the
342*85723df0SDavid van Moolenbroek 	 * socket after accepting it seems to be common among other OSes for
343*85723df0SDavid van Moolenbroek 	 * address copy errors.  Most importantly, it frees the socket driver
344*85723df0SDavid van Moolenbroek 	 * from having to deal with address copy errors itself.
345*85723df0SDavid van Moolenbroek 	 *
346*85723df0SDavid van Moolenbroek 	 * Letting VFS close the socket is also not all that great.  However,
347*85723df0SDavid van Moolenbroek 	 * it is the lesser evil compared to the two main alternatives: 1)
348*85723df0SDavid van Moolenbroek 	 * immediately calling sdr_close() from here, which would seriously
349*85723df0SDavid van Moolenbroek 	 * complicate writing socket drivers due to sockets disappearing from
350*85723df0SDavid van Moolenbroek 	 * under it, so to speak, and 2) queuing a forged incoming SDEV_CLOSE
351*85723df0SDavid van Moolenbroek 	 * request, for which we do not have the necessary infrastructure.
352*85723df0SDavid van Moolenbroek 	 * Additionally, VFS may close the newly accepted socket when out of
353*85723df0SDavid van Moolenbroek 	 * other required resources anyway, so logically this fits in well.
354*85723df0SDavid van Moolenbroek 	 * The only real price to pay is a slightly uglier message protocol.
355*85723df0SDavid van Moolenbroek 	 *
356*85723df0SDavid van Moolenbroek 	 * Copying out the address *length* is not our responsibility at all;
357*85723df0SDavid van Moolenbroek 	 * if VFS chooses to do this itself (as opposed to letting libc do it),
358*85723df0SDavid van Moolenbroek 	 * it too will have to close the socket on failure, using a separate
359*85723df0SDavid van Moolenbroek 	 * close call.  This is always multithreading-safe because userland can
360*85723df0SDavid van Moolenbroek 	 * not access the accepted socket yet anyway.
361*85723df0SDavid van Moolenbroek 	 */
362*85723df0SDavid van Moolenbroek 	if (reply >= 0) {
363*85723df0SDavid van Moolenbroek 		id = reply;
364*85723df0SDavid van Moolenbroek 		reply = OK;
365*85723df0SDavid van Moolenbroek 	} else
366*85723df0SDavid van Moolenbroek 		id = -1;
367*85723df0SDavid van Moolenbroek 
368*85723df0SDavid van Moolenbroek 	if (reply == OK && GRANT_VALID(call->_sc_grant)) {
369*85723df0SDavid van Moolenbroek 		if (addr == NULL || addr_len == 0)
370*85723df0SDavid van Moolenbroek 			panic("libsockdriver: success but no address given");
371*85723df0SDavid van Moolenbroek 
372*85723df0SDavid van Moolenbroek 		if (addr_len > call->_sc_len)
373*85723df0SDavid van Moolenbroek 			addr_len = call->_sc_len; /* truncate addr and len */
374*85723df0SDavid van Moolenbroek 
375*85723df0SDavid van Moolenbroek 		if (addr_len > 0) {
376*85723df0SDavid van Moolenbroek 			reply = sys_safecopyto(call->sc_endpt, call->_sc_grant,
377*85723df0SDavid van Moolenbroek 			    0, (vir_bytes)addr, addr_len);
378*85723df0SDavid van Moolenbroek 
379*85723df0SDavid van Moolenbroek 			/* Intentionally leave 'id' set on failure here. */
380*85723df0SDavid van Moolenbroek 		}
381*85723df0SDavid van Moolenbroek 	} else
382*85723df0SDavid van Moolenbroek 		addr_len = 0;	/* not needed, but cleaner */
383*85723df0SDavid van Moolenbroek 
384*85723df0SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
385*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_accept_reply.req_id = call->sc_req;
386*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_accept_reply.sock_id = id;
387*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_accept_reply.status = reply;
388*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_accept_reply.len = addr_len;
389*85723df0SDavid van Moolenbroek 
390*85723df0SDavid van Moolenbroek 	send_reply(call->sc_endpt, SDEV_ACCEPT_REPLY, &m);
391*85723df0SDavid van Moolenbroek }
392*85723df0SDavid van Moolenbroek 
393*85723df0SDavid van Moolenbroek /*
394*85723df0SDavid van Moolenbroek  * Send a reply to an earlier suspended receive call.  The given reply code is
395*85723df0SDavid van Moolenbroek  * the number of regular data bytes received (>= 0) or an error code (< 0).
396*85723df0SDavid van Moolenbroek  * On success, for connectionless sockets, 'addr' must point to the source
397*85723df0SDavid van Moolenbroek  * address and 'addr_len' must contain the address length; for connection-
398*85723df0SDavid van Moolenbroek  * oriented sockets, 'addr_len' must be zero, in which case 'addr' is ignored.
399*85723df0SDavid van Moolenbroek  */
400*85723df0SDavid van Moolenbroek void
sockdriver_reply_recv(const struct sockdriver_call * __restrict call,int reply,socklen_t ctl_len,struct sockaddr * __restrict addr,socklen_t addr_len,int flags)401*85723df0SDavid van Moolenbroek sockdriver_reply_recv(const struct sockdriver_call * __restrict call,
402*85723df0SDavid van Moolenbroek 	int reply, socklen_t ctl_len, struct sockaddr * __restrict addr,
403*85723df0SDavid van Moolenbroek 	socklen_t addr_len, int flags)
404*85723df0SDavid van Moolenbroek {
405*85723df0SDavid van Moolenbroek 	message m;
406*85723df0SDavid van Moolenbroek 	int r;
407*85723df0SDavid van Moolenbroek 
408*85723df0SDavid van Moolenbroek 	assert(reply != SUSPEND && reply != EDONTREPLY);
409*85723df0SDavid van Moolenbroek 
410*85723df0SDavid van Moolenbroek 	/*
411*85723df0SDavid van Moolenbroek 	 * If applicable, copy out the address.  If this fails, the result is
412*85723df0SDavid van Moolenbroek 	 * loss of the data received; in the case of AF_UNIX, this may include
413*85723df0SDavid van Moolenbroek 	 * references to file descriptors already created in the receiving
414*85723df0SDavid van Moolenbroek 	 * process.  At least Linux and NetBSD behave this way as well, which
415*85723df0SDavid van Moolenbroek 	 * is not an excuse to be lazy, but we need to change just about
416*85723df0SDavid van Moolenbroek 	 * everything for the worse (including having additional grants just
417*85723df0SDavid van Moolenbroek 	 * for storing lengths) in order to fully solve this corner case.
418*85723df0SDavid van Moolenbroek 	 *
419*85723df0SDavid van Moolenbroek 	 * TODO: a reasonable compromise might be to add a callback routine for
420*85723df0SDavid van Moolenbroek 	 * closing file descriptors in any already-written control data.  This
421*85723df0SDavid van Moolenbroek 	 * would solve the worst aspect of the data loss, not the loss itself.
422*85723df0SDavid van Moolenbroek 	 */
423*85723df0SDavid van Moolenbroek 	if (reply >= 0 && addr_len > 0 && GRANT_VALID(call->_sc_grant)) {
424*85723df0SDavid van Moolenbroek 		if (addr == NULL)
425*85723df0SDavid van Moolenbroek 			panic("libsockdriver: success but no address given");
426*85723df0SDavid van Moolenbroek 
427*85723df0SDavid van Moolenbroek 		if (addr_len > call->_sc_len)
428*85723df0SDavid van Moolenbroek 			addr_len = call->_sc_len; /* truncate addr and len */
429*85723df0SDavid van Moolenbroek 
430*85723df0SDavid van Moolenbroek 		if (addr_len > 0 && (r = sys_safecopyto(call->sc_endpt,
431*85723df0SDavid van Moolenbroek 		    call->_sc_grant, 0, (vir_bytes)addr, addr_len)) != OK)
432*85723df0SDavid van Moolenbroek 			reply = r;
433*85723df0SDavid van Moolenbroek 	} else
434*85723df0SDavid van Moolenbroek 		addr_len = 0;
435*85723df0SDavid van Moolenbroek 
436*85723df0SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
437*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_recv_reply.req_id = call->sc_req;
438*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_recv_reply.status = reply;
439*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_recv_reply.ctl_len = ctl_len;
440*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_recv_reply.addr_len = addr_len;
441*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_recv_reply.flags = flags;
442*85723df0SDavid van Moolenbroek 
443*85723df0SDavid van Moolenbroek 	send_reply(call->sc_endpt, SDEV_RECV_REPLY, &m);
444*85723df0SDavid van Moolenbroek }
445*85723df0SDavid van Moolenbroek 
446*85723df0SDavid van Moolenbroek /*
447*85723df0SDavid van Moolenbroek  * Send a reply to a select request.
448*85723df0SDavid van Moolenbroek  */
449*85723df0SDavid van Moolenbroek static void
send_select_reply(const struct sockdriver_select * sel,int type,sockid_t id,int ops)450*85723df0SDavid van Moolenbroek send_select_reply(const struct sockdriver_select * sel, int type, sockid_t id,
451*85723df0SDavid van Moolenbroek 	int ops)
452*85723df0SDavid van Moolenbroek {
453*85723df0SDavid van Moolenbroek 	message m;
454*85723df0SDavid van Moolenbroek 
455*85723df0SDavid van Moolenbroek 	assert(ops != SUSPEND && ops != EDONTREPLY);
456*85723df0SDavid van Moolenbroek 
457*85723df0SDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
458*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_select_reply.sock_id = id;
459*85723df0SDavid van Moolenbroek 	m.m_lsockdriver_vfs_select_reply.status = ops;
460*85723df0SDavid van Moolenbroek 
461*85723df0SDavid van Moolenbroek 	send_reply(sel->ss_endpt, type, &m);
462*85723df0SDavid van Moolenbroek }
463*85723df0SDavid van Moolenbroek 
464*85723df0SDavid van Moolenbroek /*
465*85723df0SDavid van Moolenbroek  * Send a reply to an earlier select call that requested notifications.
466*85723df0SDavid van Moolenbroek  */
467*85723df0SDavid van Moolenbroek void
sockdriver_reply_select(const struct sockdriver_select * sel,sockid_t id,int ops)468*85723df0SDavid van Moolenbroek sockdriver_reply_select(const struct sockdriver_select * sel, sockid_t id,
469*85723df0SDavid van Moolenbroek 	int ops)
470*85723df0SDavid van Moolenbroek {
471*85723df0SDavid van Moolenbroek 
472*85723df0SDavid van Moolenbroek 	send_select_reply(sel, SDEV_SELECT2_REPLY, id, ops);
473*85723df0SDavid van Moolenbroek }
474*85723df0SDavid van Moolenbroek 
475*85723df0SDavid van Moolenbroek /*
476*85723df0SDavid van Moolenbroek  * Create a new socket.  This call may not be suspended.
477*85723df0SDavid van Moolenbroek  */
478*85723df0SDavid van Moolenbroek static void
do_socket(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)479*85723df0SDavid van Moolenbroek do_socket(const struct sockdriver * __restrict sdp,
480*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
481*85723df0SDavid van Moolenbroek {
482*85723df0SDavid van Moolenbroek 	sockid_t r;
483*85723df0SDavid van Moolenbroek 
484*85723df0SDavid van Moolenbroek 	if (sdp->sdr_socket != NULL)
485*85723df0SDavid van Moolenbroek 		r = sdp->sdr_socket(m_ptr->m_vfs_lsockdriver_socket.domain,
486*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.type,
487*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.protocol,
488*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.user_endpt);
489*85723df0SDavid van Moolenbroek 	else
490*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
491*85723df0SDavid van Moolenbroek 
492*85723df0SDavid van Moolenbroek 	send_socket_reply(m_ptr->m_source,
493*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_socket.req_id, r, -1);
494*85723df0SDavid van Moolenbroek }
495*85723df0SDavid van Moolenbroek 
496*85723df0SDavid van Moolenbroek /*
497*85723df0SDavid van Moolenbroek  * Create a pair of connected sockets.  Relevant for UNIX domain sockets only.
498*85723df0SDavid van Moolenbroek  * This call may not be suspended.
499*85723df0SDavid van Moolenbroek  */
500*85723df0SDavid van Moolenbroek static void
do_socketpair(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)501*85723df0SDavid van Moolenbroek do_socketpair(const struct sockdriver * __restrict sdp,
502*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
503*85723df0SDavid van Moolenbroek {
504*85723df0SDavid van Moolenbroek 	sockid_t sockid[2];
505*85723df0SDavid van Moolenbroek 	int r;
506*85723df0SDavid van Moolenbroek 
507*85723df0SDavid van Moolenbroek 	if (sdp->sdr_socketpair != NULL)
508*85723df0SDavid van Moolenbroek 		r = sdp->sdr_socketpair(m_ptr->m_vfs_lsockdriver_socket.domain,
509*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.type,
510*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.protocol,
511*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_socket.user_endpt, sockid);
512*85723df0SDavid van Moolenbroek 	else
513*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
514*85723df0SDavid van Moolenbroek 
515*85723df0SDavid van Moolenbroek 	if (r != OK) {
516*85723df0SDavid van Moolenbroek 		sockid[0] = r;
517*85723df0SDavid van Moolenbroek 		sockid[1] = -1;
518*85723df0SDavid van Moolenbroek 	}
519*85723df0SDavid van Moolenbroek 
520*85723df0SDavid van Moolenbroek 	send_socket_reply(m_ptr->m_source,
521*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_socket.req_id, sockid[0], sockid[1]);
522*85723df0SDavid van Moolenbroek }
523*85723df0SDavid van Moolenbroek 
524*85723df0SDavid van Moolenbroek /*
525*85723df0SDavid van Moolenbroek  * Bind a socket to a local address, or connect a socket to a remote address.
526*85723df0SDavid van Moolenbroek  * In both cases, this call may be suspended by the socket driver, in which
527*85723df0SDavid van Moolenbroek  * case sockdriver_reply_generic() must be used to reply later.
528*85723df0SDavid van Moolenbroek  *
529*85723df0SDavid van Moolenbroek  * For bind(2), POSIX is not entirely consistent regarding call suspension: the
530*85723df0SDavid van Moolenbroek  * bind(2) call may return EINPROGRESS for nonblocking sockets, but this also
531*85723df0SDavid van Moolenbroek  * suggests that blocking bind(2) calls may be interrupted by signals (as on
532*85723df0SDavid van Moolenbroek  * MINIX3 they can be), yet EINTR is not defined as a valid return code for it.
533*85723df0SDavid van Moolenbroek  */
534*85723df0SDavid van Moolenbroek static void
do_bind_connect(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)535*85723df0SDavid van Moolenbroek do_bind_connect(const struct sockdriver * __restrict sdp,
536*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
537*85723df0SDavid van Moolenbroek {
538*85723df0SDavid van Moolenbroek 	int (*proc)(sockid_t, const struct sockaddr * __restrict, socklen_t,
539*85723df0SDavid van Moolenbroek 	    endpoint_t, const struct sockdriver_call * __restrict);
540*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
541*85723df0SDavid van Moolenbroek 	char buf[SOCKADDR_MAX];
542*85723df0SDavid van Moolenbroek 	sockid_t id;
543*85723df0SDavid van Moolenbroek 	cp_grant_id_t grant;
544*85723df0SDavid van Moolenbroek 	socklen_t len;
545*85723df0SDavid van Moolenbroek 	endpoint_t user_endpt;
546*85723df0SDavid van Moolenbroek 	int r, sflags;
547*85723df0SDavid van Moolenbroek 
548*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
549*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_addr.req_id;
550*85723df0SDavid van Moolenbroek 
551*85723df0SDavid van Moolenbroek 	id = m_ptr->m_vfs_lsockdriver_addr.sock_id;
552*85723df0SDavid van Moolenbroek 	grant = m_ptr->m_vfs_lsockdriver_addr.grant;
553*85723df0SDavid van Moolenbroek 	len = m_ptr->m_vfs_lsockdriver_addr.len;
554*85723df0SDavid van Moolenbroek 	user_endpt = m_ptr->m_vfs_lsockdriver_addr.user_endpt;
555*85723df0SDavid van Moolenbroek 	sflags = m_ptr->m_vfs_lsockdriver_addr.sflags;
556*85723df0SDavid van Moolenbroek 
557*85723df0SDavid van Moolenbroek 	switch (m_ptr->m_type) {
558*85723df0SDavid van Moolenbroek 	case SDEV_BIND:		proc = sdp->sdr_bind;		break;
559*85723df0SDavid van Moolenbroek 	case SDEV_CONNECT:	proc = sdp->sdr_connect;	break;
560*85723df0SDavid van Moolenbroek 	default:		panic("expected bind or connect");
561*85723df0SDavid van Moolenbroek 	}
562*85723df0SDavid van Moolenbroek 
563*85723df0SDavid van Moolenbroek 	r = OK;
564*85723df0SDavid van Moolenbroek 	if (!GRANT_VALID(grant) || len == 0 || len > sizeof(buf))
565*85723df0SDavid van Moolenbroek 		r = EINVAL;
566*85723df0SDavid van Moolenbroek 	else
567*85723df0SDavid van Moolenbroek 		r = sys_safecopyfrom(m_ptr->m_source, grant, 0, (vir_bytes)buf,
568*85723df0SDavid van Moolenbroek 		    len);
569*85723df0SDavid van Moolenbroek 
570*85723df0SDavid van Moolenbroek 	if (r == OK) {
571*85723df0SDavid van Moolenbroek 		if (proc != NULL)
572*85723df0SDavid van Moolenbroek 			r = proc(id, (struct sockaddr *)buf, len, user_endpt,
573*85723df0SDavid van Moolenbroek 			    (sflags & SDEV_NONBLOCK) ? NULL : &call);
574*85723df0SDavid van Moolenbroek 		else
575*85723df0SDavid van Moolenbroek 			r = EOPNOTSUPP;
576*85723df0SDavid van Moolenbroek 	}
577*85723df0SDavid van Moolenbroek 
578*85723df0SDavid van Moolenbroek 	assert(!(sflags & SDEV_NONBLOCK) || (r != SUSPEND && r != EDONTREPLY));
579*85723df0SDavid van Moolenbroek 
580*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
581*85723df0SDavid van Moolenbroek 		sockdriver_reply_generic(&call, r);
582*85723df0SDavid van Moolenbroek }
583*85723df0SDavid van Moolenbroek 
584*85723df0SDavid van Moolenbroek /*
585*85723df0SDavid van Moolenbroek  * Put a socket in listening mode.  This call may not be suspended.
586*85723df0SDavid van Moolenbroek  */
587*85723df0SDavid van Moolenbroek static void
do_listen(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)588*85723df0SDavid van Moolenbroek do_listen(const struct sockdriver * __restrict sdp,
589*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
590*85723df0SDavid van Moolenbroek {
591*85723df0SDavid van Moolenbroek 	int r;
592*85723df0SDavid van Moolenbroek 
593*85723df0SDavid van Moolenbroek 	if (sdp->sdr_listen != NULL)
594*85723df0SDavid van Moolenbroek 		r = sdp->sdr_listen(m_ptr->m_vfs_lsockdriver_simple.sock_id,
595*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_simple.param /*backlog*/);
596*85723df0SDavid van Moolenbroek 	else
597*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
598*85723df0SDavid van Moolenbroek 
599*85723df0SDavid van Moolenbroek 	send_generic_reply(m_ptr->m_source,
600*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_simple.req_id, r);
601*85723df0SDavid van Moolenbroek }
602*85723df0SDavid van Moolenbroek 
603*85723df0SDavid van Moolenbroek /*
604*85723df0SDavid van Moolenbroek  * Accept a connection on a listening socket, creating a new socket.
605*85723df0SDavid van Moolenbroek  * This call may be suspended by the socket driver, in which case
606*85723df0SDavid van Moolenbroek  * sockdriver_reply_accept() must be used to reply later.
607*85723df0SDavid van Moolenbroek  */
608*85723df0SDavid van Moolenbroek static void
do_accept(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)609*85723df0SDavid van Moolenbroek do_accept(const struct sockdriver * __restrict sdp,
610*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
611*85723df0SDavid van Moolenbroek {
612*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
613*85723df0SDavid van Moolenbroek 	char buf[SOCKADDR_MAX];
614*85723df0SDavid van Moolenbroek 	struct sockaddr *addr;
615*85723df0SDavid van Moolenbroek 	socklen_t len;
616*85723df0SDavid van Moolenbroek 	endpoint_t user_endpt;
617*85723df0SDavid van Moolenbroek 	int sflags;
618*85723df0SDavid van Moolenbroek 	sockid_t r;
619*85723df0SDavid van Moolenbroek 
620*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
621*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_addr.req_id;
622*85723df0SDavid van Moolenbroek 	call._sc_grant = m_ptr->m_vfs_lsockdriver_addr.grant;
623*85723df0SDavid van Moolenbroek 	call._sc_len = m_ptr->m_vfs_lsockdriver_addr.len;
624*85723df0SDavid van Moolenbroek 
625*85723df0SDavid van Moolenbroek 	addr = (struct sockaddr *)buf;
626*85723df0SDavid van Moolenbroek 	len = 0;
627*85723df0SDavid van Moolenbroek 	user_endpt = m_ptr->m_vfs_lsockdriver_addr.user_endpt;
628*85723df0SDavid van Moolenbroek 	sflags = m_ptr->m_vfs_lsockdriver_addr.sflags;
629*85723df0SDavid van Moolenbroek 
630*85723df0SDavid van Moolenbroek 	if (sdp->sdr_accept != NULL)
631*85723df0SDavid van Moolenbroek 		r = sdp->sdr_accept(m_ptr->m_vfs_lsockdriver_addr.sock_id,
632*85723df0SDavid van Moolenbroek 		    addr, &len, user_endpt,
633*85723df0SDavid van Moolenbroek 		    (sflags & SDEV_NONBLOCK) ? NULL : &call);
634*85723df0SDavid van Moolenbroek 	else
635*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
636*85723df0SDavid van Moolenbroek 
637*85723df0SDavid van Moolenbroek 	assert(!(sflags & SDEV_NONBLOCK) || (r != SUSPEND && r != EDONTREPLY));
638*85723df0SDavid van Moolenbroek 
639*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
640*85723df0SDavid van Moolenbroek 		sockdriver_reply_accept(&call, r, addr, len);
641*85723df0SDavid van Moolenbroek }
642*85723df0SDavid van Moolenbroek 
643*85723df0SDavid van Moolenbroek /*
644*85723df0SDavid van Moolenbroek  * Send regular and/or control data.  This call may be suspended by the socket
645*85723df0SDavid van Moolenbroek  * driver, in which case sockdriver_reply_generic() must be used to reply
646*85723df0SDavid van Moolenbroek  * later.
647*85723df0SDavid van Moolenbroek  */
648*85723df0SDavid van Moolenbroek static void
do_send(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)649*85723df0SDavid van Moolenbroek do_send(const struct sockdriver * __restrict sdp,
650*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
651*85723df0SDavid van Moolenbroek {
652*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
653*85723df0SDavid van Moolenbroek 	struct sockdriver_data data, ctl_data;
654*85723df0SDavid van Moolenbroek 	char buf[SOCKADDR_MAX];
655*85723df0SDavid van Moolenbroek 	struct sockaddr *addr;
656*85723df0SDavid van Moolenbroek 	cp_grant_id_t addr_grant;
657*85723df0SDavid van Moolenbroek 	socklen_t addr_len;
658*85723df0SDavid van Moolenbroek 	endpoint_t user_endpt;
659*85723df0SDavid van Moolenbroek 	sockid_t id;
660*85723df0SDavid van Moolenbroek 	int r, flags;
661*85723df0SDavid van Moolenbroek 
662*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
663*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_sendrecv.req_id;
664*85723df0SDavid van Moolenbroek 
665*85723df0SDavid van Moolenbroek 	data._sd_grant = m_ptr->m_vfs_lsockdriver_sendrecv.data_grant;
666*85723df0SDavid van Moolenbroek 	data._sd_endpt = m_ptr->m_source;
667*85723df0SDavid van Moolenbroek 	data._sd_len = m_ptr->m_vfs_lsockdriver_sendrecv.data_len;
668*85723df0SDavid van Moolenbroek 
669*85723df0SDavid van Moolenbroek 	/* The returned size must fit in an 'int'; truncate accordingly. */
670*85723df0SDavid van Moolenbroek 	if (data._sd_len > INT_MAX)
671*85723df0SDavid van Moolenbroek 		data._sd_len = INT_MAX;
672*85723df0SDavid van Moolenbroek 
673*85723df0SDavid van Moolenbroek 	ctl_data._sd_endpt = m_ptr->m_source;
674*85723df0SDavid van Moolenbroek 	ctl_data._sd_grant = m_ptr->m_vfs_lsockdriver_sendrecv.ctl_grant;
675*85723df0SDavid van Moolenbroek 	ctl_data._sd_len = m_ptr->m_vfs_lsockdriver_sendrecv.ctl_len;
676*85723df0SDavid van Moolenbroek 
677*85723df0SDavid van Moolenbroek 	id = m_ptr->m_vfs_lsockdriver_sendrecv.sock_id;
678*85723df0SDavid van Moolenbroek 	addr_grant = m_ptr->m_vfs_lsockdriver_sendrecv.addr_grant;
679*85723df0SDavid van Moolenbroek 	addr_len = m_ptr->m_vfs_lsockdriver_sendrecv.addr_len;
680*85723df0SDavid van Moolenbroek 	user_endpt = m_ptr->m_vfs_lsockdriver_sendrecv.user_endpt;
681*85723df0SDavid van Moolenbroek 	flags = m_ptr->m_vfs_lsockdriver_sendrecv.flags;
682*85723df0SDavid van Moolenbroek 
683*85723df0SDavid van Moolenbroek 	r = OK;
684*85723df0SDavid van Moolenbroek 	if (GRANT_VALID(addr_grant)) {
685*85723df0SDavid van Moolenbroek 		if (addr_len == 0 || addr_len > sizeof(buf))
686*85723df0SDavid van Moolenbroek 			r = EINVAL;
687*85723df0SDavid van Moolenbroek 		else
688*85723df0SDavid van Moolenbroek 			r = sys_safecopyfrom(m_ptr->m_source, addr_grant, 0,
689*85723df0SDavid van Moolenbroek 			    (vir_bytes)buf, addr_len);
690*85723df0SDavid van Moolenbroek 		addr = (struct sockaddr *)buf;
691*85723df0SDavid van Moolenbroek 	} else {
692*85723df0SDavid van Moolenbroek 		addr = NULL;
693*85723df0SDavid van Moolenbroek 		addr_len = 0;
694*85723df0SDavid van Moolenbroek 	}
695*85723df0SDavid van Moolenbroek 
696*85723df0SDavid van Moolenbroek 	if (r == OK) {
697*85723df0SDavid van Moolenbroek 		if (sdp->sdr_send != NULL)
698*85723df0SDavid van Moolenbroek 			r = sdp->sdr_send(id, &data, data._sd_len, &ctl_data,
699*85723df0SDavid van Moolenbroek 			    ctl_data._sd_len, addr, addr_len, user_endpt,
700*85723df0SDavid van Moolenbroek 			    flags, (flags & MSG_DONTWAIT) ? NULL : &call);
701*85723df0SDavid van Moolenbroek 		else
702*85723df0SDavid van Moolenbroek 			r = EOPNOTSUPP;
703*85723df0SDavid van Moolenbroek 	}
704*85723df0SDavid van Moolenbroek 
705*85723df0SDavid van Moolenbroek 	assert(!(flags & MSG_DONTWAIT) || (r != SUSPEND && r != EDONTREPLY));
706*85723df0SDavid van Moolenbroek 
707*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
708*85723df0SDavid van Moolenbroek 		sockdriver_reply_generic(&call, r);
709*85723df0SDavid van Moolenbroek }
710*85723df0SDavid van Moolenbroek 
711*85723df0SDavid van Moolenbroek /*
712*85723df0SDavid van Moolenbroek  * Receive regular and/or control data.  This call may be suspended by the
713*85723df0SDavid van Moolenbroek  * socket driver, in which case sockdriver_reply_recv() must be used to reply
714*85723df0SDavid van Moolenbroek  * later.
715*85723df0SDavid van Moolenbroek  */
716*85723df0SDavid van Moolenbroek static void
do_recv(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)717*85723df0SDavid van Moolenbroek do_recv(const struct sockdriver * __restrict sdp,
718*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
719*85723df0SDavid van Moolenbroek {
720*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
721*85723df0SDavid van Moolenbroek 	struct sockdriver_data data, ctl_data;
722*85723df0SDavid van Moolenbroek 	char buf[SOCKADDR_MAX];
723*85723df0SDavid van Moolenbroek 	struct sockaddr *addr;
724*85723df0SDavid van Moolenbroek 	sockid_t id;
725*85723df0SDavid van Moolenbroek 	socklen_t ctl_len, addr_len;
726*85723df0SDavid van Moolenbroek 	endpoint_t user_endpt;
727*85723df0SDavid van Moolenbroek 	int r, flags;
728*85723df0SDavid van Moolenbroek 
729*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
730*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_sendrecv.req_id;
731*85723df0SDavid van Moolenbroek 	call._sc_grant = m_ptr->m_vfs_lsockdriver_sendrecv.addr_grant;
732*85723df0SDavid van Moolenbroek 	call._sc_len = m_ptr->m_vfs_lsockdriver_sendrecv.addr_len;
733*85723df0SDavid van Moolenbroek 
734*85723df0SDavid van Moolenbroek 	data._sd_endpt = m_ptr->m_source;
735*85723df0SDavid van Moolenbroek 	data._sd_grant = m_ptr->m_vfs_lsockdriver_sendrecv.data_grant;
736*85723df0SDavid van Moolenbroek 	data._sd_len = m_ptr->m_vfs_lsockdriver_sendrecv.data_len;
737*85723df0SDavid van Moolenbroek 
738*85723df0SDavid van Moolenbroek 	/* The returned size must fit in an 'int'; truncate accordingly. */
739*85723df0SDavid van Moolenbroek 	if (data._sd_len > INT_MAX)
740*85723df0SDavid van Moolenbroek 		data._sd_len = INT_MAX;
741*85723df0SDavid van Moolenbroek 
742*85723df0SDavid van Moolenbroek 	ctl_data._sd_endpt = m_ptr->m_source;
743*85723df0SDavid van Moolenbroek 	ctl_data._sd_grant = m_ptr->m_vfs_lsockdriver_sendrecv.ctl_grant;
744*85723df0SDavid van Moolenbroek 	ctl_data._sd_len = m_ptr->m_vfs_lsockdriver_sendrecv.ctl_len;
745*85723df0SDavid van Moolenbroek 
746*85723df0SDavid van Moolenbroek 	id = m_ptr->m_vfs_lsockdriver_sendrecv.sock_id;
747*85723df0SDavid van Moolenbroek 	ctl_len = ctl_data._sd_len;
748*85723df0SDavid van Moolenbroek 	addr = (struct sockaddr *)buf;
749*85723df0SDavid van Moolenbroek 	addr_len = 0; /* the default: no source address */
750*85723df0SDavid van Moolenbroek 	user_endpt = m_ptr->m_vfs_lsockdriver_sendrecv.user_endpt;
751*85723df0SDavid van Moolenbroek 	flags = m_ptr->m_vfs_lsockdriver_sendrecv.flags;
752*85723df0SDavid van Moolenbroek 
753*85723df0SDavid van Moolenbroek 	if (sdp->sdr_recv != NULL)
754*85723df0SDavid van Moolenbroek 		r = sdp->sdr_recv(id, &data, data._sd_len, &ctl_data, &ctl_len,
755*85723df0SDavid van Moolenbroek 		    addr, &addr_len, user_endpt, &flags,
756*85723df0SDavid van Moolenbroek 		    (flags & MSG_DONTWAIT) ? NULL : &call);
757*85723df0SDavid van Moolenbroek 	else
758*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
759*85723df0SDavid van Moolenbroek 
760*85723df0SDavid van Moolenbroek 	assert(!(flags & MSG_DONTWAIT) || (r != SUSPEND && r != EDONTREPLY));
761*85723df0SDavid van Moolenbroek 
762*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
763*85723df0SDavid van Moolenbroek 		sockdriver_reply_recv(&call, r, ctl_len, addr, addr_len,
764*85723df0SDavid van Moolenbroek 		    flags);
765*85723df0SDavid van Moolenbroek }
766*85723df0SDavid van Moolenbroek 
767*85723df0SDavid van Moolenbroek /*
768*85723df0SDavid van Moolenbroek  * Process an I/O control call.  This call may be suspended by the socket
769*85723df0SDavid van Moolenbroek  * driver, in which case sockdriver_reply_generic() must be used to reply
770*85723df0SDavid van Moolenbroek  * later.
771*85723df0SDavid van Moolenbroek  */
772*85723df0SDavid van Moolenbroek static void
do_ioctl(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)773*85723df0SDavid van Moolenbroek do_ioctl(const struct sockdriver * __restrict sdp,
774*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
775*85723df0SDavid van Moolenbroek {
776*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
777*85723df0SDavid van Moolenbroek 	struct sockdriver_data data;
778*85723df0SDavid van Moolenbroek 	sockid_t id;
779*85723df0SDavid van Moolenbroek 	unsigned long request;
780*85723df0SDavid van Moolenbroek 	endpoint_t user_endpt;
781*85723df0SDavid van Moolenbroek 	int r, sflags;
782*85723df0SDavid van Moolenbroek 
783*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
784*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_ioctl.req_id;
785*85723df0SDavid van Moolenbroek 
786*85723df0SDavid van Moolenbroek 	id = m_ptr->m_vfs_lsockdriver_ioctl.sock_id;
787*85723df0SDavid van Moolenbroek 	request = m_ptr->m_vfs_lsockdriver_ioctl.request;
788*85723df0SDavid van Moolenbroek 	user_endpt = m_ptr->m_vfs_lsockdriver_ioctl.user_endpt;
789*85723df0SDavid van Moolenbroek 	sflags = m_ptr->m_vfs_lsockdriver_ioctl.sflags;
790*85723df0SDavid van Moolenbroek 
791*85723df0SDavid van Moolenbroek 	data._sd_endpt = m_ptr->m_source;
792*85723df0SDavid van Moolenbroek 	data._sd_grant = m_ptr->m_vfs_lsockdriver_ioctl.grant;
793*85723df0SDavid van Moolenbroek 	if (_MINIX_IOCTL_BIG(request))
794*85723df0SDavid van Moolenbroek 		data._sd_len = _MINIX_IOCTL_SIZE_BIG(request);
795*85723df0SDavid van Moolenbroek 	else
796*85723df0SDavid van Moolenbroek 		data._sd_len = _MINIX_IOCTL_SIZE(request);
797*85723df0SDavid van Moolenbroek 
798*85723df0SDavid van Moolenbroek 	if (sdp->sdr_ioctl != NULL)
799*85723df0SDavid van Moolenbroek 		r = sdp->sdr_ioctl(id, request, &data, user_endpt,
800*85723df0SDavid van Moolenbroek 		    (sflags & SDEV_NONBLOCK) ? NULL : &call);
801*85723df0SDavid van Moolenbroek 	else
802*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
803*85723df0SDavid van Moolenbroek 
804*85723df0SDavid van Moolenbroek 	assert(!(sflags & SDEV_NONBLOCK) || (r != SUSPEND && r != EDONTREPLY));
805*85723df0SDavid van Moolenbroek 
806*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
807*85723df0SDavid van Moolenbroek 		sockdriver_reply_generic(&call, r);
808*85723df0SDavid van Moolenbroek }
809*85723df0SDavid van Moolenbroek 
810*85723df0SDavid van Moolenbroek /*
811*85723df0SDavid van Moolenbroek  * Set socket options.  This call may not be suspended.
812*85723df0SDavid van Moolenbroek  */
813*85723df0SDavid van Moolenbroek static void
do_setsockopt(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)814*85723df0SDavid van Moolenbroek do_setsockopt(const struct sockdriver * __restrict sdp,
815*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
816*85723df0SDavid van Moolenbroek {
817*85723df0SDavid van Moolenbroek 	struct sockdriver_data data;
818*85723df0SDavid van Moolenbroek 	int r;
819*85723df0SDavid van Moolenbroek 
820*85723df0SDavid van Moolenbroek 	data._sd_endpt = m_ptr->m_source;
821*85723df0SDavid van Moolenbroek 	data._sd_grant = m_ptr->m_vfs_lsockdriver_getset.grant;
822*85723df0SDavid van Moolenbroek 	data._sd_len = m_ptr->m_vfs_lsockdriver_getset.len;
823*85723df0SDavid van Moolenbroek 
824*85723df0SDavid van Moolenbroek 	if (sdp->sdr_setsockopt != NULL)
825*85723df0SDavid van Moolenbroek 		r = sdp->sdr_setsockopt(
826*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.sock_id,
827*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.level,
828*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.name, &data, data._sd_len);
829*85723df0SDavid van Moolenbroek 	else
830*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
831*85723df0SDavid van Moolenbroek 
832*85723df0SDavid van Moolenbroek 	send_generic_reply(m_ptr->m_source,
833*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_getset.req_id, r);
834*85723df0SDavid van Moolenbroek }
835*85723df0SDavid van Moolenbroek 
836*85723df0SDavid van Moolenbroek /*
837*85723df0SDavid van Moolenbroek  * Retrieve socket options.  This call may not be suspended.
838*85723df0SDavid van Moolenbroek  */
839*85723df0SDavid van Moolenbroek static void
do_getsockopt(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)840*85723df0SDavid van Moolenbroek do_getsockopt(const struct sockdriver * __restrict sdp,
841*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
842*85723df0SDavid van Moolenbroek {
843*85723df0SDavid van Moolenbroek 	struct sockdriver_data data;
844*85723df0SDavid van Moolenbroek 	socklen_t len;
845*85723df0SDavid van Moolenbroek 	int r;
846*85723df0SDavid van Moolenbroek 
847*85723df0SDavid van Moolenbroek 	data._sd_endpt = m_ptr->m_source;
848*85723df0SDavid van Moolenbroek 	data._sd_grant = m_ptr->m_vfs_lsockdriver_getset.grant;
849*85723df0SDavid van Moolenbroek 	data._sd_len = m_ptr->m_vfs_lsockdriver_getset.len;
850*85723df0SDavid van Moolenbroek 
851*85723df0SDavid van Moolenbroek 	len = data._sd_len;
852*85723df0SDavid van Moolenbroek 
853*85723df0SDavid van Moolenbroek 	if (sdp->sdr_setsockopt != NULL)
854*85723df0SDavid van Moolenbroek 		r = sdp->sdr_getsockopt(
855*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.sock_id,
856*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.level,
857*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.name, &data, &len);
858*85723df0SDavid van Moolenbroek 	else
859*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
860*85723df0SDavid van Moolenbroek 
861*85723df0SDavid van Moolenbroek 	/*
862*85723df0SDavid van Moolenbroek 	 * For these requests, the main reply code is used to return the
863*85723df0SDavid van Moolenbroek 	 * resulting data length on success.  The length will never large
864*85723df0SDavid van Moolenbroek 	 * enough to overflow, and we save on API calls and messages this way.
865*85723df0SDavid van Moolenbroek 	 */
866*85723df0SDavid van Moolenbroek 	if (r == OK) {
867*85723df0SDavid van Moolenbroek 		assert(len <= INT_MAX);
868*85723df0SDavid van Moolenbroek 
869*85723df0SDavid van Moolenbroek 		r = (int)len;
870*85723df0SDavid van Moolenbroek 	} else if (r > 0)
871*85723df0SDavid van Moolenbroek 		panic("libsockdriver: invalid reply");
872*85723df0SDavid van Moolenbroek 
873*85723df0SDavid van Moolenbroek 	send_generic_reply(m_ptr->m_source,
874*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_getset.req_id, r);
875*85723df0SDavid van Moolenbroek }
876*85723df0SDavid van Moolenbroek 
877*85723df0SDavid van Moolenbroek /*
878*85723df0SDavid van Moolenbroek  * Get local or remote address.  This call may not be suspended.
879*85723df0SDavid van Moolenbroek  */
880*85723df0SDavid van Moolenbroek static void
do_getname(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)881*85723df0SDavid van Moolenbroek do_getname(const struct sockdriver * __restrict sdp,
882*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
883*85723df0SDavid van Moolenbroek {
884*85723df0SDavid van Moolenbroek 	int (*proc)(sockid_t, struct sockaddr * __restrict,
885*85723df0SDavid van Moolenbroek 	    socklen_t * __restrict);
886*85723df0SDavid van Moolenbroek 	char buf[SOCKADDR_MAX];
887*85723df0SDavid van Moolenbroek 	socklen_t addr_len, len;
888*85723df0SDavid van Moolenbroek 	int r;
889*85723df0SDavid van Moolenbroek 
890*85723df0SDavid van Moolenbroek 	switch (m_ptr->m_type) {
891*85723df0SDavid van Moolenbroek 	case SDEV_GETSOCKNAME:	proc = sdp->sdr_getsockname;	break;
892*85723df0SDavid van Moolenbroek 	case SDEV_GETPEERNAME:	proc = sdp->sdr_getpeername;	break;
893*85723df0SDavid van Moolenbroek 	default:		panic("expected getsockname or getpeername");
894*85723df0SDavid van Moolenbroek 	}
895*85723df0SDavid van Moolenbroek 
896*85723df0SDavid van Moolenbroek 	/* The 'name' and 'level' message fields are unused for these calls. */
897*85723df0SDavid van Moolenbroek 
898*85723df0SDavid van Moolenbroek 	addr_len = m_ptr->m_vfs_lsockdriver_getset.len;
899*85723df0SDavid van Moolenbroek 	len = 0;
900*85723df0SDavid van Moolenbroek 
901*85723df0SDavid van Moolenbroek 	if (proc != NULL)
902*85723df0SDavid van Moolenbroek 		r = proc(m_ptr->m_vfs_lsockdriver_getset.sock_id,
903*85723df0SDavid van Moolenbroek 		    (struct sockaddr *)buf, &len);
904*85723df0SDavid van Moolenbroek 	else
905*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
906*85723df0SDavid van Moolenbroek 
907*85723df0SDavid van Moolenbroek 	if (r == OK) {
908*85723df0SDavid van Moolenbroek 		if (len == 0)
909*85723df0SDavid van Moolenbroek 			panic("libsockdriver: success but no address given");
910*85723df0SDavid van Moolenbroek 
911*85723df0SDavid van Moolenbroek 		if (addr_len > len)
912*85723df0SDavid van Moolenbroek 			addr_len = len;
913*85723df0SDavid van Moolenbroek 
914*85723df0SDavid van Moolenbroek 		/* As above, use the reply code for the resulting length. */
915*85723df0SDavid van Moolenbroek 		if (addr_len > 0 && (r = sys_safecopyto(m_ptr->m_source,
916*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_getset.grant, 0, (vir_bytes)buf,
917*85723df0SDavid van Moolenbroek 		    addr_len)) == OK) {
918*85723df0SDavid van Moolenbroek 			assert(addr_len <= INT_MAX);
919*85723df0SDavid van Moolenbroek 
920*85723df0SDavid van Moolenbroek 			/*
921*85723df0SDavid van Moolenbroek 			 * The Open Group wording has changed recently, now
922*85723df0SDavid van Moolenbroek 			 * suggesting that when truncating the "stored address"
923*85723df0SDavid van Moolenbroek 			 * the resulting length should be truncated as well.
924*85723df0SDavid van Moolenbroek 			 */
925*85723df0SDavid van Moolenbroek 			r = addr_len;
926*85723df0SDavid van Moolenbroek 		}
927*85723df0SDavid van Moolenbroek 	} else if (r > 0)
928*85723df0SDavid van Moolenbroek 		panic("libsockdriver: invalid reply");
929*85723df0SDavid van Moolenbroek 
930*85723df0SDavid van Moolenbroek 	send_generic_reply(m_ptr->m_source,
931*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_getset.req_id, r);
932*85723df0SDavid van Moolenbroek }
933*85723df0SDavid van Moolenbroek 
934*85723df0SDavid van Moolenbroek /*
935*85723df0SDavid van Moolenbroek  * Shut down socket send and receive operations.  This call may not be
936*85723df0SDavid van Moolenbroek  * suspended.
937*85723df0SDavid van Moolenbroek  */
938*85723df0SDavid van Moolenbroek static void
do_shutdown(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)939*85723df0SDavid van Moolenbroek do_shutdown(const struct sockdriver * __restrict sdp,
940*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
941*85723df0SDavid van Moolenbroek {
942*85723df0SDavid van Moolenbroek 	int r;
943*85723df0SDavid van Moolenbroek 
944*85723df0SDavid van Moolenbroek 	if (sdp->sdr_shutdown != NULL)
945*85723df0SDavid van Moolenbroek 		r = sdp->sdr_shutdown(
946*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_simple.sock_id,
947*85723df0SDavid van Moolenbroek 		    m_ptr->m_vfs_lsockdriver_simple.param /*how*/);
948*85723df0SDavid van Moolenbroek 	else
949*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
950*85723df0SDavid van Moolenbroek 
951*85723df0SDavid van Moolenbroek 	send_generic_reply(m_ptr->m_source,
952*85723df0SDavid van Moolenbroek 	    m_ptr->m_vfs_lsockdriver_simple.req_id, r);
953*85723df0SDavid van Moolenbroek }
954*85723df0SDavid van Moolenbroek 
955*85723df0SDavid van Moolenbroek /*
956*85723df0SDavid van Moolenbroek  * Close a socket.  This call may be suspended by the socket driver, in which
957*85723df0SDavid van Moolenbroek  * case sockdriver_reply_generic() must be used to reply later.  Note that VFS
958*85723df0SDavid van Moolenbroek  * currently does not support blocking close operations, and will mark all
959*85723df0SDavid van Moolenbroek  * close operations as nonblocking.  This will be changed in the future.
960*85723df0SDavid van Moolenbroek  */
961*85723df0SDavid van Moolenbroek static void
do_close(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)962*85723df0SDavid van Moolenbroek do_close(const struct sockdriver * __restrict sdp,
963*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
964*85723df0SDavid van Moolenbroek {
965*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
966*85723df0SDavid van Moolenbroek 	int r, sflags;
967*85723df0SDavid van Moolenbroek 
968*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
969*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_simple.req_id;
970*85723df0SDavid van Moolenbroek 
971*85723df0SDavid van Moolenbroek 	sflags = m_ptr->m_vfs_lsockdriver_simple.param;
972*85723df0SDavid van Moolenbroek 
973*85723df0SDavid van Moolenbroek 	if (sdp->sdr_close != NULL)
974*85723df0SDavid van Moolenbroek 		r = sdp->sdr_close(m_ptr->m_vfs_lsockdriver_simple.sock_id,
975*85723df0SDavid van Moolenbroek 		    (sflags & SDEV_NONBLOCK) ? NULL : &call);
976*85723df0SDavid van Moolenbroek 	else
977*85723df0SDavid van Moolenbroek 		r = OK; /* exception: this must never fail */
978*85723df0SDavid van Moolenbroek 
979*85723df0SDavid van Moolenbroek 	assert(!(sflags & SDEV_NONBLOCK) || (r != SUSPEND && r != EDONTREPLY));
980*85723df0SDavid van Moolenbroek 
981*85723df0SDavid van Moolenbroek 	if (r != SUSPEND && r != EDONTREPLY)
982*85723df0SDavid van Moolenbroek 		sockdriver_reply_generic(&call, r);
983*85723df0SDavid van Moolenbroek }
984*85723df0SDavid van Moolenbroek 
985*85723df0SDavid van Moolenbroek /*
986*85723df0SDavid van Moolenbroek  * Cancel a previous operation which may currently be suspended.  The cancel
987*85723df0SDavid van Moolenbroek  * operation itself does not have a reply.  Instead, if the provided operation
988*85723df0SDavid van Moolenbroek  * was found to be currently suspended, that operation must be aborted and a
989*85723df0SDavid van Moolenbroek  * reply (typically EINTR) must be sent for it.  If no matching operation was
990*85723df0SDavid van Moolenbroek  * found, no reply must be sent at all.
991*85723df0SDavid van Moolenbroek  */
992*85723df0SDavid van Moolenbroek static void
do_cancel(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)993*85723df0SDavid van Moolenbroek do_cancel(const struct sockdriver * __restrict sdp,
994*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
995*85723df0SDavid van Moolenbroek {
996*85723df0SDavid van Moolenbroek 	struct sockdriver_call call;
997*85723df0SDavid van Moolenbroek 
998*85723df0SDavid van Moolenbroek 	call.sc_endpt = m_ptr->m_source;
999*85723df0SDavid van Moolenbroek 	call.sc_req = m_ptr->m_vfs_lsockdriver_simple.req_id;
1000*85723df0SDavid van Moolenbroek 
1001*85723df0SDavid van Moolenbroek 	/* The 'param' message field is unused by this request. */
1002*85723df0SDavid van Moolenbroek 
1003*85723df0SDavid van Moolenbroek 	if (sdp->sdr_cancel != NULL)
1004*85723df0SDavid van Moolenbroek 		sdp->sdr_cancel(m_ptr->m_vfs_lsockdriver_simple.sock_id,
1005*85723df0SDavid van Moolenbroek 		    &call);
1006*85723df0SDavid van Moolenbroek }
1007*85723df0SDavid van Moolenbroek 
1008*85723df0SDavid van Moolenbroek /*
1009*85723df0SDavid van Moolenbroek  * Process a select request.  Select requests have their own rules with respect
1010*85723df0SDavid van Moolenbroek  * to suspension and later notification.  The basic idea is: an immediate reply
1011*85723df0SDavid van Moolenbroek  * is always sent with the subset of requested operations that are ready.  If
1012*85723df0SDavid van Moolenbroek  * SDEV_NOTIFY is given, the remaining operations are to be combined with any
1013*85723df0SDavid van Moolenbroek  * previous operations requested (with SDEV_NOTIFY) by the calling endpoint.
1014*85723df0SDavid van Moolenbroek  * If any of the pending previous operations become ready, a late reply is sent
1015*85723df0SDavid van Moolenbroek  * and only those ready operations are forgotten, leaving any other non-ready
1016*85723df0SDavid van Moolenbroek  * operations for other late replies.
1017*85723df0SDavid van Moolenbroek  */
1018*85723df0SDavid van Moolenbroek static void
do_select(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr)1019*85723df0SDavid van Moolenbroek do_select(const struct sockdriver * __restrict sdp,
1020*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr)
1021*85723df0SDavid van Moolenbroek {
1022*85723df0SDavid van Moolenbroek 	struct sockdriver_select sel;
1023*85723df0SDavid van Moolenbroek 	sockid_t id;
1024*85723df0SDavid van Moolenbroek 	int r, ops;
1025*85723df0SDavid van Moolenbroek 
1026*85723df0SDavid van Moolenbroek 	sel.ss_endpt = m_ptr->m_source;
1027*85723df0SDavid van Moolenbroek 	id = m_ptr->m_vfs_lsockdriver_select.sock_id;
1028*85723df0SDavid van Moolenbroek 	ops = m_ptr->m_vfs_lsockdriver_select.ops;
1029*85723df0SDavid van Moolenbroek 
1030*85723df0SDavid van Moolenbroek 	if (sdp->sdr_select != NULL)
1031*85723df0SDavid van Moolenbroek 		r = sdp->sdr_select(id, ops,
1032*85723df0SDavid van Moolenbroek 		    (ops & SDEV_NOTIFY) ? &sel : NULL);
1033*85723df0SDavid van Moolenbroek 	else
1034*85723df0SDavid van Moolenbroek 		r = EOPNOTSUPP;
1035*85723df0SDavid van Moolenbroek 
1036*85723df0SDavid van Moolenbroek 	send_select_reply(&sel, SDEV_SELECT1_REPLY, id, r);
1037*85723df0SDavid van Moolenbroek }
1038*85723df0SDavid van Moolenbroek 
1039*85723df0SDavid van Moolenbroek /*
1040*85723df0SDavid van Moolenbroek  * Return TRUE if the given endpoint may initiate socket requests.
1041*85723df0SDavid van Moolenbroek  */
1042*85723df0SDavid van Moolenbroek static int
may_request(endpoint_t endpt)1043*85723df0SDavid van Moolenbroek may_request(endpoint_t endpt)
1044*85723df0SDavid van Moolenbroek {
1045*85723df0SDavid van Moolenbroek 
1046*85723df0SDavid van Moolenbroek 	/*
1047*85723df0SDavid van Moolenbroek 	 * For now, we allow only VFS to initiate socket calls.  In the future,
1048*85723df0SDavid van Moolenbroek 	 * we may allow networked file systems to call into the network stack
1049*85723df0SDavid van Moolenbroek 	 * directly.  The sockdriver API has already been designed to allow for
1050*85723df0SDavid van Moolenbroek 	 * that, but this check will then need to change.  Ideally it would be
1051*85723df0SDavid van Moolenbroek 	 * using some sort of ACL system.  For now, this check prevents that
1052*85723df0SDavid van Moolenbroek 	 * network drivers themselves create and use sockets.
1053*85723df0SDavid van Moolenbroek 	 */
1054*85723df0SDavid van Moolenbroek 	return (endpt == VFS_PROC_NR);
1055*85723df0SDavid van Moolenbroek }
1056*85723df0SDavid van Moolenbroek 
1057*85723df0SDavid van Moolenbroek /*
1058*85723df0SDavid van Moolenbroek  * Process an incoming message, and (typically) send a reply.
1059*85723df0SDavid van Moolenbroek  */
1060*85723df0SDavid van Moolenbroek void
sockdriver_process(const struct sockdriver * __restrict sdp,const message * __restrict m_ptr,int ipc_status)1061*85723df0SDavid van Moolenbroek sockdriver_process(const struct sockdriver * __restrict sdp,
1062*85723df0SDavid van Moolenbroek 	const message * __restrict m_ptr, int ipc_status)
1063*85723df0SDavid van Moolenbroek {
1064*85723df0SDavid van Moolenbroek 
1065*85723df0SDavid van Moolenbroek 	/* Handle notifications separately. */
1066*85723df0SDavid van Moolenbroek 	if (is_ipc_notify(ipc_status)) {
1067*85723df0SDavid van Moolenbroek 		switch (m_ptr->m_source) {
1068*85723df0SDavid van Moolenbroek 		case CLOCK:
1069*85723df0SDavid van Moolenbroek 			if (sdp->sdr_alarm != NULL)
1070*85723df0SDavid van Moolenbroek 				sdp->sdr_alarm(m_ptr->m_notify.timestamp);
1071*85723df0SDavid van Moolenbroek 			break;
1072*85723df0SDavid van Moolenbroek 		default:
1073*85723df0SDavid van Moolenbroek 			if (sdp->sdr_other != NULL)
1074*85723df0SDavid van Moolenbroek 				sdp->sdr_other(m_ptr, ipc_status);
1075*85723df0SDavid van Moolenbroek 		}
1076*85723df0SDavid van Moolenbroek 
1077*85723df0SDavid van Moolenbroek 		return; /* do not send a reply */
1078*85723df0SDavid van Moolenbroek 	}
1079*85723df0SDavid van Moolenbroek 
1080*85723df0SDavid van Moolenbroek 	/* Is this a socket request from an acceptable party? */
1081*85723df0SDavid van Moolenbroek 	if (!IS_SDEV_RQ(m_ptr->m_type) || !may_request(m_ptr->m_source)) {
1082*85723df0SDavid van Moolenbroek 		if (sdp->sdr_other != NULL)
1083*85723df0SDavid van Moolenbroek 			sdp->sdr_other(m_ptr, ipc_status);
1084*85723df0SDavid van Moolenbroek 
1085*85723df0SDavid van Moolenbroek 		return;	/* do not send a reply */
1086*85723df0SDavid van Moolenbroek 	}
1087*85723df0SDavid van Moolenbroek 
1088*85723df0SDavid van Moolenbroek 	/*
1089*85723df0SDavid van Moolenbroek 	 * Process the request.  If the request is not recognized, we cannot
1090*85723df0SDavid van Moolenbroek 	 * send a reply either, because we do not know the reply message
1091*85723df0SDavid van Moolenbroek 	 * format.  Passing the request message to the sdr_other hook serves no
1092*85723df0SDavid van Moolenbroek 	 * practical purpose either: if the request is legitimate, this library
1093*85723df0SDavid van Moolenbroek 	 * should know about it.
1094*85723df0SDavid van Moolenbroek 	 */
1095*85723df0SDavid van Moolenbroek 	switch (m_ptr->m_type) {
1096*85723df0SDavid van Moolenbroek 	case SDEV_SOCKET:	do_socket(sdp, m_ptr);		break;
1097*85723df0SDavid van Moolenbroek 	case SDEV_SOCKETPAIR:	do_socketpair(sdp, m_ptr);	break;
1098*85723df0SDavid van Moolenbroek 	case SDEV_BIND:		do_bind_connect(sdp, m_ptr);	break;
1099*85723df0SDavid van Moolenbroek 	case SDEV_CONNECT:	do_bind_connect(sdp, m_ptr);	break;
1100*85723df0SDavid van Moolenbroek 	case SDEV_LISTEN:	do_listen(sdp, m_ptr);		break;
1101*85723df0SDavid van Moolenbroek 	case SDEV_ACCEPT:	do_accept(sdp, m_ptr);		break;
1102*85723df0SDavid van Moolenbroek 	case SDEV_SEND:		do_send(sdp, m_ptr);		break;
1103*85723df0SDavid van Moolenbroek 	case SDEV_RECV:		do_recv(sdp, m_ptr);		break;
1104*85723df0SDavid van Moolenbroek 	case SDEV_IOCTL:	do_ioctl(sdp, m_ptr);		break;
1105*85723df0SDavid van Moolenbroek 	case SDEV_SETSOCKOPT:	do_setsockopt(sdp, m_ptr);	break;
1106*85723df0SDavid van Moolenbroek 	case SDEV_GETSOCKOPT:	do_getsockopt(sdp, m_ptr);	break;
1107*85723df0SDavid van Moolenbroek 	case SDEV_GETSOCKNAME:	do_getname(sdp, m_ptr);		break;
1108*85723df0SDavid van Moolenbroek 	case SDEV_GETPEERNAME:	do_getname(sdp, m_ptr);		break;
1109*85723df0SDavid van Moolenbroek 	case SDEV_SHUTDOWN:	do_shutdown(sdp, m_ptr);	break;
1110*85723df0SDavid van Moolenbroek 	case SDEV_CLOSE:	do_close(sdp, m_ptr);		break;
1111*85723df0SDavid van Moolenbroek 	case SDEV_CANCEL:	do_cancel(sdp, m_ptr);		break;
1112*85723df0SDavid van Moolenbroek 	case SDEV_SELECT:	do_select(sdp, m_ptr);		break;
1113*85723df0SDavid van Moolenbroek 	}
1114*85723df0SDavid van Moolenbroek }
1115*85723df0SDavid van Moolenbroek 
1116*85723df0SDavid van Moolenbroek /*
1117*85723df0SDavid van Moolenbroek  * Break out of the main loop after finishing the current request.
1118*85723df0SDavid van Moolenbroek  */
1119*85723df0SDavid van Moolenbroek void
sockdriver_terminate(void)1120*85723df0SDavid van Moolenbroek sockdriver_terminate(void)
1121*85723df0SDavid van Moolenbroek {
1122*85723df0SDavid van Moolenbroek 
1123*85723df0SDavid van Moolenbroek 	running = FALSE;
1124*85723df0SDavid van Moolenbroek 
1125*85723df0SDavid van Moolenbroek 	sef_cancel();
1126*85723df0SDavid van Moolenbroek }
1127*85723df0SDavid van Moolenbroek 
1128*85723df0SDavid van Moolenbroek /*
1129*85723df0SDavid van Moolenbroek  * Main program of any socket driver.
1130*85723df0SDavid van Moolenbroek  */
1131*85723df0SDavid van Moolenbroek void
sockdriver_task(const struct sockdriver * sdp)1132*85723df0SDavid van Moolenbroek sockdriver_task(const struct sockdriver * sdp)
1133*85723df0SDavid van Moolenbroek {
1134*85723df0SDavid van Moolenbroek 	message m;
1135*85723df0SDavid van Moolenbroek 	int r, ipc_status;
1136*85723df0SDavid van Moolenbroek 
1137*85723df0SDavid van Moolenbroek 	/* The main message loop. */
1138*85723df0SDavid van Moolenbroek 	running = TRUE;
1139*85723df0SDavid van Moolenbroek 
1140*85723df0SDavid van Moolenbroek 	while (running) {
1141*85723df0SDavid van Moolenbroek 		if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK) {
1142*85723df0SDavid van Moolenbroek 			if (r == EINTR)
1143*85723df0SDavid van Moolenbroek 				continue;	/* sef_cancel() was called */
1144*85723df0SDavid van Moolenbroek 
1145*85723df0SDavid van Moolenbroek 			panic("sockdriver: sef_receive_status failed: %d", r);
1146*85723df0SDavid van Moolenbroek 		}
1147*85723df0SDavid van Moolenbroek 
1148*85723df0SDavid van Moolenbroek 		sockdriver_process(sdp, &m, ipc_status);
1149*85723df0SDavid van Moolenbroek 	}
1150*85723df0SDavid van Moolenbroek }
1151