Exemple #1
0
int do_getsockname(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_getsockname() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	/* Unconditionally send the address we have assigned to this socket.
	 * The POSIX standard doesn't say what to do if the address
	 * hasn't been set. If the address isn't currently set, then
	 * the user will get NULL bytes. Note: libc depends on this
	 * behavior.
	 */
	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr),
		sizeof(struct sockaddr_un));

	return rc ? EIO : OK;
}
Exemple #2
0
int do_shutdown(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc, how;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_shutdown() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].type != SOCK_STREAM &&
			uds_fd_table[minor].type != SOCK_SEQPACKET) {

		/* socket must be a connection oriented socket */
		return EINVAL;
	}

	if (uds_fd_table[minor].peer == -1) {
		/* shutdown(2) is only valid for connected sockets */
		if (uds_fd_table[minor].err == ECONNRESET) {
			return ECONNRESET;
		} else {
			return ENOTCONN;
		}
	}

	/* get the 'how' parameter from the process */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
			(vir_bytes) 0, (vir_bytes) &how, sizeof(int));

	if (rc != OK) {
		return EIO;
	}

	switch (how) {
		case SHUT_RD:
			/* take away read permission */
			uds_fd_table[minor].mode &= ~S_IRUSR;
			break;

		case SHUT_WR:
			/* take away write permission */
			uds_fd_table[minor].mode &= ~S_IWUSR;
			break;

		case SHUT_RDWR:
			/* completely shutdown */
			uds_fd_table[minor].mode = 0;
			break;

		default:
			/* the 'how' parameter is invalid */
			return EINVAL;
	}

	return OK;
}
Exemple #3
0
int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	size_t rcvbuf;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n",
				uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);


	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
				(vir_bytes) 0, (vir_bytes) &rcvbuf,
				sizeof(size_t), D);

	if (rc != OK) {
		return EIO;
	}

	if (rcvbuf > PIPE_BUF) {
		/* The send buffer is limited to 32K at the moment. */
		return ENOSYS;
	}

	/* There is no way to reduce the send buffer, do we have to
	 * let this call fail for smaller buffers?
	 */
	return OK;
}
Exemple #4
0
int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n",
				uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].type == -1) {

		/* the type hasn't been set yet. instead of returning an
		 * invalid type, we fail with EINVAL
		 */
		return EINVAL;
	}

	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type),
		sizeof(int));

	return rc ? EIO : OK;
}
Exemple #5
0
int do_socket(message *dev_m_in, message *dev_m_out)
{
	int rc;
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_socket() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
#endif

	minor = uds_minor(dev_m_in);

	/* see if this socket already has a type */
	if (uds_fd_table[minor].type != -1) {
		/* socket type can only be set once */
		return EINVAL;
	}

	/* get the requested type */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type),
		sizeof(int));

	if (rc != OK) {

		/* something went wrong and we couldn't get the type */
		return EIO;
	}

	/* validate the type */
	switch (uds_fd_table[minor].type) {
		case SOCK_STREAM:
		case SOCK_DGRAM:
		case SOCK_SEQPACKET:

			/* the type is one of the 3 valid socket types */
			return OK;

		default:

			/* if the type isn't one of the 3 valid socket
			 * types, then it must be invalid.
			 */

			/* set the type back to '-1' (no type set) */
			uds_fd_table[minor].type = -1;

			return EINVAL;
	}
}
Exemple #6
0
PUBLIC int uds_write(message *dev_m_in, message *dev_m_out)
{
	int bytes;
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, 
							dev_m_in->POSITION);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {

		/* attempted to close a socket that hasn't been opened -- 
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->USER_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);

		return EINVAL;
	}

	/* track the system call we are performing in case it gets cancelled */
	uds_fd_table[minor].call_nr = dev_m_in->m_type;
	uds_fd_table[minor].ioctl = 0;
	uds_fd_table[minor].syscall_done = 0;

	/* Update the process endpoint. */
	uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 0;

	/* save I/O Grant info */
	uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
	uds_fd_table[minor].io_gr_size = dev_m_in->COUNT;

	bytes = uds_perform_write(minor, dev_m_in->m_source,
					uds_fd_table[minor].io_gr_size, 0);

	uds_set_reply(dev_m_out, TASK_REPLY, 
			uds_fd_table[minor].endpoint, 
			uds_fd_table[minor].io_gr,
			bytes);

	return bytes;
}
Exemple #7
0
int perform_connection(message *dev_m_in, message *dev_m_out,
			struct sockaddr_un *addr, int minorx, int minory)
{
	/* there are several places were a connection is established. */
	/* accept(2), connect(2), uds_status(2), socketpair(2)        */
	/* This is a helper function to make sure it is done in the   */
	/* same way in each place with the same validation checks.    */

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] perform_connection() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	/* only connection oriented types are acceptable and only like
	 * types can connect to each other
	 */
	if ((uds_fd_table[minorx].type != SOCK_SEQPACKET &&
		uds_fd_table[minorx].type != SOCK_STREAM) ||
		uds_fd_table[minorx].type != uds_fd_table[minory].type) {

		/* sockets are not in a valid state */
		return EINVAL;
	}

	/* connect the pair of sockets */
	uds_fd_table[minorx].peer = minory;
	uds_fd_table[minory].peer = minorx;

	/* Set the address of both sockets */
	memcpy(&(uds_fd_table[minorx].addr), addr, sizeof(struct sockaddr_un));
	memcpy(&(uds_fd_table[minory].addr), addr, sizeof(struct sockaddr_un));

	return OK;
}
Exemple #8
0
int do_getsockopt_peercred_old(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int peer_minor;
	int rc;
	struct ucred cred;
	struct ucred_old cred_old;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].peer == -1) {

		if (uds_fd_table[minor].err == ECONNRESET) {
			uds_fd_table[minor].err = 0;

			return ECONNRESET;
		} else {
			return ENOTCONN;
		}
	}

	peer_minor = uds_fd_table[minor].peer;

	/* obtain the peer's credentials */
	rc = getnucred(uds_fd_table[peer_minor].owner, &cred);
	if (rc == -1) {
		/* likely error: invalid endpoint / proc doesn't exist */
		return errno;
	}

	/* copy to old structure */
	cred_old.pid = cred.pid;
	cred_old.uid = (short) cred.uid;
	cred_old.gid = (char) cred.gid;

	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &cred_old, sizeof(struct ucred_old),
		D);

	return rc ? EIO : OK;
}
Exemple #9
0
int do_socketpair(message *dev_m_in, message *dev_m_out)
{
	int rc;
	dev_t minorin;
	int minorx, minory;
	struct sockaddr_un addr;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_socketpair() call_count=%d\n",
				uds_minor(dev_m_in), ++call_count);
#endif

	/* first ioctl param is the first socket */
	minorx = uds_minor(dev_m_in);

	/* third ioctl param is the minor number of the second socket */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
			(vir_bytes) 0, (vir_bytes) &minorin, sizeof(dev_t));

	if (rc != OK) {
		return EIO;
	}

	minory = minor(minorin);

#if DEBUG == 1
	printf("socketpair() %d - %d\n", minorx, minory);
#endif

	/* security check - both sockets must have the same endpoint (owner) */
	if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) {

		/* we won't allow you to magically connect your socket to
		 * someone elses socket
		 */
		return EPERM;
	}

	addr.sun_family = AF_UNIX;
	addr.sun_path[0] = 'X';
	addr.sun_path[1] = '\0';

	uds_fd_table[minorx].syscall_done = 1;
	return perform_connection(dev_m_in, dev_m_out, &addr, minorx, minory);
}
Exemple #10
0
int do_sendto(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	struct sockaddr_un addr;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_sendto() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].type != SOCK_DGRAM) {
		/* This IOCTL is only for SOCK_DGRAM sockets */
		return EINVAL;
	}

	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un),
		D);

	if (rc != OK) {
		return EIO;
	}

	/* do some basic sanity checks on the address */
	if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') {
		/* bad address */
		return EINVAL;
	}

	rc = check_perms(minor, &addr);
	if (rc != OK) {
		return rc;
	}

	memcpy(&(uds_fd_table[minor].target), &addr,
					sizeof(struct sockaddr_un));

	return OK;
}
Exemple #11
0
int do_recvfrom(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_recvfrom() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source),
		sizeof(struct sockaddr_un));

	return rc ? EIO : OK;
}
Exemple #12
0
int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	size_t rcvbuf = PIPE_BUF;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n",
				uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &(rcvbuf),
		sizeof(size_t), D);

	return rc ? EIO : OK;
}
Exemple #13
0
int do_getpeername(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_getpeername() call_count=%d\n",
				uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	/* check that the socket is connected with a valid peer */
	if (uds_fd_table[minor].peer != -1) {
		int peer_minor;

		peer_minor = uds_fd_table[minor].peer;

		/* copy the address from the peer */
		rc = sys_safecopyto(VFS_PROC_NR,
			(cp_grant_id_t) dev_m_in->IO_GRANT, (vir_bytes) 0,
			(vir_bytes) &(uds_fd_table[peer_minor].addr),
			sizeof(struct sockaddr_un));

		return rc ? EIO : OK;
	} else {
		if (uds_fd_table[minor].err == ECONNRESET) {
			uds_fd_table[minor].err = 0;

			return ECONNRESET;
		} else {
			return ENOTCONN;
		}
	}
}
Exemple #14
0
PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out)
{
	int i, j;
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x\n", dev_m_in->IO_ENDPT);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {

		/* attempted to close a socket that hasn't been opened --
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);

		return EINVAL;
	}

	/* Update the process endpoint. */
	uds_fd_table[minor].endpoint = dev_m_in->IO_ENDPT;

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 0;

	/* the system call was cancelled, so if the socket was suspended
	 * (which is likely the case), then it is not suspended anymore.
	 */
	uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;

	/* If there is a system call and it isn't complete, roll back */
	if (uds_fd_table[minor].call_nr && !uds_fd_table[minor].syscall_done) {


		if  (uds_fd_table[minor].call_nr == DEV_IOCTL_S) {

			switch (uds_fd_table[minor].ioctl) {

				case NWIOSUDSACCEPT:	/* accept() */

					/* partial accept() only changes 
					 * uds_fd_table[minorparent].child
					 */

					for (i = 0; i < NR_FDS; i++) {
						if (uds_fd_table[i].child ==
							minor) {
							
						uds_fd_table[i].child = -1;

						}
					}

					break;

				case NWIOSUDSCONN:	/* connect() */

					/* partial connect() sets addr 
					 * and adds minor to server backlog
					 */

					for (i = 0; i < NR_FDS; i++) {

						/* find a socket that is in
						 * use.
						 */
						if (uds_fd_table[i].state ==
							UDS_INUSE) {

							/* see if minor is in
							 * the backlog 
							 */
			for (j = 0; j < uds_fd_table[i].backlog_size; j++) {

				if (uds_fd_table[i].backlog[j] == minor) {

					/* remove from backlog */
					uds_fd_table[i].backlog[j] = -1;
				}
			}

						}
					}

					/* clear the address */
					memset(&(uds_fd_table[minor].addr),
						'\0',
						sizeof(struct sockaddr_un));

					break;

				case NWIOSUDSTADDR:	/* sendto() */
				case NWIOSUDSADDR:	/* bind() */
				case NWIOGUDSADDR:	/* getsockname() */
				case NWIOGUDSPADDR:	/* getpeername() */
				case NWIOSUDSTYPE:	/* socket() */
				case NWIOSUDSBLOG:	/* listen() */
				case NWIOSUDSSHUT:	/* shutdown() */
				case NWIOSUDSPAIR:	/* socketpair() */
				case NWIOGUDSSOTYPE:	/* SO_TYPE */
				case NWIOGUDSPEERCRED:	/* SO_PEERCRED */
				default:
					/* these are atomic, never suspend,
					 * and can't be cancelled once called
					 */
					break;
			}

		}

		/* DEV_READ_S or DEV_WRITE_S don't need to do anything 
		 * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT, 
		 * DEV_CLOSE are atomic, never suspend, and can't 
		 * be cancelled once called.
		 */

		uds_fd_table[minor].syscall_done = 1;
	}


	uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
			(cp_grant_id_t) dev_m_in->IO_GRANT, EINTR);

	return EINTR;
}
Exemple #15
0
int do_bind(message *dev_m_in, message *dev_m_out)
{
	int minor;
	struct sockaddr_un addr;
	int rc, i;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_bind() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
#endif

	minor = uds_minor(dev_m_in);

	if ((uds_fd_table[minor].type == -1) ||
		(uds_fd_table[minor].addr.sun_family == AF_UNIX &&
		uds_fd_table[minor].type != SOCK_DGRAM)) {

		/* the type hasn't been set by do_socket() yet OR attempting
		 * to re-bind() a non-SOCK_DGRAM socket
		 */
		return EINVAL;
	}

	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un));

	if (rc != OK) {
		return EIO;
	}

	/* do some basic sanity checks on the address */
	if (addr.sun_family != AF_UNIX) {

		/* bad family */
		return EAFNOSUPPORT;
	}

	if (addr.sun_path[0] == '\0') {

		/* bad address */
		return ENOENT;
	}

	rc = check_perms(minor, &addr);
	if (rc != OK) {
		/* permission denied, socket file doesn't exist, etc. */
		return rc;
	}

	/* make sure the address isn't already in use by another socket. */
	for (i = 0; i < NR_FDS; i++) {
		if ((uds_fd_table[i].addr.sun_family == AF_UNIX) &&
			!strncmp(addr.sun_path,
			uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {

			/* another socket is bound to this sun_path */
			return EADDRINUSE;
		}
	}

	/* looks good, perform the bind() */
	memcpy(&(uds_fd_table[minor].addr), &addr, sizeof(struct sockaddr_un));

	return OK;
}
Exemple #16
0
PUBLIC int uds_close(message *dev_m_in, message *dev_m_out)
{
	int minor;
	message fs_m_in, fs_m_out;
	int rc;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x\n", dev_m_in->IO_ENDPT);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {
		/* attempted to close a socket that hasn't been opened -- 
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
			(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
		return EINVAL;
	}

	/* no need to track the syscall in case of cancellation. close() is
	 * atomic and can't be cancelled. no need to update the endpoint here,
	 * we won't be needing it to kill the socket
	 */

	/* if the socket is connected, disconnect it */
	if (uds_fd_table[minor].peer != -1) {

		/* set peer of this peer to -1 */
		uds_fd_table[uds_fd_table[minor].peer].peer = -1;

		/* error to pass to peer */
		uds_fd_table[uds_fd_table[minor].peer].err = ECONNRESET;

		/* if peer was blocked on I/O revive peer */
		if (uds_fd_table[uds_fd_table[minor].peer].suspended) {

			int peer = uds_fd_table[minor].peer;

			uds_fd_table[peer].ready_to_revive = 1;
			notify(dev_m_in->m_source);
		}
	}

	if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
		clear_fds(minor, &(uds_fd_table[minor].ancillary_data));
	}

	/* Prepare Request to the FS side of PFS */

	fs_m_in.m_type = REQ_PUTNODE;
	fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr;
	fs_m_in.REQ_COUNT = 1;

	/* set the socket back to its original UDS_FREE state */
	memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));

	/* Request the removal of the inode from the pipe file system */

	rc = fs_putnode(&fs_m_in, &fs_m_out);
	if (rc != OK) {
		perror("fs_putnode");
		/* likely error: get_block() failed */
		return rc;
	}

	uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
			(cp_grant_id_t) dev_m_in->IO_GRANT, OK);
	return OK;
}
Exemple #17
0
int do_listen(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	int backlog_size;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_listen() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
#endif

	minor = uds_minor(dev_m_in);

	/* ensure the socket has a type and is bound */
	if (uds_fd_table[minor].type == -1 ||
		uds_fd_table[minor].addr.sun_family != AF_UNIX) {

		/* probably trying to call listen() before bind() */
		return EINVAL;
	}

	/* the two supported types for listen(2) are SOCK_STREAM and
	 * SOCK_SEQPACKET
	 */
	if (uds_fd_table[minor].type != SOCK_STREAM &&
			uds_fd_table[minor].type != SOCK_SEQPACKET) {

		/* probably trying to call listen() with a SOCK_DGRAM */
		return EOPNOTSUPP;
	}

	/* The POSIX standard doesn't say what to do if listen() has
	 * already been called. Well, there isn't an errno. we silently
	 * let it happen, but if listen() has already been called, we
	 * don't allow the backlog to shrink
	 */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &backlog_size, sizeof(int));

	if (rc != OK) {
		return EIO;
	}

	if (uds_fd_table[minor].listening == 0) {

		/* See if backlog_size is between 0 and UDS_SOMAXCONN */
		if (backlog_size >= 0 && backlog_size < UDS_SOMAXCONN) {

			/* use the user provided backlog_size */
			uds_fd_table[minor].backlog_size = backlog_size;

		} else {

			/* the user gave an invalid size, use
			 * UDS_SOMAXCONN instead
			 */
			uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
		}
	} else {

		/* See if the user is trying to expand the backlog_size */
		if (backlog_size > uds_fd_table[minor].backlog_size &&
			backlog_size < UDS_SOMAXCONN) {

			/* expand backlog_size */
			uds_fd_table[minor].backlog_size = backlog_size;
		}

		/* Don't let the user shrink the backlog_size (we might
		 * have clients waiting in those slots
		 */
	}

	/* perform listen(2) */
	uds_fd_table[minor].listening = 1;

	return OK;
}
Exemple #18
0
PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out)
{
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
 	printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, 
							dev_m_in->POSITION);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {

		/* attempted to close a socket that hasn't been opened --
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);

		return EINVAL;
	}

	/* track the system call we are performing in case it gets cancelled */
	uds_fd_table[minor].call_nr = dev_m_in->m_type;
	uds_fd_table[minor].ioctl = dev_m_in->COUNT;
	uds_fd_table[minor].syscall_done = 0;

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 0;

	/* update the owner endpoint - yes it's really stored in POSITION */
	uds_fd_table[minor].owner = dev_m_in->POSITION;

	switch (dev_m_in->COUNT) {	/* Handle the ioctl(2) command */

		case NWIOSUDSCONN:

			/* connect to a listening socket -- connect() */
			return do_connect(dev_m_in, dev_m_out);

		case NWIOSUDSACCEPT:

			/* accept an incoming connection -- accept() */
			return do_accept(dev_m_in, dev_m_out);

		case NWIOSUDSBLOG:

			/* set the backlog_size and put the socket into the
			 * listening state -- listen()
			 */
			return do_listen(dev_m_in, dev_m_out);

		case NWIOSUDSTYPE:

			/* set the type for this socket (i.e. 
			 * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
			 */
			return do_socket(dev_m_in, dev_m_out);

		case NWIOSUDSADDR:

			/* set the address for this socket -- bind() */
			return do_bind(dev_m_in, dev_m_out);

		case NWIOGUDSADDR:

			/* get the address for this socket -- getsockname() */
			return do_getsockname(dev_m_in, dev_m_out);

		case NWIOGUDSPADDR:

			/* get the address for the peer -- getpeername() */
			return do_getpeername(dev_m_in, dev_m_out);

		case NWIOSUDSSHUT:

			/* shutdown a socket for reading, writing, or 
			 * both -- shutdown()
			 */
			return do_shutdown(dev_m_in, dev_m_out);

		case NWIOSUDSPAIR:

			/* connect two sockets -- socketpair() */
			return do_socketpair(dev_m_in, dev_m_out);

		case NWIOGUDSSOTYPE:

			/* get socket type -- getsockopt(SO_TYPE) */
			return do_getsockopt_sotype(dev_m_in, dev_m_out);

		case NWIOGUDSPEERCRED:

			/* get peer endpoint -- getsockopt(SO_PEERCRED) */
			return do_getsockopt_peercred(dev_m_in, dev_m_out);

		case NWIOSUDSTADDR:

			/* set target address -- sendto() */
			return do_sendto(dev_m_in, dev_m_out);

		case NWIOGUDSFADDR:

			/* get from address -- recvfrom() */
			return do_recvfrom(dev_m_in, dev_m_out);

		case NWIOGUDSSNDBUF:

			/* get the send buffer size -- getsockopt(SO_SNDBUF) */
			return do_getsockopt_sndbuf(dev_m_in, dev_m_out);

		case NWIOSUDSSNDBUF:

			/* set the send buffer size -- setsockopt(SO_SNDBUF) */
			return do_setsockopt_sndbuf(dev_m_in, dev_m_out);

		case NWIOGUDSRCVBUF:

			/* get the send buffer size -- getsockopt(SO_SNDBUF) */
			return do_getsockopt_rcvbuf(dev_m_in, dev_m_out);

		case NWIOSUDSRCVBUF:

			/* set the send buffer size -- setsockopt(SO_SNDBUF) */
			return do_setsockopt_rcvbuf(dev_m_in, dev_m_out);

		case NWIOSUDSCTRL:

			/* set the control data -- sendmsg() */
			return do_sendmsg(dev_m_in, dev_m_out);

		case NWIOGUDSCTRL:

			/* set the control data -- recvmsg() */
			return do_recvmsg(dev_m_in, dev_m_out);

		default:

			/* the IOCTL command is not valid for /dev/uds --
			 * this happens a lot and is normal. a lot of 
			 * libc functions determine the socket type with 
			 * IOCTLs. Any not for us simply get a EBADIOCTL
			 * response.
			 */
			uds_fd_table[minor].syscall_done = 1;
			uds_set_reply(dev_m_out, TASK_REPLY,
					dev_m_in->IO_ENDPT, 
					(cp_grant_id_t) dev_m_in->IO_GRANT,
					EBADIOCTL);

			return EBADIOCTL;
	}
}
Exemple #19
0
int do_accept(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int minorparent; /* minor number of parent (server) */
	int minorpeer;
	int rc, i;
	struct sockaddr_un addr;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_accept() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	/* Somewhat weird logic is used in this function, so here's an
	 * overview... The minor number is the server's client socket
	 * (the socket to be returned by accept()). The data waiting
	 * for us in the IO Grant is the address that the server is
	 * listening on. This function uses the address to find the
	 * server's descriptor. From there we can perform the
	 * connection or suspend and wait for a connect().
	 */

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].type != -1) {
		/* this IOCTL must be called on a 'fresh' socket */
		return EINVAL;
	}

	/* Get the server's address */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un));

	if (rc != OK) {
		return EIO;
	}

	/* locate server socket */
	rc = -1; /* to trap error */

	for (i = 0; i < NR_FDS; i++) {

		if (uds_fd_table[i].addr.sun_family == AF_UNIX &&
				!strncmp(addr.sun_path,
				uds_fd_table[i].addr.sun_path,
				UNIX_PATH_MAX) &&
				uds_fd_table[i].listening == 1) {

			rc = 0;
			break;
		}
	}

	if (rc == -1) {
		/* there is no server listening on addr. Maybe someone
		 * screwed up the ioctl()?
		 */
		return EINVAL;
	}

	minorparent = i; /* parent */

	/* we are the parent's child */
	uds_fd_table[minorparent].child = minor;

	/* the peer has the same type as the parent. we need to be that
	 * type too.
	 */
	uds_fd_table[minor].type = uds_fd_table[minorparent].type;

	/* locate peer to accept in the parent's backlog */
	minorpeer = -1; /* to trap error */
	for (i = 0; i < uds_fd_table[minorparent].backlog_size; i++) {
		if (uds_fd_table[minorparent].backlog[i] != -1) {
			minorpeer = uds_fd_table[minorparent].backlog[i];
			uds_fd_table[minorparent].backlog[i] = -1;
			rc = 0;
			break;
		}
	}

	if (minorpeer == -1) {

#if DEBUG == 1
		printf("(uds) [%d] {do_accept} suspend\n", minor);
#endif

		/* there are no peers in the backlog, suspend and wait
		 * for some to show up
		 */
		uds_fd_table[minor].suspended = UDS_SUSPENDED_ACCEPT;

		return SUSPEND;
	}

#if DEBUG == 1
	printf("(uds) [%d] connecting to %d -- parent is %d\n", minor,
						minorpeer, minorparent);
#endif

	rc = perform_connection(dev_m_in, dev_m_out, &addr, minor, minorpeer);
	if (rc != OK) {
#if DEBUG == 1
		printf("(uds) [%d] {do_accept} connection not performed\n",
								minor);
#endif
		return rc;
	}

	uds_fd_table[minorparent].child = -1;

	/* if peer is blocked on connect() revive peer */
	if (uds_fd_table[minorpeer].suspended) {
#if DEBUG == 1
		printf("(uds) [%d] {do_accept} revive %d\n", minor,
								minorpeer);
#endif
		uds_fd_table[minorpeer].ready_to_revive = 1;
		uds_unsuspend(dev_m_in->m_source, minorpeer);
	}

	return OK;
}
Exemple #20
0
PUBLIC int uds_select(message *dev_m_in, message *dev_m_out)
{
	int i, bytes;
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x\n", dev_m_in->IO_ENDPT);
#endif

	minor = uds_minor(dev_m_in);

	if (uds_fd_table[minor].state != UDS_INUSE) {

		/* attempted to close a socket that hasn't been opened -- 
		 * something is very wrong :(
		 */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);

		return EINVAL;
	}

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 1;
	uds_fd_table[minor].select_proc = dev_m_in->m_source;

	/* track the system call we are performing in case it gets cancelled */
	uds_fd_table[minor].call_nr = dev_m_in->m_type;
	uds_fd_table[minor].ioctl = 0;
	uds_fd_table[minor].syscall_done = 0;

	/* Can't update the process endpoint here, no info.  */

	uds_fd_table[minor].sel_ops_in = dev_m_in->IO_ENDPT;
	uds_fd_table[minor].sel_ops_out = 0;

	/* check if there is data available to read */
	bytes = uds_perform_read(minor, dev_m_in->m_source, 1, 1);
	if (bytes > 0) {

		/* there is data in the pipe for us to read */
		uds_fd_table[minor].sel_ops_out |= SEL_RD;

	} else if (uds_fd_table[minor].listening == 1) {

		/* check for pending connections */
		for (i = 0; i < uds_fd_table[minor].backlog_size; i++) {
			if (uds_fd_table[minor].backlog[i] != -1) {
				uds_fd_table[minor].sel_ops_out |= SEL_RD;
				break;
			}
		}
	}

	/* check if we can write without blocking */
	bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
	if (bytes > 0) {
		uds_fd_table[minor].sel_ops_out |= SEL_WR;
	}

	uds_fd_table[minor].syscall_done = 1;

	uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, 
			(cp_grant_id_t) dev_m_in->IO_GRANT, 
			uds_fd_table[minor].sel_ops_out);

	return uds_fd_table[minor].sel_ops_out;
}
Exemple #21
0
int do_recvmsg(message *dev_m_in, message *dev_m_out)
{
	int minor;
	int rc;
	struct msg_control msg_ctrl;
	socklen_t controllen_avail = 0;
	socklen_t controllen_needed = 0;
	socklen_t controllen_desired = 0;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_sendmsg() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);


#if DEBUG == 1
	printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor,
				uds_fd_table[minor].ancillary_data.cred.pid,
				uds_fd_table[minor].ancillary_data.cred.uid,
				uds_fd_table[minor].ancillary_data.cred.gid);
#endif

	memset(&msg_ctrl, '\0', sizeof(struct msg_control));

	/* get the msg_control from the user, it will include the
	 * amount of space the user has allocated for control data.
	 */
	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
					(vir_bytes) 0, (vir_bytes) &msg_ctrl,
					sizeof(struct msg_control));

	if (rc != OK) {
		return EIO;
	}

	controllen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX);

	if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
		controllen_needed = CMSG_LEN(sizeof(int) *
				(uds_fd_table[minor].ancillary_data.nfiledes));
	}

	/* if there is room we also include credentials */
	controllen_desired = controllen_needed +
				CMSG_LEN(sizeof(struct ucred));

	if (controllen_needed > controllen_avail) {
		return EOVERFLOW;
	}

	rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl);
	if (rc != OK) {
		return rc;
	}

	if (controllen_desired <= controllen_avail) {
		rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data,
								&msg_ctrl);
		if (rc != OK) {
			return rc;
		}
	}

	/* send the user the control data */
	rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
		(vir_bytes) 0, (vir_bytes) &msg_ctrl,
		sizeof(struct msg_control));

	return rc ? EIO : OK;
}
Exemple #22
0
PUBLIC int uds_status(message *dev_m_in, message *dev_m_out)
{
	int i, bytes;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_status() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION);
#endif

	for (i = 0; i < NR_FDS; i++) {

		if (uds_fd_table[i].status_updated == 1) {

			/* clear the status_updated flag */
			uds_fd_table[i].status_updated = 0;
			uds_fd_table[i].selecting = 0;

			/* prepare the response */
			dev_m_out->m_type = DEV_IO_READY;
			dev_m_out->DEV_MINOR = i;
			dev_m_out->DEV_SEL_OPS = uds_fd_table[i].sel_ops_out;

			return uds_fd_table[i].sel_ops_out;
		}

		if (uds_fd_table[i].ready_to_revive == 1) {

			/* clear the ready to revive flag */
			uds_fd_table[i].ready_to_revive = 0;

			switch (uds_fd_table[i].suspended) {

				case UDS_SUSPENDED_READ:

					bytes = uds_perform_read(i, 
						dev_m_in->m_source,
						uds_fd_table[i].io_gr_size,
						0);

					if (bytes == -1) {

						uds_set_reply(dev_m_out,
						DEV_REVIVE, 
						uds_fd_table[i].endpoint,
						uds_fd_table[i].io_gr,
						errno);

						return errno;

					} else if (bytes == SUSPEND) {

						dev_m_out->m_type =
							DEV_NO_STATUS;

						return OK;

					} else  {

						uds_fd_table[i].suspended =
							UDS_NOT_SUSPENDED;

						uds_set_reply(dev_m_out,
						DEV_REVIVE, 
						uds_fd_table[i].endpoint,
						uds_fd_table[i].io_gr,
						bytes);

						return bytes;
					}

				case UDS_SUSPENDED_WRITE:

					bytes = uds_perform_write(i,
						dev_m_in->m_source, 
						uds_fd_table[i].io_gr_size,
						0);

					if (bytes == -1) {

						uds_set_reply(dev_m_out,
						DEV_REVIVE, 
						uds_fd_table[i].endpoint,
						uds_fd_table[i].io_gr,
						errno);

						return errno;

					} else if (bytes == SUSPEND) {

						dev_m_out->m_type =
							DEV_NO_STATUS;

						return OK;

					} else  {

						uds_fd_table[i].suspended =
							UDS_NOT_SUSPENDED;

						uds_set_reply(dev_m_out, 
						DEV_REVIVE, 
						uds_fd_table[i].endpoint,
						uds_fd_table[i].io_gr,
						bytes);

						return bytes;
					}

				case UDS_SUSPENDED_CONNECT:
				case UDS_SUSPENDED_ACCEPT:

					/* In both cases, the process 
					 * that send the notify() 
					 * already performed the connection. 
					 * The only thing to do here is 
					 * unblock.
					 */

					uds_fd_table[i].suspended = 
							UDS_NOT_SUSPENDED;

					uds_set_reply(dev_m_out,
						DEV_REVIVE, 
						uds_fd_table[i].endpoint,
						uds_fd_table[i].io_gr,
						OK);

					return OK;

				default:
					continue;
			}

		}
	}

	dev_m_out->m_type = DEV_NO_STATUS;
	return OK;
}
Exemple #23
0
int do_connect(message *dev_m_in, message *dev_m_out)
{
	int minor, child;
	struct sockaddr_un addr;
	int rc, i, j;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_connect() call_count=%d\n", uds_minor(dev_m_in),
								++call_count);
#endif

	minor = uds_minor(dev_m_in);

	/* only connection oriented sockets can connect */
	if (uds_fd_table[minor].type != SOCK_STREAM &&
			uds_fd_table[minor].type != SOCK_SEQPACKET) {
		return EINVAL;
	}

	if (uds_fd_table[minor].peer != -1) {
		/* socket is already connected */
		return EISCONN;
	}

	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
				(vir_bytes) 0, (vir_bytes) &addr,
				sizeof(struct sockaddr_un));

	if (rc != OK) {
		return EIO;
	}

	rc = check_perms(minor, &addr);
	if (rc != OK) {
		/* permission denied, socket file doesn't exist, etc. */
		return rc;
	}

	/* look for a socket of the same type that is listening on the
	 * address we want to connect to
	 */
	for (i = 0; i < NR_FDS; i++) {

		if (uds_fd_table[minor].type == uds_fd_table[i].type &&
			uds_fd_table[i].listening &&
			uds_fd_table[i].addr.sun_family == AF_UNIX &&
			!strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path,
			UNIX_PATH_MAX)) {

			if ((child = uds_fd_table[i].child) != -1) {

				/* the server is blocked on accept(2) --
				 * perform connection to the child
				 */

				rc = perform_connection(dev_m_in, dev_m_out,
					&addr, minor, child);

				if (rc == OK) {

					uds_fd_table[i].child = -1;

#if DEBUG == 1
		printf("(uds) [%d] {do_connect} revive %d\n", minor, child);
#endif

					/* wake the parent (server) */
					uds_fd_table[child].ready_to_revive =
						1;
					uds_unsuspend(dev_m_in->m_source,
						child);
				}

				return rc;

			} else {

#if DEBUG == 1
				printf("(uds) [%d] adding to %d's backlog\n",
								minor, i);
#endif

				/* tell the server were waiting to be served */

				/* look for a free slot in the backlog */
				rc = -1; /* to trap error */
				for (j = 0; j < uds_fd_table[i].backlog_size;
					j++) {

					if (uds_fd_table[i].backlog[j] == -1) {

						uds_fd_table[i].backlog[j] =
							minor;

						rc = 0;
						break;
					}
				}

				if (rc == -1) {

					/* backlog is full */
					break;
				}

				/* see if the server is blocked on select() */
				if (uds_fd_table[i].selecting == 1) {

					/* if the server wants to know
					 * about data ready to read and
					 * it doesn't know about it
					 * already, then let the server
					 * know we have data for it.
					 */
					if ((uds_fd_table[i].sel_ops_in &
						SEL_RD) &&
						!(uds_fd_table[i].sel_ops_out &
						SEL_RD)) {

						uds_fd_table[i].sel_ops_out |=
							SEL_RD;
						uds_fd_table[i].status_updated
							= 1;

						uds_unsuspend(
						dev_m_in->m_source, i);
					}
				}

				/* we found our server */
				uds_fd_table[minor].peer = i;

				/* set the address */
				memcpy(&(uds_fd_table[minor].addr), &addr,
					sizeof(struct sockaddr_un));

				break;
			}
		}
	}

	if (uds_fd_table[minor].peer == -1) {
		/* could not find another open socket listening on the
		 * specified address with room in the backlog
		 */
		return ECONNREFUSED;
	}

#if DEBUG == 1
	printf("(uds) [%d] {do_connect} suspend\n", minor);
#endif

	/* suspend until the server side completes the connection with accept()
	 */

	uds_fd_table[minor].suspended = UDS_SUSPENDED_CONNECT;

	return SUSPEND;
}
Exemple #24
0
int do_sendmsg(message *dev_m_in, message *dev_m_out)
{
	int minor, peer, rc, i;
	struct msg_control msg_ctrl;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] do_sendmsg() call_count=%d\n",
					uds_minor(dev_m_in), ++call_count);
#endif

	minor = uds_minor(dev_m_in);

	memset(&msg_ctrl, '\0', sizeof(struct msg_control));

	rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
					(vir_bytes) 0, (vir_bytes) &msg_ctrl,
					sizeof(struct msg_control));

	if (rc != OK) {
		return EIO;
	}

	/* locate peer */
	peer = -1;
	if (uds_fd_table[minor].type == SOCK_DGRAM) {
		if (uds_fd_table[minor].target.sun_path[0] == '\0' ||
			uds_fd_table[minor].target.sun_family != AF_UNIX) {

			return EDESTADDRREQ;
		}

		for (i = 0; i < NR_FDS; i++) {

			/* look for a SOCK_DGRAM socket that is bound on
			 * the target address
			 */
			if (uds_fd_table[i].type == SOCK_DGRAM &&
				uds_fd_table[i].addr.sun_family == AF_UNIX &&
				!strncmp(uds_fd_table[minor].target.sun_path,
				uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)){

				peer = i;
				break;
			}
		}

		if (peer == -1) {
			return ENOENT;
		}
	} else {
		peer = uds_fd_table[minor].peer;
		if (peer == -1) {
			return ENOTCONN;
		}
	}

#if DEBUG == 1
	printf("(uds) [%d] sendmsg() -- peer=%d\n", minor, peer);
#endif
	/* note: it's possible that there is already some file
	 * descriptors in ancillary_data if the peer didn't call
	 * recvmsg() yet. That's okay. The receiver will
	 * get the current file descriptors plus the new ones.
	 */
	rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data,
								minor);
	if (rc != OK) {
		return rc;
	}

	return send_fds(minor, &uds_fd_table[peer].ancillary_data);
}
Exemple #25
0
PUBLIC int uds_open(message *dev_m_in, message *dev_m_out)
{
	message fs_m_in, fs_m_out;
	struct ucred ucred;
	int rc, i;
	int minor;

#if DEBUG == 1
	static int call_count = 0;
	printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in),
							++call_count);
	printf("Endpoint: 0x%x\n", dev_m_in->IO_ENDPT);
#endif

	/*
	 * Find a slot in the descriptor table for the new descriptor.
	 * The index of the descriptor in the table will be returned.
	 * Subsequent calls to read/write/close/ioctl/etc will use this
	 * minor number. The minor number must be different from the
	 * the /dev/uds device's minor number (currently 0).
	 */

	minor = -1; /* to trap error */

	for (i = 1; i < NR_FDS; i++) {
		if (uds_fd_table[i].state == UDS_FREE) {
			minor = i;
			break;
		}
	}

	if (minor == -1) {

		/* descriptor table full */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE);
		return ENFILE;
	}

	/*
	 * We found a slot in uds_fd_table, now initialize the descriptor
	 */

	/* mark this one as 'in use' so that it doesn't get assigned to
	 * another socket
	 */
	uds_fd_table[minor].state = UDS_INUSE;

	/* track the system call we are performing in case it gets cancelled */
	uds_fd_table[minor].call_nr = dev_m_in->m_type;
	uds_fd_table[minor].ioctl = 0;
	uds_fd_table[minor].syscall_done = 0;

	/* set the socket owner */
	uds_fd_table[minor].owner = dev_m_in->IO_ENDPT;
	uds_fd_table[minor].endpoint = dev_m_in->IO_ENDPT;

	/* setup select(2) framework */
	uds_fd_table[minor].selecting = 0;
	uds_fd_table[minor].select_proc = 0;
	uds_fd_table[minor].sel_ops_in = 0;
	uds_fd_table[minor].sel_ops_out = 0;
	uds_fd_table[minor].status_updated = 0;

	/* initialize the data pointer (pos) to the start of the PIPE */
	uds_fd_table[minor].pos = 0;

	/* the PIPE is initially empty */
	uds_fd_table[minor].size = 0;

	/* the default for a new socket is to allow reading and writing.
	 * shutdown(2) will remove one or both flags.
	 */
	uds_fd_table[minor].mode = S_IRUSR|S_IWUSR;

	/* In libc socket(2) sets this to the actual value later with the
	 * NWIOSUDSTYPE ioctl().
	 */
	uds_fd_table[minor].type = -1;

	/* Clear the backlog by setting each entry to -1 */
	for (i = 0; i < UDS_SOMAXCONN; i++) {
		/* initially no connections are pending */
		uds_fd_table[minor].backlog[i] = -1;
	}

	memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct 
								ancillary));
	for (i = 0; i < OPEN_MAX; i++) {
		uds_fd_table[minor].ancillary_data.fds[i] = -1;
	}

	/* default the size to UDS_SOMAXCONN */
	uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;

	/* the socket isn't listening for incoming connections until
	 * listen(2) is called
	 */
	uds_fd_table[minor].listening = 0;

	/* initially the socket is not connected to a peer */
	uds_fd_table[minor].peer = -1;

	/* there isn't a child waiting to be accept(2)'d */
	uds_fd_table[minor].child = -1;

	/* initially the socket is not bound or listening on an address */
	memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un));
	memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un));
	memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un));

	/* Initially the socket isn't suspended. */
	uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;

	/* and the socket doesn't have an I/O grant initially */
	uds_fd_table[minor].io_gr = (cp_grant_id_t) 0;

	/* since there is no I/O grant it effectively has no size either */
	uds_fd_table[minor].io_gr_size = 0;

	/* The process isn't suspended so we don't flag it as revivable */
	uds_fd_table[minor].ready_to_revive = 0;

	/* get the effective user id and effective group id from the endpoint */
	/* this is needed in the REQ_NEWNODE request to PFS. */
	rc = getnucred(uds_fd_table[minor].endpoint, &ucred);
	if (rc == -1) {
		/* roll back the changes we made to the descriptor */
		memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));

		/* likely error: invalid endpoint / proc doesn't exist */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, errno);
		return errno;
	}

	/* Prepare Request to the FS side of PFS */

	fs_m_in.m_type = REQ_NEWNODE;
	fs_m_in.REQ_MODE = I_NAMED_PIPE;
	fs_m_in.REQ_DEV = NO_DEV;
	fs_m_in.REQ_UID = ucred.uid;
	fs_m_in.REQ_GID = ucred.gid;

	/* Request a new inode on the pipe file system */

	rc = fs_newnode(&fs_m_in, &fs_m_out);
	if (rc != OK) {
		/* roll back the changes we made to the descriptor */
		memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));

		/* likely error: get_block() failed */
		uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
				(cp_grant_id_t) dev_m_in->IO_GRANT, errno);
		return errno;
	}

	/* Process the response */

	uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR;

	/* prepare the reply */

	uds_fd_table[minor].syscall_done = 1;
	uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
			(cp_grant_id_t) dev_m_in->IO_GRANT, minor);
	return minor;
}