Exemple #1
0
/*
 * Convert a user file descriptor to a kernel file entry.  A reference on the
 * file entry is held upon returning.  This is lighter weight than
 * fgetsock(), which bumps the socket reference drops the file reference
 * count instead, as this approach avoids several additional mutex operations
 * associated with the additional reference count.
 */
static int
getsock(struct filedesc *fdp, int fd, struct file **fpp)
{
	struct file *fp;
	int error;

	fp = NULL;
	if (fdp == NULL)
		error = EBADF;
	else {
		FILEDESC_LOCK_FAST(fdp);
		fp = fget_locked(fdp, fd);
		if (fp == NULL)
			error = EBADF;
		else if (fp->f_type != DTYPE_SOCKET) {
			fp = NULL;
			error = ENOTSOCK;
		} else {
			fhold(fp);
			error = 0;
		}
		FILEDESC_UNLOCK_FAST(fdp);
	}
	*fpp = fp;
	return (error);
}
Exemple #2
0
/*
 * File descriptors can be passed into an AF_NETGRAPH socket.
 * Note, that file descriptors cannot be passed OUT.
 * Only character device descriptors are accepted.
 * Character devices are useful to connect a graph to a device,
 * which after all is the purpose of this whole system.
 */
static int
ng_internalize(struct mbuf *control, struct thread *td)
{
	const struct cmsghdr *cm = mtod(control, const struct cmsghdr *);
	struct file *fp;
	struct vnode *vn;
	int oldfds;
	int fd;

	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
	    cm->cmsg_len != control->m_len) {
		TRAP_ERROR;
		return (EINVAL);
	}

	/* Check there is only one FD. XXX what would more than one signify? */
	oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
	if (oldfds != 1) {
		TRAP_ERROR;
		return (EINVAL);
	}

	/* Check that the FD given is legit. and change it to a pointer to a
	 * struct file. */
	fd = CMSG_DATA(cm);
	if ((error = fget(td, fd, &fp)) != 0)
		return (error);

	/* Depending on what kind of resource it is, act differently. For
	 * devices, we treat it as a file. For an AF_NETGRAPH socket,
	 * shortcut straight to the node. */
	switch (fp->f_type) {
	case DTYPE_VNODE:
		vn = fp->f_data;
		if (vn && (vn->v_type == VCHR)) {
			/* for a VCHR, actually reference the FILE */
			fhold(fp);
			/* XXX then what :) */
			/* how to pass on to other modules? */
		} else {
			fdrop(fp, td);
			TRAP_ERROR;
			return (EINVAL);
		}
		break;
	default:
		fdrop(fp, td);
		TRAP_ERROR;
		return (EINVAL);
	}
	fdrop(fp, td);
	return (0);
}
Exemple #3
0
/*
 * Convert a file descriptor to appropriate smb_share pointer
 */
static struct file*
nsmb_getfp(struct filedesc* fdp, int fd, int flag)
{
	struct file* fp;

	FILEDESC_SLOCK(fdp);
	if ((fp = fget_locked(fdp, fd)) == NULL || (fp->f_flag & flag) == 0) {
		FILEDESC_SUNLOCK(fdp);
		return (NULL);
	}
	fhold(fp);
	FILEDESC_SUNLOCK(fdp);
	return (fp);
}
Exemple #4
0
/*
 * Convert a file descriptor to appropriate smb_share pointer
 */
static struct file*
nsmb_getfp(struct filedesc* fdp, int fd, int flag)
{
	struct file* fp;

	FILEDESC_SLOCK(fdp);
	if (fd < 0 || fd >= fdp->fd_nfiles ||
	    (fp = fdp->fd_ofiles[fd]) == NULL ||
	    (fp->f_flag & flag) == 0) {
		FILEDESC_SUNLOCK(fdp);
		return (NULL);
	}
	fhold(fp);
	FILEDESC_SUNLOCK(fdp);
	return (fp);
}
Exemple #5
0
static int
sysvipc_install_fd(struct proc *p_from, struct proc *p_to, int fd)
{
	struct filedesc *fdp_from = p_from->p_fd;
	struct filedesc *fdp_to = p_to->p_fd;
	
	struct file *fp;
	int error, newfd;
	int flags;

	/*
	 * Get the file corresponding to fd from the process p_from.
	 */
	spin_lock(&fdp_from->fd_spin);
	if ((unsigned)fd >= fdp_from->fd_nfiles || fdp_from->fd_files[fd].fp == NULL) {
		spin_unlock(&fdp_from->fd_spin);
		return (EBADF);
	}

	fp = fdp_from->fd_files[fd].fp;
	flags = fdp_from->fd_files[fd].fileflags;
	fhold(fp);	/* MPSAFE - can be called with a spinlock held */
	spin_unlock(&fdp_from->fd_spin);

	/*
	 * Reserve a fd in the process p_to.
	 */
	error = fdalloc(p_to, 1, &newfd);
	if (error) {
		fdrop(fp);
		return (error);
	}

	/*
	 * Set fd for the fp file.
	 */
	fsetfd(fdp_to, fp, newfd);
	fdp_to->fd_files[newfd].fileflags = flags;
	fdrop(fp);

	return (newfd);
}
Exemple #6
0
static int 
bsd_accept(cyg_file *fp, cyg_file *new_fp,
           struct sockaddr *name, socklen_t *anamelen)
{
    socklen_t namelen = 0;
    int error = 0, s;
    struct socket *head, *so;
    struct sockaddr *sa;

    if( anamelen != NULL)
        namelen = *anamelen;

    s = splsoftnet();
    head = (struct socket *)fp->f_data;

    if ((head->so_options & SO_ACCEPTCONN) == 0) {
        splx(s);
        return (EINVAL);
    }

    if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
        splx(s);
        return (EWOULDBLOCK);
    }

    while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
        if (head->so_state & SS_CANTRCVMORE) {
            head->so_error = ECONNABORTED;
            break;
        }
        error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH,
                       "netcon", 0);
        if (error) {
            splx(s);
            return (error);
        }
    }

    if (head->so_error) {
        error = head->so_error;
        head->so_error = 0;
        splx(s);
        return (error);
    }

    /*
     * At this point we know that there is at least one connection
     * ready to be accepted. Remove it from the queue prior to
     * allocating the file descriptor for it since falloc() may
     * block allowing another process to accept the connection
     * instead.
     */
    so = TAILQ_FIRST(&head->so_comp);
    TAILQ_REMOVE(&head->so_comp, so, so_list);
    head->so_qlen--;

#if 0 // FIXME
    fflag = lfp->f_flag;
    error = falloc(p, &nfp, &fd);
    if (error) {
        /*
         * Probably ran out of file descriptors. Put the
         * unaccepted connection back onto the queue and
         * do another wakeup so some other process might
         * have a chance at it.
         */
        TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
        head->so_qlen++;
        wakeup_one(&head->so_timeo);
        splx(s);
        goto done;
    }
    fhold(nfp);
    p->p_retval[0] = fd;

    /* connection has been removed from the listen queue */
    KNOTE(&head->so_rcv.sb_sel.si_note, 0);
#endif

    so->so_state &= ~SS_COMP;
    so->so_head = NULL;

    cyg_selinit(&so->so_rcv.sb_sel);
    cyg_selinit(&so->so_snd.sb_sel);
    
    new_fp->f_type      = DTYPE_SOCKET;
    new_fp->f_flag     |= FREAD|FWRITE;
    new_fp->f_offset    = 0;
    new_fp->f_ops       = &bsd_sock_fileops;
    new_fp->f_data      = (CYG_ADDRWORD)so;
    new_fp->f_xops      = (CYG_ADDRWORD)&bsd_sockops;
    
    sa = 0;
    error = soaccept(so, &sa);
    if (error) {
        /*
         * return a namelen of zero for older code which might
         * ignore the return value from accept.
         */	
        if (name != NULL) {
            *anamelen = 0;
        }
        goto noconnection;
    }
    if (sa == NULL) {
        namelen = 0;
        if (name)
            goto gotnoname;
        splx(s);
        error = 0;
        goto done;
    }
    if (name) {
        if (namelen > sa->sa_len)
            namelen = sa->sa_len;
#ifdef COMPAT_OLDSOCK
        if (compat)
            ((struct osockaddr *)sa)->sa_family = sa->sa_family;
#endif
        error = copyout(sa, (caddr_t)name, namelen);
        if (!error)
gotnoname:
        *anamelen = namelen;
    }
noconnection:

#if 0 // FIXME
	/*
	 * close the new descriptor, assuming someone hasn't ripped it
	 * out from under us.
	 */
	if (error) {
		if (fdp->fd_ofiles[fd] == nfp) {
			fdp->fd_ofiles[fd] = NULL;
			fdrop(nfp, p);
		}
	}
	splx(s);

	/*
	 * Release explicitly held references before returning.
	 */
done:
	if (nfp != NULL)
		fdrop(nfp, p);
	fdrop(lfp, p);
	return (error);
    m_freem(nam);
#else
 done:
#endif
    splx(s);
    
    return (error);
}
/*
 * Mount the per-process file descriptors (/dev/fd)
 */
static int
portal_mount(struct mount *mp)
{
	struct file *fp;
	struct portalmount *fmp;
	struct socket *so;
	struct vnode *rvp;
	struct thread *td;
	struct portalnode *pn;
	int error, v;
	char *p;

	td = curthread;
	if (vfs_filteropt(mp->mnt_optnew, portal_opts))
		return (EINVAL);

	error = vfs_scanopt(mp->mnt_optnew, "socket", "%d", &v);
	if (error != 1)
		return (EINVAL);
	error = vfs_getopt(mp->mnt_optnew, "config", (void **)&p, NULL);
	if (error)
		return (error);

	/*
	 * Capsicum is not incompatible with portalfs, but we don't really
	 * know what rights are required. In the spirit of "better safe than
	 * sorry", pretend that all rights are required for now.
	 */
	if ((error = fget(td, v, CAP_MASK_VALID, &fp)) != 0)
		return (error);
        if (fp->f_type != DTYPE_SOCKET) {
		fdrop(fp, td);
                return(ENOTSOCK);
	}
	so = fp->f_data;	/* XXX race against userland */
	if (so->so_proto->pr_domain->dom_family != AF_UNIX) {
		fdrop(fp, td);
		return (ESOCKTNOSUPPORT);
	}

	pn = malloc(sizeof(struct portalnode),
		M_TEMP, M_WAITOK);

	fmp = malloc(sizeof(struct portalmount),
		M_PORTALFSMNT, M_WAITOK);	/* XXX */

	error = getnewvnode("portal", mp, &portal_vnodeops, &rvp); /* XXX */
	if (error) {
		free(fmp, M_PORTALFSMNT);
		free(pn, M_TEMP);
		fdrop(fp, td);
		return (error);
	}

	error = insmntque(rvp, mp);	/* XXX: Too early for mpsafe fs */
	if (error != 0) {
		free(fmp, M_PORTALFSMNT);
		free(pn, M_TEMP);
		fdrop(fp, td);
		return (error);
	}
	rvp->v_data = pn;
	rvp->v_type = VDIR;
	rvp->v_vflag |= VV_ROOT;
	VTOPORTAL(rvp)->pt_arg = 0;
	VTOPORTAL(rvp)->pt_size = 0;
	VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID;
	fmp->pm_root = rvp;
	fhold(fp);
	fmp->pm_server = fp;

	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	MNT_IUNLOCK(mp);
	mp->mnt_data =  fmp;
	vfs_getnewfsid(mp);

	vfs_mountedfrom(mp, p);
	fdrop(fp, td);
	return (0);
}