/* ARGSUSED */ int sys_getpeername(struct proc *p, void *v, register_t *retval) { struct sys_getpeername_args /* { syscallarg(int) fdes; syscallarg(struct sockaddr *) asa; syscallarg(socklen_t *) alen; } */ *uap = v; struct file *fp; struct socket *so; struct mbuf *m = NULL; socklen_t len; int error; if ((error = getsock(p->p_fd, SCARG(uap, fdes), &fp)) != 0) return (error); so = fp->f_data; if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { FRELE(fp, p); return (ENOTCONN); } error = copyin(SCARG(uap, alen), &len, sizeof (len)); if (error) goto bad; m = m_getclr(M_WAIT, MT_SONAME); error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p); if (error) goto bad; error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen)); bad: FRELE(fp, p); m_freem(m); return (error); }
/* ARGSUSED */ int sys_connect(struct proc *p, void *v, register_t *retval) { struct sys_connect_args /* { syscallarg(int) s; syscallarg(const struct sockaddr *) name; syscallarg(socklen_t) namelen; } */ *uap = v; struct file *fp; struct socket *so; struct mbuf *nam = NULL; int error, s; if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); so = fp->f_data; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { FRELE(fp, p); return (EALREADY); } error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), MT_SONAME); if (error) goto bad; #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); #endif error = soconnect(so, nam); if (error) goto bad; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { FRELE(fp, p); m_freem(nam); return (EINPROGRESS); } s = splsoftnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = tsleep(&so->so_timeo, PSOCK | PCATCH, "netcon2", 0); if (error) break; } if (error == 0) { error = so->so_error; so->so_error = 0; } splx(s); bad: so->so_state &= ~SS_ISCONNECTING; FRELE(fp, p); if (nam) m_freem(nam); if (error == ERESTART) error = EINTR; return (error); }
/* ARGSUSED */ int sys_bind(struct proc *p, void *v, register_t *retval) { struct sys_bind_args /* { syscallarg(int) s; syscallarg(const struct sockaddr *) name; syscallarg(socklen_t) namelen; } */ *uap = v; struct file *fp; struct mbuf *nam; int error; if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), MT_SONAME); if (error == 0) { #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); #endif error = sobind(fp->f_data, nam, p); m_freem(nam); } FRELE(fp, p); return (error); }
/* ARGSUSED */ int sys_setsockopt(struct proc *p, void *v, register_t *retval) { struct sys_setsockopt_args /* { syscallarg(int) s; syscallarg(int) level; syscallarg(int) name; syscallarg(const void *) val; syscallarg(socklen_t) valsize; } */ *uap = v; struct file *fp; struct mbuf *m = NULL; int error; if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); if (SCARG(uap, valsize) > MCLBYTES) { error = EINVAL; goto bad; } if (SCARG(uap, val)) { m = m_get(M_WAIT, MT_SOOPTS); if (SCARG(uap, valsize) > MLEN) { MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { error = ENOBUFS; goto bad; } } if (m == NULL) { error = ENOBUFS; goto bad; } error = copyin(SCARG(uap, val), mtod(m, caddr_t), SCARG(uap, valsize)); if (error) { goto bad; } m->m_len = SCARG(uap, valsize); } error = sosetopt(fp->f_data, SCARG(uap, level), SCARG(uap, name), m); m = NULL; bad: if (m) m_freem(m); FRELE(fp, p); return (error); }
/* ARGSUSED */ int sys_shutdown(struct proc *p, void *v, register_t *retval) { struct sys_shutdown_args /* { syscallarg(int) s; syscallarg(int) how; } */ *uap = v; struct file *fp; int error; if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); error = soshutdown(fp->f_data, SCARG(uap, how)); FRELE(fp, p); return (error); }
/* * Given a file descriptor, check an ACL for it. */ int sys___acl_aclcheck_fd(struct proc *p, void *v, register_t *retval) { struct sys___acl_aclcheck_fd_args *uap = v; struct vnode *vp; struct file *fp; int error; error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); if (error) return (error); vp = (struct vnode *)fp->f_data; vref(vp); /* vn_acl_check() will drop the reference. */ error = vn_acl_check(p, vp, SCARG(uap, type), SCARG(uap, aclp)); FRELE(fp); return (error); }
/* ARGSUSED */ int sys_getsockopt(struct proc *p, void *v, register_t *retval) { struct sys_getsockopt_args /* { syscallarg(int) s; syscallarg(int) level; syscallarg(int) name; syscallarg(void *) val; syscallarg(socklen_t *) avalsize; } */ *uap = v; struct file *fp; struct mbuf *m = NULL; socklen_t valsize; int error; if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); if (SCARG(uap, val)) { error = copyin(SCARG(uap, avalsize), &valsize, sizeof (valsize)); if (error) goto out; } else valsize = 0; if ((error = sogetopt(fp->f_data, SCARG(uap, level), SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize && m != NULL) { if (valsize > m->m_len) valsize = m->m_len; error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize); if (error == 0) error = copyout(&valsize, SCARG(uap, avalsize), sizeof (valsize)); } out: FRELE(fp, p); if (m != NULL) (void)m_free(m); return (error); }
int linux_ioctl_fdio(struct proc *p, struct linux_sys_ioctl_args *uap, register_t *retval) { struct filedesc *fdp; struct file *fp; int error; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); u_long com; struct fd_type fparams; struct linux_floppy_struct lflop; struct linux_floppy_drive_struct ldrive; com = (u_long)SCARG(uap, data); fdp = p->p_fd; if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) return (EBADF); FREF(fp); com = SCARG(uap, com); ioctlf = fp->f_ops->fo_ioctl; retval[0] = error = 0; switch (com) { case LINUX_FDMSGON: case LINUX_FDMSGOFF: case LINUX_FDTWADDLE: case LINUX_FDCLRPRM: /* whatever you say */ break; case LINUX_FDPOLLDRVSTAT: /* * Just fill in some innocent defaults. */ memset(&ldrive, 0, sizeof ldrive); ldrive.fd_ref = 1; ldrive.maxblock = 2; ldrive.maxtrack = ldrive.track = 1; ldrive.flags = LINUX_FD_DISK_WRITABLE; error = copyout(&ldrive, SCARG(uap, data), sizeof ldrive); break; case LINUX_FDGETPRM: error = ioctlf(fp, FD_GTYPE, (caddr_t)&fparams, p); if (error != 0) break; lflop.size = fparams.heads * fparams.sectrac * fparams.tracks; lflop.sect = fparams.sectrac; lflop.head = fparams.heads; lflop.track = fparams.tracks; lflop.stretch = fparams.step == 2 ? 1 : 0; lflop.spec1 = fparams.steprate; lflop.gap = fparams.gap1; lflop.fmt_gap = fparams.gap2; lflop.rate = fparams.rate; error = copyout(&lflop, SCARG(uap, data), sizeof lflop); break; case LINUX_FDSETPRM: /* * Should use FDIOCSETFORMAT here, iff its interface * is extended. */ case LINUX_FDDEFPRM: case LINUX_FDFMTBEG: case LINUX_FDFMTTRK: case LINUX_FDFMTEND: case LINUX_FDSETEMSGTRESH: case LINUX_FDFLUSH: case LINUX_FDSETMAXERRS: case LINUX_FDGETMAXERRS: case LINUX_FDGETDRVTYP: case LINUX_FDSETDRVPRM: case LINUX_FDGETDRVPRM: case LINUX_FDGETDRVSTAT: case LINUX_FDRESET: case LINUX_FDGETFDCSTAT: case LINUX_FDWERRORCLR: case LINUX_FDWERRORGET: case LINUX_FDRAWCMD: case LINUX_FDEJECT: default: error = EINVAL; } FRELE(fp, p); return 0; }
/* * We come here in a last attempt to satisfy a Linux ioctl() call */ int linux_machdepioctl(struct proc *p, void *v, register_t *retval) { struct linux_sys_ioctl_args /* { syscallarg(int) fd; syscallarg(u_long) com; syscallarg(caddr_t) data; } */ *uap = v; struct sys_ioctl_args bia; u_long com; int error; #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL)) struct vt_mode lvt; caddr_t bvtp, sg; #endif struct filedesc *fdp; struct file *fp; int fd; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); struct ioctl_pt pt; fd = SCARG(uap, fd); SCARG(&bia, fd) = SCARG(uap, fd); SCARG(&bia, data) = SCARG(uap, data); com = SCARG(uap, com); fdp = p->p_fd; if ((fp = fd_getfile(fdp, fd)) == NULL) return (EBADF); switch (com) { #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL)) case LINUX_KDGKBMODE: com = KDGKBMODE; break; case LINUX_KDSKBMODE: com = KDSKBMODE; if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW) SCARG(&bia, data) = (caddr_t)K_RAW; break; case LINUX_KIOCSOUND: SCARG(&bia, data) = (caddr_t)(((unsigned long)SCARG(&bia, data)) & 0xffff); /* FALLTHROUGH */ case LINUX_KDMKTONE: com = KDMKTONE; break; case LINUX_KDSETMODE: com = KDSETMODE; break; case LINUX_KDGETMODE: #if NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL) com = WSDISPLAYIO_GMODE; #else com = KDGETMODE; #endif break; case LINUX_KDENABIO: com = KDENABIO; break; case LINUX_KDDISABIO: com = KDDISABIO; break; case LINUX_KDGETLED: com = KDGETLED; break; case LINUX_KDSETLED: com = KDSETLED; break; case LINUX_VT_OPENQRY: com = VT_OPENQRY; break; case LINUX_VT_GETMODE: { int sig; SCARG(&bia, com) = VT_GETMODE; if ((error = sys_ioctl(p, &bia, retval))) return error; if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; /* We need to bounds check here in case there is a race with another thread */ if ((error = bsd_to_linux_signal(lvt.relsig, &sig))) return error; lvt.relsig = sig; if ((error = bsd_to_linux_signal(lvt.acqsig, &sig))) return error; lvt.acqsig = sig; if ((error = bsd_to_linux_signal(lvt.frsig, &sig))) return error; lvt.frsig = sig; return copyout((caddr_t)&lvt, SCARG(uap, data), sizeof (struct vt_mode)); } case LINUX_VT_SETMODE: { int sig; com = VT_SETMODE; if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; if ((error = linux_to_bsd_signal(lvt.relsig, &sig))) return error; lvt.relsig = sig; if ((error = linux_to_bsd_signal(lvt.acqsig, &sig))) return error; lvt.acqsig = sig; if ((error = linux_to_bsd_signal(lvt.frsig, &sig))) return error; lvt.frsig = sig; sg = stackgap_init(p->p_emul); bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode)); if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode)))) return error; SCARG(&bia, data) = bvtp; break; } case LINUX_VT_DISALLOCATE: /* XXX should use WSDISPLAYIO_DELSCREEN */ return 0; case LINUX_VT_RELDISP: com = VT_RELDISP; break; case LINUX_VT_ACTIVATE: com = VT_ACTIVATE; break; case LINUX_VT_WAITACTIVE: com = VT_WAITACTIVE; break; case LINUX_VT_GETSTATE: com = VT_GETSTATE; break; case LINUX_KDGKBTYPE: { char tmp = KB_101; /* This is what Linux does */ return copyout(&tmp, SCARG(uap, data), sizeof(char)); } #endif default: /* * Unknown to us. If it's on a device, just pass it through * using PTIOCLINUX, the device itself might be able to * make some sense of it. * XXX hack: if the function returns EJUSTRETURN, * it has stuffed a sysctl return value in pt.data. */ FREF(fp); ioctlf = fp->f_ops->fo_ioctl; pt.com = SCARG(uap, com); pt.data = SCARG(uap, data); error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p); FRELE(fp); if (error == EJUSTRETURN) { retval[0] = (register_t)pt.data; error = 0; } if (error == ENOTTY) printf("linux_machdepioctl: invalid ioctl %08lx\n", com); return (error); } SCARG(&bia, com) = com; return sys_ioctl(p, &bia, retval); }
int linux_ioctl_hdio(struct proc *p, struct linux_sys_ioctl_args *uap, register_t *retval) { u_long com; int error, error1; caddr_t sg; struct filedesc *fdp; struct file *fp; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); struct ataparams *atap, ata; struct atareq req; struct disklabel label, *labp; struct partinfo partp; struct linux_hd_geometry hdg; struct linux_hd_big_geometry hdg_big; fdp = p->p_fd; if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) return (EBADF); FREF(fp); com = SCARG(uap, com); ioctlf = fp->f_ops->fo_ioctl; retval[0] = error = 0; com = SCARG(uap, com); switch (com) { case LINUX_HDIO_OBSOLETE_IDENTITY: case LINUX_HDIO_GET_IDENTITY: sg = stackgap_init(p->p_emul); atap = stackgap_alloc(&sg, DEV_BSIZE); if (atap == NULL) { error = ENOMEM; break; } req.flags = ATACMD_READ; req.command = WDCC_IDENTIFY; req.databuf = (caddr_t)atap; req.datalen = DEV_BSIZE; req.timeout = 1000; error = ioctlf(fp, ATAIOCCOMMAND, (caddr_t)&req, p); if (error != 0) break; if (req.retsts != ATACMD_OK) { error = EIO; break; } error = copyin(atap, &ata, sizeof ata); if (error != 0) break; /* * 142 is the size of the old structure used by Linux, * which doesn't seem to be defined anywhere anymore. */ error = copyout(&ata, SCARG(uap, data), com == LINUX_HDIO_GET_IDENTITY ? sizeof ata : 142); break; case LINUX_HDIO_GETGEO: error = linux_machdepioctl(p, uap, retval); if (error == 0) break; error = ioctlf(fp, DIOCGDINFO, (caddr_t)&label, p); error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p); if (error != 0 && error1 != 0) { error = error1; break; } labp = error != 0 ? &label : partp.disklab; hdg.start = error1 != 0 ? partp.part->p_offset : 0; hdg.heads = labp->d_ntracks; hdg.cylinders = labp->d_ncylinders; hdg.sectors = labp->d_nsectors; error = copyout(&hdg, SCARG(uap, data), sizeof hdg); break; case LINUX_HDIO_GETGEO_BIG: error = linux_machdepioctl(p, uap, retval); if (error == 0) break; case LINUX_HDIO_GETGEO_BIG_RAW: error = ioctlf(fp, DIOCGDINFO, (caddr_t)&label, p); error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p); if (error != 0 && error1 != 0) { error = error1; break; } labp = error != 0 ? &label : partp.disklab; hdg_big.start = error1 != 0 ? partp.part->p_offset : 0; hdg_big.heads = labp->d_ntracks; hdg_big.cylinders = labp->d_ncylinders; hdg_big.sectors = labp->d_nsectors; error = copyout(&hdg_big, SCARG(uap, data), sizeof hdg_big); break; case LINUX_HDIO_GET_UNMASKINTR: case LINUX_HDIO_GET_MULTCOUNT: case LINUX_HDIO_GET_KEEPSETTINGS: case LINUX_HDIO_GET_32BIT: case LINUX_HDIO_GET_NOWERR: case LINUX_HDIO_GET_DMA: case LINUX_HDIO_GET_NICE: case LINUX_HDIO_DRIVE_RESET: case LINUX_HDIO_TRISTATE_HWIF: case LINUX_HDIO_DRIVE_TASK: case LINUX_HDIO_DRIVE_CMD: case LINUX_HDIO_SET_MULTCOUNT: case LINUX_HDIO_SET_UNMASKINTR: case LINUX_HDIO_SET_KEEPSETTINGS: case LINUX_HDIO_SET_32BIT: case LINUX_HDIO_SET_NOWERR: case LINUX_HDIO_SET_DMA: case LINUX_HDIO_SET_PIO_MODE: case LINUX_HDIO_SCAN_HWIF: case LINUX_HDIO_SET_NICE: case LINUX_HDIO_UNREGISTER_HWIF: error = EINVAL; } FRELE(fp); return error; }
int recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, register_t *retsize) { struct file *fp; struct uio auio; struct iovec *iov; int i; size_t len; int error; struct mbuf *from = NULL, *control = NULL; #ifdef KTRACE struct iovec *ktriov = NULL; #endif if ((error = getsock(p->p_fd, s, &fp)) != 0) return (error); auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_procp = p; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { /* Don't allow sum > SSIZE_MAX */ if (iov->iov_len > SSIZE_MAX || (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { error = EINVAL; goto out; } } #ifdef KTRACE if (KTRPOINT(p, KTR_GENIO)) { int iovlen = auio.uio_iovcnt * sizeof (struct iovec); ktriov = malloc(iovlen, M_TEMP, M_WAITOK); bcopy(auio.uio_iov, ktriov, iovlen); } #endif len = auio.uio_resid; error = soreceive(fp->f_data, &from, &auio, NULL, mp->msg_control ? &control : NULL, &mp->msg_flags, mp->msg_control ? mp->msg_controllen : 0); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; } #ifdef KTRACE if (ktriov != NULL) { if (error == 0) ktrgenio(p, s, UIO_READ, ktriov, len - auio.uio_resid); free(ktriov, M_TEMP); } #endif if (error) goto out; *retsize = len - auio.uio_resid; if (mp->msg_name) { socklen_t alen; if (from == NULL) alen = 0; else { alen = from->m_len; error = copyout(mtod(from, caddr_t), mp->msg_name, MIN(alen, mp->msg_namelen)); if (error) goto out; #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(from, caddr_t), alen); #endif } mp->msg_namelen = alen; if (namelenp && (error = copyout(&alen, namelenp, sizeof(alen)))) { goto out; } } if (mp->msg_control) { len = mp->msg_controllen; if (len <= 0 || control == NULL) len = 0; else { struct mbuf *m = control; caddr_t p = mp->msg_control; do { i = m->m_len; if (len < i) { mp->msg_flags |= MSG_CTRUNC; i = len; } error = copyout(mtod(m, caddr_t), p, i); if (m->m_next) i = ALIGN(i); p += i; len -= i; if (error != 0 || len <= 0) break; } while ((m = m->m_next) != NULL); len = p - (caddr_t)mp->msg_control; } mp->msg_controllen = len; } if (!error) { fp->f_rxfer++; fp->f_rbytes += *retsize; } out: FRELE(fp, p); if (from) m_freem(from); if (control) m_freem(control); return (error); }
int sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize) { struct file *fp; struct uio auio; struct iovec *iov; int i; struct mbuf *to, *control; size_t len; int error; #ifdef KTRACE struct iovec *ktriov = NULL; #endif to = NULL; if ((error = getsock(p->p_fd, s, &fp)) != 0) return (error); auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_procp = p; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { /* Don't allow sum > SSIZE_MAX */ if (iov->iov_len > SSIZE_MAX || (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { error = EINVAL; goto bad; } } if (mp->msg_name) { error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME); if (error) goto bad; #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen); #endif } if (mp->msg_control) { if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) { error = EINVAL; goto bad; } error = sockargs(&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); if (error) goto bad; } else control = 0; #ifdef KTRACE if (KTRPOINT(p, KTR_GENIO)) { int iovlen = auio.uio_iovcnt * sizeof (struct iovec); ktriov = malloc(iovlen, M_TEMP, M_WAITOK); bcopy(auio.uio_iov, ktriov, iovlen); } #endif len = auio.uio_resid; error = sosend(fp->f_data, to, &auio, NULL, control, flags); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) ptsignal(p, SIGPIPE, STHREAD); } if (error == 0) { *retsize = len - auio.uio_resid; fp->f_wxfer++; fp->f_wbytes += *retsize; } #ifdef KTRACE if (ktriov != NULL) { if (error == 0) ktrgenio(p, s, UIO_WRITE, ktriov, *retsize); free(ktriov, M_TEMP); } #endif bad: FRELE(fp, p); if (to) m_freem(to); return (error); }
int sys_accept(struct proc *p, void *v, register_t *retval) { struct sys_accept_args /* { syscallarg(int) s; syscallarg(struct sockaddr *) name; syscallarg(socklen_t *) anamelen; } */ *uap = v; struct file *fp, *headfp; struct mbuf *nam; socklen_t namelen; int error, s, tmpfd; struct socket *head, *so; int nflag; if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen), &namelen, sizeof (namelen)))) return (error); if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); headfp = fp; s = splsoftnet(); head = fp->f_data; redo: if ((head->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto bad; } if ((head->so_state & SS_NBIO) && head->so_qlen == 0) { if (head->so_state & SS_CANTRCVMORE) error = ECONNABORTED; else error = EWOULDBLOCK; goto bad; } while (head->so_qlen == 0 && head->so_error == 0) { if (head->so_state & SS_CANTRCVMORE) { head->so_error = ECONNABORTED; break; } error = tsleep(&head->so_timeo, PSOCK | PCATCH, "netcon", 0); if (error) { goto bad; } } if (head->so_error) { error = head->so_error; head->so_error = 0; goto bad; } /* Take note if socket was non-blocking. */ nflag = (headfp->f_flag & FNONBLOCK); fdplock(p->p_fd); error = falloc(p, &fp, &tmpfd); fdpunlock(p->p_fd); if (error != 0) { /* * Probably ran out of file descriptors. Wakeup * so some other process might have a chance at it. */ wakeup_one(&head->so_timeo); goto bad; } nam = m_get(M_WAIT, MT_SONAME); /* * Check whether the queue emptied while we slept: falloc() or * m_get() may have blocked, allowing the connection to be reset * or another thread or process to accept it. If so, start over. */ if (head->so_qlen == 0) { m_freem(nam); fdplock(p->p_fd); fdremove(p->p_fd, tmpfd); closef(fp, p); fdpunlock(p->p_fd); goto redo; } /* * Do not sleep after we have taken the socket out of the queue. */ so = TAILQ_FIRST(&head->so_q); if (soqremque(so, 1) == 0) panic("accept"); /* connection has been removed from the listen queue */ KNOTE(&head->so_rcv.sb_sel.si_note, 0); fp->f_type = DTYPE_SOCKET; fp->f_flag = FREAD | FWRITE | nflag; fp->f_ops = &socketops; fp->f_data = so; error = soaccept(so, nam); if (!error && SCARG(uap, name)) { error = copyaddrout(p, nam, SCARG(uap, name), namelen, SCARG(uap, anamelen)); } if (error) { /* if an error occurred, free the file descriptor */ fdplock(p->p_fd); fdremove(p->p_fd, tmpfd); closef(fp, p); fdpunlock(p->p_fd); } else { FILE_SET_MATURE(fp, p); *retval = tmpfd; } m_freem(nam); bad: splx(s); FRELE(headfp, p); return (error); }
int sys_mmap(struct proc *p, void *v, register_t *retval) { struct sys_mmap_args /* { syscallarg(void *) addr; syscallarg(size_t) len; syscallarg(int) prot; syscallarg(int) flags; syscallarg(int) fd; syscallarg(long) pad; syscallarg(off_t) pos; } */ *uap = v; vaddr_t addr; struct vattr va; off_t pos; vsize_t size, pageoff; vm_prot_t prot, maxprot; int flags, fd; vaddr_t vm_min_address = VM_MIN_ADDRESS; struct filedesc *fdp = p->p_fd; struct file *fp = NULL; struct vnode *vp; caddr_t handle; int error; /* * first, extract syscall args from the uap. */ addr = (vaddr_t) SCARG(uap, addr); size = (vsize_t) SCARG(uap, len); prot = SCARG(uap, prot); flags = SCARG(uap, flags); fd = SCARG(uap, fd); pos = SCARG(uap, pos); /* * Fixup the old deprecated MAP_COPY into MAP_PRIVATE, and * validate the flags. */ if ((prot & VM_PROT_ALL) != prot) return (EINVAL); if ((flags & MAP_FLAGMASK) != flags) return (EINVAL); if (flags & MAP_COPY) flags = (flags & ~MAP_COPY) | MAP_PRIVATE; if ((flags & (MAP_SHARED|MAP_PRIVATE)) == (MAP_SHARED|MAP_PRIVATE)) return (EINVAL); if (flags & MAP_DENYWRITE) return (EINVAL); /* * align file position and save offset. adjust size. */ ALIGN_ADDR(pos, size, pageoff); /* * now check (MAP_FIXED) or get (!MAP_FIXED) the "addr" */ if (flags & MAP_FIXED) { /* adjust address by the same amount as we did the offset */ addr -= pageoff; if (addr & PAGE_MASK) return (EINVAL); /* not page aligned */ if (addr > SIZE_MAX - size) return (EINVAL); /* no wrapping! */ if (VM_MAXUSER_ADDRESS > 0 && (addr + size) > VM_MAXUSER_ADDRESS) return (EINVAL); if (vm_min_address > 0 && addr < vm_min_address) return (EINVAL); } else { /* * not fixed: make sure we skip over the largest possible heap. * we will refine our guess later (e.g. to account for VAC, etc) */ if (addr == 0) addr = uvm_map_hint(p, prot); else if (!(flags & MAP_TRYFIXED) && addr < (vaddr_t)p->p_vmspace->vm_daddr) addr = uvm_map_hint(p, prot); } /* * check for file mappings (i.e. not anonymous) and verify file. */ if ((flags & MAP_ANON) == 0) { if ((fp = fd_getfile(fdp, fd)) == NULL) return (EBADF); FREF(fp); if (fp->f_type != DTYPE_VNODE) { error = ENODEV; /* only mmap vnodes! */ goto out; } vp = (struct vnode *)fp->f_data; /* convert to vnode */ if (vp->v_type != VREG && vp->v_type != VCHR && vp->v_type != VBLK) { error = ENODEV; /* only REG/CHR/BLK support mmap */ goto out; } if (vp->v_type == VREG && (pos + size) < pos) { error = EINVAL; /* no offset wrapping */ goto out; } /* special case: catch SunOS style /dev/zero */ if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) { flags |= MAP_ANON; FRELE(fp); fp = NULL; goto is_anon; } /* * Old programs may not select a specific sharing type, so * default to an appropriate one. * * XXX: how does MAP_ANON fit in the picture? */ if ((flags & (MAP_SHARED|MAP_PRIVATE)) == 0) { #if defined(DEBUG) printf("WARNING: defaulted mmap() share type to " "%s (pid %d comm %s)\n", vp->v_type == VCHR ? "MAP_SHARED" : "MAP_PRIVATE", p->p_pid, p->p_comm); #endif if (vp->v_type == VCHR) flags |= MAP_SHARED; /* for a device */ else flags |= MAP_PRIVATE; /* for a file */ } /* * MAP_PRIVATE device mappings don't make sense (and aren't * supported anyway). However, some programs rely on this, * so just change it to MAP_SHARED. */ if (vp->v_type == VCHR && (flags & MAP_PRIVATE) != 0) { flags = (flags & ~MAP_PRIVATE) | MAP_SHARED; } #ifdef ANOUBIS /* Force DENYWRITE mappings if file->denywrite is set. */ if (fp->denywrite) flags |= MAP_DENYWRITE; #endif /* * now check protection */ /* * Don't allow the file to be mapped into executable memory if * the underlying file system is marked as 'noexec'. */ if (prot & PROT_EXEC && vp->v_mount->mnt_flag & MNT_NOEXEC) { error = EACCES; goto out; } maxprot = VM_PROT_EXECUTE; /* check read access */ if (fp->f_flag & FREAD) maxprot |= VM_PROT_READ; else if (prot & PROT_READ) { error = EACCES; goto out; } /* PROT_EXEC only makes sense if the descriptor is readable. */ if (!(fp->f_flag & FREAD) && prot & PROT_EXEC) { error = EACCES; goto out; } /* check write access, shared case first */ if (flags & MAP_SHARED) { /* * if the file is writable, only add PROT_WRITE to * maxprot if the file is not immutable, append-only. * otherwise, if we have asked for PROT_WRITE, return * EPERM. */ if (fp->f_flag & FWRITE) { if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) goto out; if ((va.va_flags & (IMMUTABLE|APPEND)) == 0) maxprot |= VM_PROT_WRITE; else if (prot & PROT_WRITE) { error = EPERM; goto out; } } else if (prot & PROT_WRITE) { error = EACCES; goto out; } } else { /* MAP_PRIVATE mappings can always write to */ maxprot |= VM_PROT_WRITE; } #ifdef MAC error = mac_vnode_check_mmap(p->p_ucred, vp, prot, flags); if (error) goto out; #endif vfs_mark_atime(vp, p->p_ucred); /* * set handle to vnode */ handle = (caddr_t)vp; } else { /* MAP_ANON case */ /* * XXX What do we do about (MAP_SHARED|MAP_PRIVATE) == 0? */ if (fd != -1) { error = EINVAL; goto out; } is_anon: /* label for SunOS style /dev/zero */ handle = NULL; maxprot = VM_PROT_ALL; pos = 0; } if ((flags & MAP_ANON) != 0 || ((flags & MAP_PRIVATE) != 0 && (prot & PROT_WRITE) != 0)) { if (size > (p->p_rlimit[RLIMIT_DATA].rlim_cur - ptoa(p->p_vmspace->vm_dused))) { error = ENOMEM; goto out; } } /* * now let kernel internal function uvm_mmap do the work. */ error = uvm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, flags, handle, pos, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur, p); if (error == 0) /* remember to add offset */ *retval = (register_t)(addr + pageoff); out: if (fp) FRELE(fp); return (error); }
int sys_mquery(struct proc *p, void *v, register_t *retval) { struct sys_mquery_args /* { syscallarg(void *) addr; syscallarg(size_t) len; syscallarg(int) prot; syscallarg(int) flags; syscallarg(int) fd; syscallarg(long) pad; syscallarg(off_t) pos; } */ *uap = v; struct file *fp; struct uvm_object *uobj; voff_t uoff; int error; vaddr_t vaddr; int flags = 0; vsize_t size; vm_prot_t prot; int fd; vaddr = (vaddr_t) SCARG(uap, addr); prot = SCARG(uap, prot); size = (vsize_t) SCARG(uap, len); fd = SCARG(uap, fd); if ((prot & VM_PROT_ALL) != prot) return (EINVAL); if (SCARG(uap, flags) & MAP_FIXED) flags |= UVM_FLAG_FIXED; if (fd >= 0) { if ((error = getvnode(p->p_fd, fd, &fp)) != 0) return (error); uobj = &((struct vnode *)fp->f_data)->v_uvm.u_obj; uoff = SCARG(uap, pos); } else { fp = NULL; uobj = NULL; uoff = 0; } if (vaddr == 0) vaddr = uvm_map_hint(p, prot); /* prevent a user requested address from falling in heap space */ if ((vaddr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (vaddr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) { if (flags & UVM_FLAG_FIXED) { error = EINVAL; goto done; } vaddr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); } vm_map_lock(&p->p_vmspace->vm_map); again: if (uvm_map_findspace(&p->p_vmspace->vm_map, vaddr, size, &vaddr, uobj, uoff, 0, flags) == NULL) { if (flags & UVM_FLAG_FIXED) error = EINVAL; else error = ENOMEM; } else { /* prevent a returned address from falling in heap space */ if ((vaddr + size > (vaddr_t)p->p_vmspace->vm_daddr) && (vaddr < (vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ)) { vaddr = round_page((vaddr_t)p->p_vmspace->vm_daddr + MAXDSIZ); goto again; } error = 0; *retval = (register_t)(vaddr); } vm_map_unlock(&p->p_vmspace->vm_map); done: if (fp != NULL) FRELE(fp); return (error); }
int diskmapioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct dk_diskmap *dm; struct nameidata ndp; struct filedesc *fdp; struct file *fp = NULL; struct vnode *vp = NULL, *ovp; char *devname; int fd, error = EINVAL; if (cmd != DIOCMAP) return EINVAL; /* * Map a request for a disk to the correct device. We should be * supplied with either a diskname or a disklabel UID. */ dm = (struct dk_diskmap *)addr; fd = dm->fd; devname = malloc(PATH_MAX, M_DEVBUF, M_WAITOK); if (copyinstr(dm->device, devname, PATH_MAX, NULL)) goto invalid; if (disk_map(devname, devname, PATH_MAX, dm->flags) == 0) if (copyoutstr(devname, dm->device, PATH_MAX, NULL)) goto invalid; /* Attempt to open actual device. */ fdp = p->p_fd; fdplock(fdp); if ((error = getvnode(fdp, fd, &fp)) != 0) goto bad; ndp.ni_segflg = UIO_SYSSPACE; ndp.ni_dirfd = AT_FDCWD; ndp.ni_dirp = devname; ndp.ni_cnd.cn_proc = p; if ((error = vn_open(&ndp, fp->f_flag, 0)) != 0) goto bad; vp = ndp.ni_vp; /* Close the original vnode. */ ovp = (struct vnode *)fp->f_data; if (fp->f_flag & FWRITE) ovp->v_writecount--; if (ovp->v_writecount == 0) { vn_lock(ovp, LK_EXCLUSIVE | LK_RETRY, p); VOP_CLOSE(ovp, fp->f_flag, p->p_ucred); vput(ovp); } fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; fp->f_offset = 0; fp->f_rxfer = 0; fp->f_wxfer = 0; fp->f_seek = 0; fp->f_rbytes = 0; fp->f_wbytes = 0; VOP_UNLOCK(vp, 0); FRELE(fp, p); fdpunlock(fdp); free(devname, M_DEVBUF, 0); return 0; bad: if (vp) vput(vp); if (fp) FRELE(fp, p); fdpunlock(fdp); invalid: free(devname, M_DEVBUF, 0); return (error); }