Exemple #1
0
/* 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);
}
Exemple #2
0
/* 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);
}
Exemple #3
0
/* 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);
}
Exemple #4
0
/* 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);
}
Exemple #5
0
/* 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);
}
Exemple #6
0
/*
 * 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);
}
Exemple #7
0
/* 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);
}
Exemple #8
0
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;
}
Exemple #9
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);
}
Exemple #10
0
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;
}
Exemple #11
0
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);
}
Exemple #12
0
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);
}
Exemple #13
0
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);
}
Exemple #14
0
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);
}
Exemple #15
0
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);
}
Exemple #16
0
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);
}