xref: /minix3/minix/servers/vfs/socket.c (revision 491d647a3b6c5e781017a8842cade543fc0b74a3)
1c38dbb97SDavid van Moolenbroek /*
2c38dbb97SDavid van Moolenbroek  * This file implements the upper socket layer of VFS: the BSD socket system
3c38dbb97SDavid van Moolenbroek  * calls, and any associated file descriptor, file pointer, vnode, and file
4c38dbb97SDavid van Moolenbroek  * system processing.  In most cases, this layer will call into the lower
5c38dbb97SDavid van Moolenbroek  * socket layer in order to send the request to a socket driver.  Generic file
6c38dbb97SDavid van Moolenbroek  * calls (e.g., read, write, ioctl, and select) are not implemented here, and
7c38dbb97SDavid van Moolenbroek  * will directly call into the lower socket layer as well.
8c38dbb97SDavid van Moolenbroek  *
9c38dbb97SDavid van Moolenbroek  * The following table shows the system call numbers implemented in this file,
10c38dbb97SDavid van Moolenbroek  * along with their request and reply message types.  Each request layout
11c38dbb97SDavid van Moolenbroek  * message type is prefixed with "m_lc_vfs_".  Each reply layout message type
12c38dbb97SDavid van Moolenbroek  * is prefixed with "m_vfs_lc_".  For requests without a specific reply layout,
13c38dbb97SDavid van Moolenbroek  * only the "m_type" message field is used in the reply message.
14c38dbb97SDavid van Moolenbroek  *
15c38dbb97SDavid van Moolenbroek  * Type			Request layout		Reply layout
16c38dbb97SDavid van Moolenbroek  * ----			--------------		------------
17c38dbb97SDavid van Moolenbroek  * VFS_SOCKET		socket
18c38dbb97SDavid van Moolenbroek  * VFS_SOCKETPAIR	socket			fdpair
19c38dbb97SDavid van Moolenbroek  * VFS_BIND		sockaddr
20c38dbb97SDavid van Moolenbroek  * VFS_CONNECT		sockaddr
21c38dbb97SDavid van Moolenbroek  * VFS_LISTEN		listen
22c38dbb97SDavid van Moolenbroek  * VFS_ACCEPT		sockaddr		socklen
23c38dbb97SDavid van Moolenbroek  * VFS_SENDTO		sendrecv
24c38dbb97SDavid van Moolenbroek  * VFS_RECVFROM		sendrecv		socklen
25c38dbb97SDavid van Moolenbroek  * VFS_SENDMSG		sockmsg
26c38dbb97SDavid van Moolenbroek  * VFS_RECVMSG		sockmsg
27c38dbb97SDavid van Moolenbroek  * VFS_SETSOCKOPT	sockopt
28c38dbb97SDavid van Moolenbroek  * VFS_GETSOCKOPT	sockopt			socklen
29c38dbb97SDavid van Moolenbroek  * VFS_GETSOCKNAME	sockaddr		socklen
30c38dbb97SDavid van Moolenbroek  * VFS_GETPEERNAME	sockaddr		socklen
31c38dbb97SDavid van Moolenbroek  * VFS_SHUTDOWN		shutdown
32c38dbb97SDavid van Moolenbroek  */
33c38dbb97SDavid van Moolenbroek 
34c38dbb97SDavid van Moolenbroek #include "fs.h"
35e3b8d4bbSDavid van Moolenbroek #include "vnode.h"
36e3b8d4bbSDavid van Moolenbroek #include "file.h"
37c38dbb97SDavid van Moolenbroek 
38c38dbb97SDavid van Moolenbroek #include <sys/socket.h>
39c38dbb97SDavid van Moolenbroek 
40c38dbb97SDavid van Moolenbroek /*
41e3b8d4bbSDavid van Moolenbroek  * Convert any SOCK_xx open flags to O_xx open flags.
42e3b8d4bbSDavid van Moolenbroek  */
43e3b8d4bbSDavid van Moolenbroek static int
get_sock_flags(int type)44e3b8d4bbSDavid van Moolenbroek get_sock_flags(int type)
45e3b8d4bbSDavid van Moolenbroek {
46e3b8d4bbSDavid van Moolenbroek 	int flags;
47e3b8d4bbSDavid van Moolenbroek 
48e3b8d4bbSDavid van Moolenbroek 	flags = 0;
49e3b8d4bbSDavid van Moolenbroek 	if (type & SOCK_CLOEXEC)
50e3b8d4bbSDavid van Moolenbroek 		flags |= O_CLOEXEC;
51e3b8d4bbSDavid van Moolenbroek 	if (type & SOCK_NONBLOCK)
52e3b8d4bbSDavid van Moolenbroek 		flags |= O_NONBLOCK;
53e3b8d4bbSDavid van Moolenbroek 	if (type & SOCK_NOSIGPIPE)
54e3b8d4bbSDavid van Moolenbroek 		flags |= O_NOSIGPIPE;
55e3b8d4bbSDavid van Moolenbroek 
56e3b8d4bbSDavid van Moolenbroek 	return flags;
57e3b8d4bbSDavid van Moolenbroek }
58e3b8d4bbSDavid van Moolenbroek 
59e3b8d4bbSDavid van Moolenbroek /*
60e3b8d4bbSDavid van Moolenbroek  * Perform cheap pre-call checks to ensure that the given number of socket FDs
61e3b8d4bbSDavid van Moolenbroek  * can be created for the current process.
62e3b8d4bbSDavid van Moolenbroek  */
63e3b8d4bbSDavid van Moolenbroek static int
check_sock_fds(int nfds)64e3b8d4bbSDavid van Moolenbroek check_sock_fds(int nfds)
65e3b8d4bbSDavid van Moolenbroek {
66e3b8d4bbSDavid van Moolenbroek 
67e3b8d4bbSDavid van Moolenbroek 	/*
68e3b8d4bbSDavid van Moolenbroek 	 * For now, we simply check if there are enough file descriptor slots
69e3b8d4bbSDavid van Moolenbroek 	 * free in the process.  Since the process is blocked on a socket call,
70e3b8d4bbSDavid van Moolenbroek 	 * this aspect will not change.  Availability of file pointers, vnodes,
71e3b8d4bbSDavid van Moolenbroek 	 * and PFS nodes may vary, and is therefore less interesting to check
72e3b8d4bbSDavid van Moolenbroek 	 * here - it will have to be checked again upon completion anyway.
73e3b8d4bbSDavid van Moolenbroek 	 */
74e3b8d4bbSDavid van Moolenbroek 	return check_fds(fp, nfds);
75e3b8d4bbSDavid van Moolenbroek }
76e3b8d4bbSDavid van Moolenbroek 
77e3b8d4bbSDavid van Moolenbroek /*
78e3b8d4bbSDavid van Moolenbroek  * Create a new file descriptor, including supporting objects, for the open
79e3b8d4bbSDavid van Moolenbroek  * socket identified by 'dev', in the current process, using the O_xx open
80e3b8d4bbSDavid van Moolenbroek  * flags 'flags'.  On success, return the file descriptor number.  The results
81e3b8d4bbSDavid van Moolenbroek  * of a successful call can be undone with close_fd(), which will also close
82e3b8d4bbSDavid van Moolenbroek  * the socket itself.  On failure, return a negative error code.  In this case,
83e3b8d4bbSDavid van Moolenbroek  * the socket will be left open.
84e3b8d4bbSDavid van Moolenbroek  */
85e3b8d4bbSDavid van Moolenbroek static int
make_sock_fd(dev_t dev,int flags)86e3b8d4bbSDavid van Moolenbroek make_sock_fd(dev_t dev, int flags)
87e3b8d4bbSDavid van Moolenbroek {
88e3b8d4bbSDavid van Moolenbroek 	struct vmnt *vmp;
89e3b8d4bbSDavid van Moolenbroek 	struct vnode *vp;
90e3b8d4bbSDavid van Moolenbroek 	struct filp *filp;
91e3b8d4bbSDavid van Moolenbroek 	struct node_details res;
92e3b8d4bbSDavid van Moolenbroek 	int r, fd;
93e3b8d4bbSDavid van Moolenbroek 
94e3b8d4bbSDavid van Moolenbroek 	assert((flags & ~(O_CLOEXEC | O_NONBLOCK | O_NOSIGPIPE)) == 0);
95e3b8d4bbSDavid van Moolenbroek 
96e3b8d4bbSDavid van Moolenbroek #if !NDEBUG
97e3b8d4bbSDavid van Moolenbroek 	/*
98e3b8d4bbSDavid van Moolenbroek 	 * Check whether there is a socket object for the new device already.
99e3b8d4bbSDavid van Moolenbroek 	 * This is an expensive check, but if the socket driver sends us a new
100e3b8d4bbSDavid van Moolenbroek 	 * socket ID that is already in use, this is a sure sign of driver
101e3b8d4bbSDavid van Moolenbroek 	 * misbehavior.  So far it does seem like nothing would go wrong within
102e3b8d4bbSDavid van Moolenbroek 	 * VFS in this case though, which is why this is a debug-only check.
103e3b8d4bbSDavid van Moolenbroek 	 */
104e3b8d4bbSDavid van Moolenbroek 	if (find_filp_by_sock_dev(dev) != NULL) {
105e3b8d4bbSDavid van Moolenbroek 		printf("VFS: socket driver %d generated in-use socket ID!\n",
106e3b8d4bbSDavid van Moolenbroek 		    get_smap_by_dev(dev, NULL)->smap_endpt);
107e3b8d4bbSDavid van Moolenbroek 		return EIO;
108e3b8d4bbSDavid van Moolenbroek 	}
109e3b8d4bbSDavid van Moolenbroek #endif /* !NDEBUG */
110e3b8d4bbSDavid van Moolenbroek 
111e3b8d4bbSDavid van Moolenbroek 	/*
112e3b8d4bbSDavid van Moolenbroek 	 * Get a lock on PFS.  TODO: it is not clear whether locking PFS is
113e3b8d4bbSDavid van Moolenbroek 	 * needed at all, let alone which lock: map_vnode() uses a write lock,
114e3b8d4bbSDavid van Moolenbroek 	 * create_pipe() uses a read lock, and cdev_clone() uses no lock at
115e3b8d4bbSDavid van Moolenbroek 	 * all.  As is, the README prescribes VMNT_READ, so that's what we use
116e3b8d4bbSDavid van Moolenbroek 	 * here.  The code below largely copies the create_pipe() code anyway.
117e3b8d4bbSDavid van Moolenbroek 	 */
118e3b8d4bbSDavid van Moolenbroek 	if ((vmp = find_vmnt(PFS_PROC_NR)) == NULL)
119e3b8d4bbSDavid van Moolenbroek 		panic("PFS gone");
120e3b8d4bbSDavid van Moolenbroek 	if ((r = lock_vmnt(vmp, VMNT_READ)) != OK)
121e3b8d4bbSDavid van Moolenbroek 		return r;
122e3b8d4bbSDavid van Moolenbroek 
123e3b8d4bbSDavid van Moolenbroek 	/* Obtain a free vnode. */
124e3b8d4bbSDavid van Moolenbroek 	if ((vp = get_free_vnode()) == NULL) {
125e3b8d4bbSDavid van Moolenbroek 		unlock_vmnt(vmp);
126e3b8d4bbSDavid van Moolenbroek 		return err_code;
127e3b8d4bbSDavid van Moolenbroek 	}
128e3b8d4bbSDavid van Moolenbroek 	lock_vnode(vp, VNODE_OPCL);
129e3b8d4bbSDavid van Moolenbroek 
130e3b8d4bbSDavid van Moolenbroek 	/* Acquire a file descriptor. */
131e3b8d4bbSDavid van Moolenbroek 	if ((r = get_fd(fp, 0, R_BIT | W_BIT, &fd, &filp)) != OK) {
132e3b8d4bbSDavid van Moolenbroek 		unlock_vnode(vp);
133e3b8d4bbSDavid van Moolenbroek 		unlock_vmnt(vmp);
134e3b8d4bbSDavid van Moolenbroek 		return r;
135e3b8d4bbSDavid van Moolenbroek 	}
136e3b8d4bbSDavid van Moolenbroek 
137e3b8d4bbSDavid van Moolenbroek 	/* Create a PFS node for the socket. */
138e3b8d4bbSDavid van Moolenbroek 	if ((r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid,
139e3b8d4bbSDavid van Moolenbroek 	    S_IFSOCK | ACCESSPERMS, dev, &res)) != OK) {
140e3b8d4bbSDavid van Moolenbroek 		unlock_filp(filp);
141e3b8d4bbSDavid van Moolenbroek 		unlock_vnode(vp);
142e3b8d4bbSDavid van Moolenbroek 		unlock_vmnt(vmp);
143e3b8d4bbSDavid van Moolenbroek 		return r;
144e3b8d4bbSDavid van Moolenbroek 	}
145e3b8d4bbSDavid van Moolenbroek 
146e3b8d4bbSDavid van Moolenbroek 	/* Fill in the objects, and link them together. */
147e3b8d4bbSDavid van Moolenbroek 	vp->v_fs_e = res.fs_e;
148e3b8d4bbSDavid van Moolenbroek 	vp->v_inode_nr = res.inode_nr;
149e3b8d4bbSDavid van Moolenbroek 	vp->v_mode = res.fmode;
150e3b8d4bbSDavid van Moolenbroek 	vp->v_sdev = dev;
151e3b8d4bbSDavid van Moolenbroek 	vp->v_fs_count = 1;
152e3b8d4bbSDavid van Moolenbroek 	vp->v_ref_count = 1;
153e3b8d4bbSDavid van Moolenbroek 	vp->v_vmnt = NULL;
154e3b8d4bbSDavid van Moolenbroek 	vp->v_dev = NO_DEV;
155e3b8d4bbSDavid van Moolenbroek 	vp->v_size = 0;
156e3b8d4bbSDavid van Moolenbroek 
157e3b8d4bbSDavid van Moolenbroek 	filp->filp_vno = vp;
158e3b8d4bbSDavid van Moolenbroek 	filp->filp_flags = O_RDWR | flags;
159e3b8d4bbSDavid van Moolenbroek 	filp->filp_count = 1;
160e3b8d4bbSDavid van Moolenbroek 
161e3b8d4bbSDavid van Moolenbroek 	fp->fp_filp[fd] = filp;
162e3b8d4bbSDavid van Moolenbroek 	if (flags & O_CLOEXEC)
163e3b8d4bbSDavid van Moolenbroek 		FD_SET(fd, &fp->fp_cloexec_set);
164e3b8d4bbSDavid van Moolenbroek 
165e3b8d4bbSDavid van Moolenbroek 	/* Release locks, and return the new file descriptor. */
166e3b8d4bbSDavid van Moolenbroek 	unlock_filp(filp); /* this also unlocks the vnode now! */
167e3b8d4bbSDavid van Moolenbroek 	unlock_vmnt(vmp);
168e3b8d4bbSDavid van Moolenbroek 
169e3b8d4bbSDavid van Moolenbroek 	return fd;
170e3b8d4bbSDavid van Moolenbroek }
171e3b8d4bbSDavid van Moolenbroek 
172e3b8d4bbSDavid van Moolenbroek /*
173c38dbb97SDavid van Moolenbroek  * Create a socket.
174c38dbb97SDavid van Moolenbroek  */
175c38dbb97SDavid van Moolenbroek int
do_socket(void)176c38dbb97SDavid van Moolenbroek do_socket(void)
177c38dbb97SDavid van Moolenbroek {
178e3b8d4bbSDavid van Moolenbroek 	int domain, type, sock_type, protocol;
179e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
180e3b8d4bbSDavid van Moolenbroek 	int r, flags;
181c38dbb97SDavid van Moolenbroek 
182e3b8d4bbSDavid van Moolenbroek 	domain = job_m_in.m_lc_vfs_socket.domain;
183e3b8d4bbSDavid van Moolenbroek 	type = job_m_in.m_lc_vfs_socket.type;
184e3b8d4bbSDavid van Moolenbroek 	protocol = job_m_in.m_lc_vfs_socket.protocol;
185e3b8d4bbSDavid van Moolenbroek 
186e3b8d4bbSDavid van Moolenbroek 	/* Is there a socket driver for this domain at all? */
187e3b8d4bbSDavid van Moolenbroek 	if (get_smap_by_domain(domain) == NULL)
188c38dbb97SDavid van Moolenbroek 		return EAFNOSUPPORT;
189e3b8d4bbSDavid van Moolenbroek 
190e3b8d4bbSDavid van Moolenbroek 	/*
191e3b8d4bbSDavid van Moolenbroek 	 * Ensure that it is at least likely that after creating a socket, we
192e3b8d4bbSDavid van Moolenbroek 	 * will be able to create a file descriptor for it, along with all the
193e3b8d4bbSDavid van Moolenbroek 	 * necessary supporting objects.  While it would be slightly neater to
194e3b8d4bbSDavid van Moolenbroek 	 * allocate these objects before trying to create the socket, this is
195e3b8d4bbSDavid van Moolenbroek 	 * offset by the fact that that approach results in a downright mess in
196e3b8d4bbSDavid van Moolenbroek 	 * do_socketpair() below, and with the current approach we can reuse
197e3b8d4bbSDavid van Moolenbroek 	 * the same code for accepting sockets as well.  For newly created
198e3b8d4bbSDavid van Moolenbroek 	 * sockets, it is no big deal to close them right after creation; for
199e3b8d4bbSDavid van Moolenbroek 	 * newly accepted sockets, we have no choice but to do that anyway.
200e3b8d4bbSDavid van Moolenbroek 	 * Moreover, object creation failures should be rare and our approach
201e3b8d4bbSDavid van Moolenbroek 	 * does not cause significantly more overhead anyway, so the entire
202e3b8d4bbSDavid van Moolenbroek 	 * issue is largely philosophical anyway.  For now, this will do.
203e3b8d4bbSDavid van Moolenbroek 	 */
204e3b8d4bbSDavid van Moolenbroek 	if ((r = check_sock_fds(1)) != OK)
205e3b8d4bbSDavid van Moolenbroek 		return r;
206e3b8d4bbSDavid van Moolenbroek 
207e3b8d4bbSDavid van Moolenbroek 	sock_type = type & ~SOCK_FLAGS_MASK;
208e3b8d4bbSDavid van Moolenbroek 	flags = get_sock_flags(type);
209e3b8d4bbSDavid van Moolenbroek 
210e3b8d4bbSDavid van Moolenbroek 	if ((r = sdev_socket(domain, sock_type, protocol, &dev,
211e3b8d4bbSDavid van Moolenbroek 	    FALSE /*pair*/)) != OK)
212e3b8d4bbSDavid van Moolenbroek 		return r;
213e3b8d4bbSDavid van Moolenbroek 
214e3b8d4bbSDavid van Moolenbroek 	if ((r = make_sock_fd(dev, flags)) < 0)
215*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev, FALSE /*may_suspend*/);
216e3b8d4bbSDavid van Moolenbroek 
217e3b8d4bbSDavid van Moolenbroek 	return r;
218c38dbb97SDavid van Moolenbroek }
219c38dbb97SDavid van Moolenbroek 
220c38dbb97SDavid van Moolenbroek /*
221c38dbb97SDavid van Moolenbroek  * Create a pair of connected sockets.
222c38dbb97SDavid van Moolenbroek  */
223c38dbb97SDavid van Moolenbroek int
do_socketpair(void)224c38dbb97SDavid van Moolenbroek do_socketpair(void)
225c38dbb97SDavid van Moolenbroek {
226e3b8d4bbSDavid van Moolenbroek 	int domain, type, sock_type, protocol;
227e3b8d4bbSDavid van Moolenbroek 	dev_t dev[2];
228e3b8d4bbSDavid van Moolenbroek 	int r, fd0, fd1, flags;
229c38dbb97SDavid van Moolenbroek 
230e3b8d4bbSDavid van Moolenbroek 	domain = job_m_in.m_lc_vfs_socket.domain;
231e3b8d4bbSDavid van Moolenbroek 	type = job_m_in.m_lc_vfs_socket.type;
232e3b8d4bbSDavid van Moolenbroek 	protocol = job_m_in.m_lc_vfs_socket.protocol;
233e3b8d4bbSDavid van Moolenbroek 
234e3b8d4bbSDavid van Moolenbroek 	/* Is there a socket driver for this domain at all? */
235e3b8d4bbSDavid van Moolenbroek 	if (get_smap_by_domain(domain) == NULL)
236c38dbb97SDavid van Moolenbroek 		return EAFNOSUPPORT;
237e3b8d4bbSDavid van Moolenbroek 
238e3b8d4bbSDavid van Moolenbroek 	/*
239e3b8d4bbSDavid van Moolenbroek 	 * See the lengthy comment in do_socket().  This time we need two of
240e3b8d4bbSDavid van Moolenbroek 	 * everything, though.
241e3b8d4bbSDavid van Moolenbroek 	 */
242e3b8d4bbSDavid van Moolenbroek 	if ((r = check_sock_fds(2)) != OK)
243e3b8d4bbSDavid van Moolenbroek 		return r;
244e3b8d4bbSDavid van Moolenbroek 
245e3b8d4bbSDavid van Moolenbroek 	sock_type = type & ~SOCK_FLAGS_MASK;
246e3b8d4bbSDavid van Moolenbroek 	flags = get_sock_flags(type);
247e3b8d4bbSDavid van Moolenbroek 
248e3b8d4bbSDavid van Moolenbroek 	if ((r = sdev_socket(domain, sock_type, protocol, dev,
249e3b8d4bbSDavid van Moolenbroek 	    TRUE /*pair*/)) != OK)
250e3b8d4bbSDavid van Moolenbroek 		return r;
251e3b8d4bbSDavid van Moolenbroek 
252e3b8d4bbSDavid van Moolenbroek 	if ((fd0 = make_sock_fd(dev[0], flags)) < 0) {
253*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev[0], FALSE /*may_suspend*/);
254*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev[1], FALSE /*may_suspend*/);
255e3b8d4bbSDavid van Moolenbroek 		return fd0;
256e3b8d4bbSDavid van Moolenbroek 	}
257e3b8d4bbSDavid van Moolenbroek 
258e3b8d4bbSDavid van Moolenbroek 	if ((fd1 = make_sock_fd(dev[1], flags)) < 0) {
259*491d647aSDavid van Moolenbroek 		close_fd(fp, fd0, FALSE /*may_suspend*/);
260*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev[1], FALSE /*may_suspend*/);
261e3b8d4bbSDavid van Moolenbroek 		return fd1;
262e3b8d4bbSDavid van Moolenbroek 	}
263e3b8d4bbSDavid van Moolenbroek 
264e3b8d4bbSDavid van Moolenbroek 	job_m_out.m_vfs_lc_fdpair.fd0 = fd0;
265e3b8d4bbSDavid van Moolenbroek 	job_m_out.m_vfs_lc_fdpair.fd1 = fd1;
266e3b8d4bbSDavid van Moolenbroek 	return OK;
267e3b8d4bbSDavid van Moolenbroek }
268e3b8d4bbSDavid van Moolenbroek 
269e3b8d4bbSDavid van Moolenbroek /*
270e3b8d4bbSDavid van Moolenbroek  * Check whether the given file descriptor identifies an open socket in the
271e3b8d4bbSDavid van Moolenbroek  * current process.  If so, return OK, with the socket device number stored in
272e3b8d4bbSDavid van Moolenbroek  * 'dev' and its file pointer flags stored in 'flags' (if not NULL).  If not,
273e3b8d4bbSDavid van Moolenbroek  * return an appropriate error code.
274e3b8d4bbSDavid van Moolenbroek  */
275e3b8d4bbSDavid van Moolenbroek static int
get_sock(int fd,dev_t * dev,int * flags)276e3b8d4bbSDavid van Moolenbroek get_sock(int fd, dev_t * dev, int * flags)
277e3b8d4bbSDavid van Moolenbroek {
278e3b8d4bbSDavid van Moolenbroek 	struct filp *filp;
279e3b8d4bbSDavid van Moolenbroek 
280e3b8d4bbSDavid van Moolenbroek 	if ((filp = get_filp(fd, VNODE_READ)) == NULL)
281e3b8d4bbSDavid van Moolenbroek 		return err_code;
282e3b8d4bbSDavid van Moolenbroek 
283e3b8d4bbSDavid van Moolenbroek 	if (!S_ISSOCK(filp->filp_vno->v_mode)) {
284e3b8d4bbSDavid van Moolenbroek 		unlock_filp(filp);
285e3b8d4bbSDavid van Moolenbroek 		return ENOTSOCK;
286e3b8d4bbSDavid van Moolenbroek 	}
287e3b8d4bbSDavid van Moolenbroek 
288e3b8d4bbSDavid van Moolenbroek 	*dev = filp->filp_vno->v_sdev;
289e3b8d4bbSDavid van Moolenbroek 	if (flags != NULL)
290e3b8d4bbSDavid van Moolenbroek 		*flags = filp->filp_flags;
291e3b8d4bbSDavid van Moolenbroek 
292e3b8d4bbSDavid van Moolenbroek 	/*
293e3b8d4bbSDavid van Moolenbroek 	 * It is safe to leave the file pointer object unlocked during the
294e3b8d4bbSDavid van Moolenbroek 	 * actual call.  Since the current process is blocked for the duration
295e3b8d4bbSDavid van Moolenbroek 	 * of the socket call, we know the socket's file descriptor, and thus
296e3b8d4bbSDavid van Moolenbroek 	 * its file pointer, can not possibly be freed.  In addition, we will
297e3b8d4bbSDavid van Moolenbroek 	 * not be accessing the file pointer anymore later, with the exception
298e3b8d4bbSDavid van Moolenbroek 	 * of accept calls, which reacquire the lock when the reply comes in.
299e3b8d4bbSDavid van Moolenbroek 	 */
300e3b8d4bbSDavid van Moolenbroek 	unlock_filp(filp);
301e3b8d4bbSDavid van Moolenbroek 	return OK;
302c38dbb97SDavid van Moolenbroek }
303c38dbb97SDavid van Moolenbroek 
304c38dbb97SDavid van Moolenbroek /*
305c38dbb97SDavid van Moolenbroek  * Bind a socket to a local address.
306c38dbb97SDavid van Moolenbroek  */
307c38dbb97SDavid van Moolenbroek int
do_bind(void)308c38dbb97SDavid van Moolenbroek do_bind(void)
309c38dbb97SDavid van Moolenbroek {
310e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
311e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
312c38dbb97SDavid van Moolenbroek 
313e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockaddr.fd;
314e3b8d4bbSDavid van Moolenbroek 
315e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
316e3b8d4bbSDavid van Moolenbroek 		return r;
317e3b8d4bbSDavid van Moolenbroek 
318e3b8d4bbSDavid van Moolenbroek 	return sdev_bind(dev, job_m_in.m_lc_vfs_sockaddr.addr,
319e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockaddr.addr_len, flags);
320c38dbb97SDavid van Moolenbroek }
321c38dbb97SDavid van Moolenbroek 
322c38dbb97SDavid van Moolenbroek /*
323c38dbb97SDavid van Moolenbroek  * Connect a socket to a remote address.
324c38dbb97SDavid van Moolenbroek  */
325c38dbb97SDavid van Moolenbroek int
do_connect(void)326c38dbb97SDavid van Moolenbroek do_connect(void)
327c38dbb97SDavid van Moolenbroek {
328e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
329e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
330c38dbb97SDavid van Moolenbroek 
331e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockaddr.fd;
332e3b8d4bbSDavid van Moolenbroek 
333e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
334e3b8d4bbSDavid van Moolenbroek 		return r;
335e3b8d4bbSDavid van Moolenbroek 
336e3b8d4bbSDavid van Moolenbroek 	return sdev_connect(dev, job_m_in.m_lc_vfs_sockaddr.addr,
337e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockaddr.addr_len, flags);
338c38dbb97SDavid van Moolenbroek }
339c38dbb97SDavid van Moolenbroek 
340c38dbb97SDavid van Moolenbroek /*
341c38dbb97SDavid van Moolenbroek  * Put a socket in listening mode.
342c38dbb97SDavid van Moolenbroek  */
343c38dbb97SDavid van Moolenbroek int
do_listen(void)344c38dbb97SDavid van Moolenbroek do_listen(void)
345c38dbb97SDavid van Moolenbroek {
346e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
347e3b8d4bbSDavid van Moolenbroek 	int r, fd, backlog;
348c38dbb97SDavid van Moolenbroek 
349e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_listen.fd;
350e3b8d4bbSDavid van Moolenbroek 	backlog = job_m_in.m_lc_vfs_listen.backlog;
351e3b8d4bbSDavid van Moolenbroek 
352e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
353e3b8d4bbSDavid van Moolenbroek 		return r;
354e3b8d4bbSDavid van Moolenbroek 
355e3b8d4bbSDavid van Moolenbroek 	if (backlog < 0)
356e3b8d4bbSDavid van Moolenbroek 		backlog = 0;
357e3b8d4bbSDavid van Moolenbroek 
358e3b8d4bbSDavid van Moolenbroek 	return sdev_listen(dev, backlog);
359c38dbb97SDavid van Moolenbroek }
360c38dbb97SDavid van Moolenbroek 
361c38dbb97SDavid van Moolenbroek /*
362c38dbb97SDavid van Moolenbroek  * Accept a connection on a listening socket, creating a new socket.
363c38dbb97SDavid van Moolenbroek  */
364c38dbb97SDavid van Moolenbroek int
do_accept(void)365c38dbb97SDavid van Moolenbroek do_accept(void)
366c38dbb97SDavid van Moolenbroek {
367e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
368e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
369c38dbb97SDavid van Moolenbroek 
370e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockaddr.fd;
371e3b8d4bbSDavid van Moolenbroek 
372e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
373e3b8d4bbSDavid van Moolenbroek 		return r;
374e3b8d4bbSDavid van Moolenbroek 
375e3b8d4bbSDavid van Moolenbroek 	if ((r = check_sock_fds(1)) != OK)
376e3b8d4bbSDavid van Moolenbroek 		return r;
377e3b8d4bbSDavid van Moolenbroek 
378e3b8d4bbSDavid van Moolenbroek 	return sdev_accept(dev, job_m_in.m_lc_vfs_sockaddr.addr,
379e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockaddr.addr_len, flags, fd);
380e3b8d4bbSDavid van Moolenbroek }
381e3b8d4bbSDavid van Moolenbroek 
382e3b8d4bbSDavid van Moolenbroek /*
383e3b8d4bbSDavid van Moolenbroek  * Resume a previously suspended accept(2) system call.  This routine must
384e3b8d4bbSDavid van Moolenbroek  * cover three distinct cases, depending on the 'status' and 'dev' values:
385e3b8d4bbSDavid van Moolenbroek  *
386e3b8d4bbSDavid van Moolenbroek  * #1. If the 'status' parameter is set to OK, the accept call succeeded.  In
387e3b8d4bbSDavid van Moolenbroek  *     that case, the function is guaranteed to be called from a worker thread,
388e3b8d4bbSDavid van Moolenbroek  *     with 'fp' set to the user process that made the system call.  In that
389e3b8d4bbSDavid van Moolenbroek  *     case, this function may block its calling thread.  The 'dev' parameter
390e3b8d4bbSDavid van Moolenbroek  *     will contain the device number of the newly accepted socket.
391e3b8d4bbSDavid van Moolenbroek  * #2. If the 'status' parameter contains a negative error code, but 'dev' is
392e3b8d4bbSDavid van Moolenbroek  *     *not* set to NO_DEV, then the same as above applies, except that the new
393e3b8d4bbSDavid van Moolenbroek  *     socket must be closed immediately.
394e3b8d4bbSDavid van Moolenbroek  * #3. If 'status' is a negative error code and 'dev' is set to NO_DEV, then
395e3b8d4bbSDavid van Moolenbroek  *     the accept call has failed and no new socket was ever created.  In this
396e3b8d4bbSDavid van Moolenbroek  *     case, the function MUST NOT block its calling thread.
397e3b8d4bbSDavid van Moolenbroek  */
398e3b8d4bbSDavid van Moolenbroek void
resume_accept(struct fproc * rfp,int status,dev_t dev,unsigned int addr_len,int listen_fd)399e3b8d4bbSDavid van Moolenbroek resume_accept(struct fproc * rfp, int status, dev_t dev, unsigned int addr_len,
400e3b8d4bbSDavid van Moolenbroek 	int listen_fd)
401e3b8d4bbSDavid van Moolenbroek {
402e3b8d4bbSDavid van Moolenbroek 	message m;
403e3b8d4bbSDavid van Moolenbroek 	dev_t ldev;
404e3b8d4bbSDavid van Moolenbroek 	int r, flags;
405e3b8d4bbSDavid van Moolenbroek 
406e3b8d4bbSDavid van Moolenbroek 	/*
407e3b8d4bbSDavid van Moolenbroek 	 * If the call did not succeed and no socket was created (case #3), we
408e3b8d4bbSDavid van Moolenbroek 	 * cannot and should not do more than send the error to the user
409e3b8d4bbSDavid van Moolenbroek 	 * process.
410e3b8d4bbSDavid van Moolenbroek 	 */
411e3b8d4bbSDavid van Moolenbroek 	if (status != OK && dev == NO_DEV) {
412e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, status);
413e3b8d4bbSDavid van Moolenbroek 
414e3b8d4bbSDavid van Moolenbroek 		return;
415e3b8d4bbSDavid van Moolenbroek 	}
416e3b8d4bbSDavid van Moolenbroek 
417e3b8d4bbSDavid van Moolenbroek 	/*
418e3b8d4bbSDavid van Moolenbroek 	 * The call succeeded.  The lower socket layer (sdev.c) ensures that in
419e3b8d4bbSDavid van Moolenbroek 	 * that case, we are called from a worker thread which is associated
420e3b8d4bbSDavid van Moolenbroek 	 * with the original user process.  Thus, we can block the current
421e3b8d4bbSDavid van Moolenbroek 	 * thread.  Start by verifying that the listening socket is still
422e3b8d4bbSDavid van Moolenbroek 	 * around.  If it is not, it must have been invalidated as a result of
423e3b8d4bbSDavid van Moolenbroek 	 * a socket driver death, in which case we must report an error but
424e3b8d4bbSDavid van Moolenbroek 	 * need not close the new socket.  As a side effect, obtain the
425e3b8d4bbSDavid van Moolenbroek 	 * listening socket's flags, which on BSD systems are inherited by the
426e3b8d4bbSDavid van Moolenbroek 	 * accepted socket.
427e3b8d4bbSDavid van Moolenbroek 	 */
428e3b8d4bbSDavid van Moolenbroek 	assert(fp == rfp); /* needed for get_sock() and make_sock_fd() */
429e3b8d4bbSDavid van Moolenbroek 
430e3b8d4bbSDavid van Moolenbroek 	if (get_sock(listen_fd, &ldev, &flags) != OK) {
431e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, EIO);
432e3b8d4bbSDavid van Moolenbroek 
433e3b8d4bbSDavid van Moolenbroek 		return;
434e3b8d4bbSDavid van Moolenbroek 	}
435e3b8d4bbSDavid van Moolenbroek 
436e3b8d4bbSDavid van Moolenbroek 	/* The same socket driver must host both sockets, obviously. */
437e3b8d4bbSDavid van Moolenbroek 	assert(get_smap_by_dev(ldev, NULL) == get_smap_by_dev(dev, NULL));
438e3b8d4bbSDavid van Moolenbroek 
439e3b8d4bbSDavid van Moolenbroek 	/*
440e3b8d4bbSDavid van Moolenbroek 	 * If an error status was returned (case #2), we must now close the
441e3b8d4bbSDavid van Moolenbroek 	 * newly accepted socket.  Effectively, this allows socket drivers to
442e3b8d4bbSDavid van Moolenbroek 	 * handle address copy failures in the cleanest possible way.
443e3b8d4bbSDavid van Moolenbroek 	 */
444e3b8d4bbSDavid van Moolenbroek 	if (status != OK) {
445*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev, FALSE /*may_suspend*/);
446e3b8d4bbSDavid van Moolenbroek 
447e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, status);
448e3b8d4bbSDavid van Moolenbroek 
449e3b8d4bbSDavid van Moolenbroek 		return;
450e3b8d4bbSDavid van Moolenbroek 	}
451e3b8d4bbSDavid van Moolenbroek 
452e3b8d4bbSDavid van Moolenbroek 	/*
453e3b8d4bbSDavid van Moolenbroek 	 * A new socket has been successfully accepted (case #1).  Try to
454e3b8d4bbSDavid van Moolenbroek 	 * create a file descriptor for the new socket.  If this fails, we have
455e3b8d4bbSDavid van Moolenbroek 	 * to close the new socket after all.  That is not great, but we have
456e3b8d4bbSDavid van Moolenbroek 	 * no way to prevent this except by preallocating all objects for the
457e3b8d4bbSDavid van Moolenbroek 	 * duration of the accept call, which is not exactly great either.
458e3b8d4bbSDavid van Moolenbroek 	 */
459e3b8d4bbSDavid van Moolenbroek 	flags &= O_CLOEXEC | O_NONBLOCK | O_NOSIGPIPE;
460e3b8d4bbSDavid van Moolenbroek 
461e3b8d4bbSDavid van Moolenbroek 	if ((r = make_sock_fd(dev, flags)) < 0) {
462*491d647aSDavid van Moolenbroek 		(void)sdev_close(dev, FALSE /*may_suspend*/);
463e3b8d4bbSDavid van Moolenbroek 
464e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, r);
465e3b8d4bbSDavid van Moolenbroek 
466e3b8d4bbSDavid van Moolenbroek 		return;
467e3b8d4bbSDavid van Moolenbroek 	}
468e3b8d4bbSDavid van Moolenbroek 
469e3b8d4bbSDavid van Moolenbroek 	/*
470e3b8d4bbSDavid van Moolenbroek 	 * The accept call has succeeded.  Send a reply message with the new
471e3b8d4bbSDavid van Moolenbroek 	 * file descriptor and an address length (which may be zero).
472e3b8d4bbSDavid van Moolenbroek 	 */
473e3b8d4bbSDavid van Moolenbroek 	memset(&m, 0, sizeof(m));
474e3b8d4bbSDavid van Moolenbroek 	m.m_vfs_lc_socklen.len = addr_len;
475e3b8d4bbSDavid van Moolenbroek 
476e3b8d4bbSDavid van Moolenbroek 	reply(&m, rfp->fp_endpoint, r);
477c38dbb97SDavid van Moolenbroek }
478c38dbb97SDavid van Moolenbroek 
479c38dbb97SDavid van Moolenbroek /*
480c38dbb97SDavid van Moolenbroek  * Send a message on a socket.
481c38dbb97SDavid van Moolenbroek  */
482c38dbb97SDavid van Moolenbroek int
do_sendto(void)483c38dbb97SDavid van Moolenbroek do_sendto(void)
484c38dbb97SDavid van Moolenbroek {
485e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
486e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
487c38dbb97SDavid van Moolenbroek 
488e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sendrecv.fd;
489e3b8d4bbSDavid van Moolenbroek 
490e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
491e3b8d4bbSDavid van Moolenbroek 		return r;
492e3b8d4bbSDavid van Moolenbroek 
493e3b8d4bbSDavid van Moolenbroek 	return sdev_readwrite(dev, job_m_in.m_lc_vfs_sendrecv.buf,
494e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.len, 0, 0,
495e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.addr,
496e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.addr_len,
497e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.flags, WRITING, flags, 0);
498c38dbb97SDavid van Moolenbroek }
499c38dbb97SDavid van Moolenbroek 
500c38dbb97SDavid van Moolenbroek /*
501c38dbb97SDavid van Moolenbroek  * Receive a message from a socket.
502c38dbb97SDavid van Moolenbroek  */
503c38dbb97SDavid van Moolenbroek int
do_recvfrom(void)504c38dbb97SDavid van Moolenbroek do_recvfrom(void)
505c38dbb97SDavid van Moolenbroek {
506e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
507e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
508c38dbb97SDavid van Moolenbroek 
509e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sendrecv.fd;
510e3b8d4bbSDavid van Moolenbroek 
511e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
512e3b8d4bbSDavid van Moolenbroek 		return r;
513e3b8d4bbSDavid van Moolenbroek 
514e3b8d4bbSDavid van Moolenbroek 	return sdev_readwrite(dev, job_m_in.m_lc_vfs_sendrecv.buf,
515e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.len, 0, 0,
516e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.addr,
517e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.addr_len,
518e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sendrecv.flags, READING, flags, 0);
519e3b8d4bbSDavid van Moolenbroek }
520e3b8d4bbSDavid van Moolenbroek 
521e3b8d4bbSDavid van Moolenbroek /*
522e3b8d4bbSDavid van Moolenbroek  * Resume a previously suspended recvfrom(2) system call.  This function MUST
523e3b8d4bbSDavid van Moolenbroek  * NOT block its calling thread.
524e3b8d4bbSDavid van Moolenbroek  */
525e3b8d4bbSDavid van Moolenbroek void
resume_recvfrom(struct fproc * rfp,int status,unsigned int addr_len)526e3b8d4bbSDavid van Moolenbroek resume_recvfrom(struct fproc * rfp, int status, unsigned int addr_len)
527e3b8d4bbSDavid van Moolenbroek {
528e3b8d4bbSDavid van Moolenbroek 	message m;
529e3b8d4bbSDavid van Moolenbroek 
530e3b8d4bbSDavid van Moolenbroek 	if (status >= 0) {
531e3b8d4bbSDavid van Moolenbroek 		memset(&m, 0, sizeof(m));
532e3b8d4bbSDavid van Moolenbroek 		m.m_vfs_lc_socklen.len = addr_len;
533e3b8d4bbSDavid van Moolenbroek 
534e3b8d4bbSDavid van Moolenbroek 		reply(&m, rfp->fp_endpoint, status);
535e3b8d4bbSDavid van Moolenbroek 	} else
536e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, status);
537c38dbb97SDavid van Moolenbroek }
538c38dbb97SDavid van Moolenbroek 
539c38dbb97SDavid van Moolenbroek /*
540c38dbb97SDavid van Moolenbroek  * Send or receive a message on a socket using a message structure.
541c38dbb97SDavid van Moolenbroek  */
542c38dbb97SDavid van Moolenbroek int
do_sockmsg(void)543c38dbb97SDavid van Moolenbroek do_sockmsg(void)
544c38dbb97SDavid van Moolenbroek {
545e3b8d4bbSDavid van Moolenbroek 	struct msghdr msg;
546e3b8d4bbSDavid van Moolenbroek 	struct iovec iov;
547e3b8d4bbSDavid van Moolenbroek 	vir_bytes msg_buf, data_buf;
548e3b8d4bbSDavid van Moolenbroek 	size_t data_len;
549e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
550e3b8d4bbSDavid van Moolenbroek 	int r, fd, flags;
551c38dbb97SDavid van Moolenbroek 
552e3b8d4bbSDavid van Moolenbroek 	assert(job_call_nr == VFS_SENDMSG || job_call_nr == VFS_RECVMSG);
553e3b8d4bbSDavid van Moolenbroek 
554e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockmsg.fd;
555e3b8d4bbSDavid van Moolenbroek 	msg_buf = job_m_in.m_lc_vfs_sockmsg.msgbuf;
556e3b8d4bbSDavid van Moolenbroek 
557e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, &flags)) != OK)
558e3b8d4bbSDavid van Moolenbroek 		return r;
559e3b8d4bbSDavid van Moolenbroek 
560e3b8d4bbSDavid van Moolenbroek 	if ((r = sys_datacopy_wrapper(who_e, msg_buf, SELF, (vir_bytes)&msg,
561e3b8d4bbSDavid van Moolenbroek 	    sizeof(msg))) != OK)
562e3b8d4bbSDavid van Moolenbroek 		return r;
563e3b8d4bbSDavid van Moolenbroek 
564e3b8d4bbSDavid van Moolenbroek 	data_buf = 0;
565e3b8d4bbSDavid van Moolenbroek 	data_len = 0;
566e3b8d4bbSDavid van Moolenbroek 	if (msg.msg_iovlen > 0) {
567e3b8d4bbSDavid van Moolenbroek 		/*
568e3b8d4bbSDavid van Moolenbroek 		 * We do not yet support vectors with more than one element;
569e3b8d4bbSDavid van Moolenbroek 		 * for this reason, libc is currently expected to consolidate
570e3b8d4bbSDavid van Moolenbroek 		 * the entire vector into a single element.  Once we do add
571e3b8d4bbSDavid van Moolenbroek 		 * proper vector support, the ABI itself need not be changed.
572e3b8d4bbSDavid van Moolenbroek 		 */
573e3b8d4bbSDavid van Moolenbroek 		if (msg.msg_iovlen > 1)
574e3b8d4bbSDavid van Moolenbroek 			return EMSGSIZE;
575e3b8d4bbSDavid van Moolenbroek 
576e3b8d4bbSDavid van Moolenbroek 		if ((r = sys_datacopy_wrapper(who_e, (vir_bytes)msg.msg_iov,
577e3b8d4bbSDavid van Moolenbroek 		    SELF, (vir_bytes)&iov, sizeof(iov))) != OK)
578e3b8d4bbSDavid van Moolenbroek 			return r;
579e3b8d4bbSDavid van Moolenbroek 
580e3b8d4bbSDavid van Moolenbroek 		if (iov.iov_len > SSIZE_MAX)
581e3b8d4bbSDavid van Moolenbroek 			return EINVAL;
582e3b8d4bbSDavid van Moolenbroek 
583e3b8d4bbSDavid van Moolenbroek 		if (iov.iov_len > 0) {
584e3b8d4bbSDavid van Moolenbroek 			data_buf = (vir_bytes)iov.iov_base;
585e3b8d4bbSDavid van Moolenbroek 			data_len = iov.iov_len;
586e3b8d4bbSDavid van Moolenbroek 		}
587e3b8d4bbSDavid van Moolenbroek 	}
588e3b8d4bbSDavid van Moolenbroek 
589e3b8d4bbSDavid van Moolenbroek 	return sdev_readwrite(dev, data_buf, data_len,
590e3b8d4bbSDavid van Moolenbroek 	    (vir_bytes)msg.msg_control, msg.msg_controllen,
591e3b8d4bbSDavid van Moolenbroek 	    (vir_bytes)msg.msg_name, msg.msg_namelen,
592e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockmsg.flags,
593e3b8d4bbSDavid van Moolenbroek 	    (job_call_nr == VFS_RECVMSG) ? READING : WRITING, flags,
594e3b8d4bbSDavid van Moolenbroek 	    (job_call_nr == VFS_RECVMSG) ? msg_buf : 0);
595e3b8d4bbSDavid van Moolenbroek }
596e3b8d4bbSDavid van Moolenbroek 
597e3b8d4bbSDavid van Moolenbroek /*
598e3b8d4bbSDavid van Moolenbroek  * Resume a previously suspended recvmsg(2) system call.  The 'status'
599e3b8d4bbSDavid van Moolenbroek  * parameter contains either the number of data bytes received or a negative
600e3b8d4bbSDavid van Moolenbroek  * error code.  The 'msg_buf' parameter contains the user address of the msghdr
601e3b8d4bbSDavid van Moolenbroek  * structure.  If a failure occurs in this function, the received data
602e3b8d4bbSDavid van Moolenbroek  * (including, in the worst case, references to received file descriptors) will
603e3b8d4bbSDavid van Moolenbroek  * be lost - while seriously ugly, this is always the calling process's fault,
604e3b8d4bbSDavid van Moolenbroek  * extremely hard to deal with, and on par with current behavior in other
605e3b8d4bbSDavid van Moolenbroek  * operating systems.  This function MUST NOT block its calling thread.
606e3b8d4bbSDavid van Moolenbroek  */
607e3b8d4bbSDavid van Moolenbroek void
resume_recvmsg(struct fproc * rfp,int status,unsigned int ctl_len,unsigned int addr_len,int flags,vir_bytes msg_buf)608e3b8d4bbSDavid van Moolenbroek resume_recvmsg(struct fproc * rfp, int status, unsigned int ctl_len,
609e3b8d4bbSDavid van Moolenbroek 	unsigned int addr_len, int flags, vir_bytes msg_buf)
610e3b8d4bbSDavid van Moolenbroek {
611e3b8d4bbSDavid van Moolenbroek 	struct msghdr msg;
612e3b8d4bbSDavid van Moolenbroek 	int r;
613e3b8d4bbSDavid van Moolenbroek 
614e3b8d4bbSDavid van Moolenbroek 	if (status < 0) {
615e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, status);
616e3b8d4bbSDavid van Moolenbroek 
617e3b8d4bbSDavid van Moolenbroek 		return;
618e3b8d4bbSDavid van Moolenbroek 	}
619e3b8d4bbSDavid van Moolenbroek 
620e3b8d4bbSDavid van Moolenbroek 	/*
621e3b8d4bbSDavid van Moolenbroek 	 * Unfortunately, we now need to update a subset of the fields of the
622e3b8d4bbSDavid van Moolenbroek 	 * msghdr structure.  We can 1) copy in the entire structure for the
623e3b8d4bbSDavid van Moolenbroek 	 * second time, modify some fields, and copy it out in its entirety
624e3b8d4bbSDavid van Moolenbroek 	 * again, 2) copy out individual fields that have been changed, 3) save
625e3b8d4bbSDavid van Moolenbroek 	 * a copy of the original structure somewhere.  The third option is the
626e3b8d4bbSDavid van Moolenbroek 	 * most efficient, but would increase the fproc structure size by quite
627e3b8d4bbSDavid van Moolenbroek 	 * a bit.  The main difference between the first and second options is
628e3b8d4bbSDavid van Moolenbroek 	 * the number of kernel calls; we choose to use the first option.
629e3b8d4bbSDavid van Moolenbroek 	 */
630e3b8d4bbSDavid van Moolenbroek 	if ((r = sys_datacopy_wrapper(rfp->fp_endpoint, msg_buf, SELF,
631e3b8d4bbSDavid van Moolenbroek 	    (vir_bytes)&msg, sizeof(msg))) != OK) {
632e3b8d4bbSDavid van Moolenbroek 		/* We copied it in before, how could it fail now? */
633e3b8d4bbSDavid van Moolenbroek 		printf("VFS: resume_recvmsg cannot copy in msghdr? (%d)\n", r);
634e3b8d4bbSDavid van Moolenbroek 
635e3b8d4bbSDavid van Moolenbroek 		replycode(rfp->fp_endpoint, r);
636e3b8d4bbSDavid van Moolenbroek 
637e3b8d4bbSDavid van Moolenbroek 		return;
638e3b8d4bbSDavid van Moolenbroek 	}
639e3b8d4bbSDavid van Moolenbroek 
640e3b8d4bbSDavid van Moolenbroek 	/* Modify and copy out the structure, and wake up the caller. */
641e3b8d4bbSDavid van Moolenbroek 	msg.msg_controllen = ctl_len;
642e3b8d4bbSDavid van Moolenbroek 	msg.msg_flags = flags;
643e3b8d4bbSDavid van Moolenbroek 	if (addr_len > 0)
644e3b8d4bbSDavid van Moolenbroek 		msg.msg_namelen = addr_len;
645e3b8d4bbSDavid van Moolenbroek 
646e3b8d4bbSDavid van Moolenbroek 	if ((r = sys_datacopy_wrapper(SELF, (vir_bytes)&msg, rfp->fp_endpoint,
647e3b8d4bbSDavid van Moolenbroek 	    msg_buf, sizeof(msg))) != OK)
648e3b8d4bbSDavid van Moolenbroek 		status = r;
649e3b8d4bbSDavid van Moolenbroek 
650e3b8d4bbSDavid van Moolenbroek 	replycode(rfp->fp_endpoint, status);
651c38dbb97SDavid van Moolenbroek }
652c38dbb97SDavid van Moolenbroek 
653c38dbb97SDavid van Moolenbroek /*
654c38dbb97SDavid van Moolenbroek  * Set socket options.
655c38dbb97SDavid van Moolenbroek  */
656c38dbb97SDavid van Moolenbroek int
do_setsockopt(void)657c38dbb97SDavid van Moolenbroek do_setsockopt(void)
658c38dbb97SDavid van Moolenbroek {
659e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
660e3b8d4bbSDavid van Moolenbroek 	int r, fd;
661c38dbb97SDavid van Moolenbroek 
662e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockopt.fd;
663e3b8d4bbSDavid van Moolenbroek 
664e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
665e3b8d4bbSDavid van Moolenbroek 		return r;
666e3b8d4bbSDavid van Moolenbroek 
667e3b8d4bbSDavid van Moolenbroek 	return sdev_setsockopt(dev, job_m_in.m_lc_vfs_sockopt.level,
668e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockopt.name, job_m_in.m_lc_vfs_sockopt.buf,
669e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockopt.len);
670c38dbb97SDavid van Moolenbroek }
671c38dbb97SDavid van Moolenbroek 
672c38dbb97SDavid van Moolenbroek /*
673c38dbb97SDavid van Moolenbroek  * Get socket options.
674c38dbb97SDavid van Moolenbroek  */
675c38dbb97SDavid van Moolenbroek int
do_getsockopt(void)676c38dbb97SDavid van Moolenbroek do_getsockopt(void)
677c38dbb97SDavid van Moolenbroek {
678e3b8d4bbSDavid van Moolenbroek 	unsigned int len;
679e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
680e3b8d4bbSDavid van Moolenbroek 	int r, fd;
681c38dbb97SDavid van Moolenbroek 
682e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockopt.fd;
683e3b8d4bbSDavid van Moolenbroek 	len = job_m_in.m_lc_vfs_sockopt.len;
684e3b8d4bbSDavid van Moolenbroek 
685e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
686e3b8d4bbSDavid van Moolenbroek 		return r;
687e3b8d4bbSDavid van Moolenbroek 
688e3b8d4bbSDavid van Moolenbroek 	r = sdev_getsockopt(dev, job_m_in.m_lc_vfs_sockopt.level,
689e3b8d4bbSDavid van Moolenbroek 	    job_m_in.m_lc_vfs_sockopt.name, job_m_in.m_lc_vfs_sockopt.buf,
690e3b8d4bbSDavid van Moolenbroek 	    &len);
691e3b8d4bbSDavid van Moolenbroek 
692e3b8d4bbSDavid van Moolenbroek 	if (r == OK)
693e3b8d4bbSDavid van Moolenbroek 		job_m_out.m_vfs_lc_socklen.len = len;
694e3b8d4bbSDavid van Moolenbroek 	return r;
695c38dbb97SDavid van Moolenbroek }
696c38dbb97SDavid van Moolenbroek 
697c38dbb97SDavid van Moolenbroek /*
698c38dbb97SDavid van Moolenbroek  * Get the local address of a socket.
699c38dbb97SDavid van Moolenbroek  */
700c38dbb97SDavid van Moolenbroek int
do_getsockname(void)701c38dbb97SDavid van Moolenbroek do_getsockname(void)
702c38dbb97SDavid van Moolenbroek {
703e3b8d4bbSDavid van Moolenbroek 	unsigned int len;
704e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
705e3b8d4bbSDavid van Moolenbroek 	int r, fd;
706c38dbb97SDavid van Moolenbroek 
707e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockaddr.fd;
708e3b8d4bbSDavid van Moolenbroek 	len = job_m_in.m_lc_vfs_sockaddr.addr_len;
709e3b8d4bbSDavid van Moolenbroek 
710e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
711e3b8d4bbSDavid van Moolenbroek 		return r;
712e3b8d4bbSDavid van Moolenbroek 
713e3b8d4bbSDavid van Moolenbroek 	r = sdev_getsockname(dev, job_m_in.m_lc_vfs_sockaddr.addr, &len);
714e3b8d4bbSDavid van Moolenbroek 
715e3b8d4bbSDavid van Moolenbroek 	if (r == OK)
716e3b8d4bbSDavid van Moolenbroek 		job_m_out.m_vfs_lc_socklen.len = len;
717e3b8d4bbSDavid van Moolenbroek 	return r;
718c38dbb97SDavid van Moolenbroek }
719c38dbb97SDavid van Moolenbroek 
720c38dbb97SDavid van Moolenbroek /*
721c38dbb97SDavid van Moolenbroek  * Get the remote address of a socket.
722c38dbb97SDavid van Moolenbroek  */
723c38dbb97SDavid van Moolenbroek int
do_getpeername(void)724c38dbb97SDavid van Moolenbroek do_getpeername(void)
725c38dbb97SDavid van Moolenbroek {
726e3b8d4bbSDavid van Moolenbroek 	unsigned int len;
727e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
728e3b8d4bbSDavid van Moolenbroek 	int r, fd;
729c38dbb97SDavid van Moolenbroek 
730e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_sockaddr.fd;
731e3b8d4bbSDavid van Moolenbroek 	len = job_m_in.m_lc_vfs_sockaddr.addr_len;
732e3b8d4bbSDavid van Moolenbroek 
733e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
734e3b8d4bbSDavid van Moolenbroek 		return r;
735e3b8d4bbSDavid van Moolenbroek 
736e3b8d4bbSDavid van Moolenbroek 	r = sdev_getpeername(dev, job_m_in.m_lc_vfs_sockaddr.addr, &len);
737e3b8d4bbSDavid van Moolenbroek 
738e3b8d4bbSDavid van Moolenbroek 	if (r == OK)
739e3b8d4bbSDavid van Moolenbroek 		job_m_out.m_vfs_lc_socklen.len = len;
740e3b8d4bbSDavid van Moolenbroek 	return r;
741c38dbb97SDavid van Moolenbroek }
742c38dbb97SDavid van Moolenbroek 
743c38dbb97SDavid van Moolenbroek /*
744c38dbb97SDavid van Moolenbroek  * Shut down socket send and receive operations.
745c38dbb97SDavid van Moolenbroek  */
746c38dbb97SDavid van Moolenbroek int
do_shutdown(void)747c38dbb97SDavid van Moolenbroek do_shutdown(void)
748c38dbb97SDavid van Moolenbroek {
749e3b8d4bbSDavid van Moolenbroek 	dev_t dev;
750e3b8d4bbSDavid van Moolenbroek 	int r, fd, how;
751c38dbb97SDavid van Moolenbroek 
752e3b8d4bbSDavid van Moolenbroek 	fd = job_m_in.m_lc_vfs_shutdown.fd;
753e3b8d4bbSDavid van Moolenbroek 	how = job_m_in.m_lc_vfs_shutdown.how;
754e3b8d4bbSDavid van Moolenbroek 
755e3b8d4bbSDavid van Moolenbroek 	if ((r = get_sock(fd, &dev, NULL)) != OK)
756e3b8d4bbSDavid van Moolenbroek 		return r;
757e3b8d4bbSDavid van Moolenbroek 
758e3b8d4bbSDavid van Moolenbroek 	if (how != SHUT_RD && how != SHUT_WR && how != SHUT_RDWR)
759e3b8d4bbSDavid van Moolenbroek 		return EINVAL;
760e3b8d4bbSDavid van Moolenbroek 
761e3b8d4bbSDavid van Moolenbroek 	return sdev_shutdown(dev, how);
762c38dbb97SDavid van Moolenbroek }
763