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