/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
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); }
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); }