Beispiel #1
0
__private_extern__ int
soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
{
	int error = 0;
	int int_arg;

	socket_lock(so, 1);

	/* call the socket filter's ioctl handler anything but ours */
	if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') {
		switch (cmd) {
		case SIOCGASSOCIDS32:
		case SIOCGASSOCIDS64:
		case SIOCGCONNIDS32:
		case SIOCGCONNIDS64:
		case SIOCGCONNINFO32:
		case SIOCGCONNINFO64:
		case SIOCSCONNORDER:
		case SIOCGCONNORDER:
			/* don't pass to filter */
			break;

		default:
			error = sflt_ioctl(so, cmd, data);
			if (error != 0)
				goto out;
			break;
		}
	}

	switch (cmd) {
	case FIONBIO:			/* int */
		bcopy(data, &int_arg, sizeof (int_arg));
		if (int_arg)
			so->so_state |= SS_NBIO;
		else
			so->so_state &= ~SS_NBIO;

		goto out;

	case FIOASYNC:			/* int */
		bcopy(data, &int_arg, sizeof (int_arg));
		if (int_arg) {
			so->so_state |= SS_ASYNC;
			so->so_rcv.sb_flags |= SB_ASYNC;
			so->so_snd.sb_flags |= SB_ASYNC;
		} else {
			so->so_state &= ~SS_ASYNC;
			so->so_rcv.sb_flags &= ~SB_ASYNC;
			so->so_snd.sb_flags &= ~SB_ASYNC;
		}
		goto out;

	case FIONREAD:			/* int */
		bcopy(&so->so_rcv.sb_cc, data, sizeof (u_int32_t));
		goto out;

	case SIOCSPGRP:			/* int */
		bcopy(data, &so->so_pgid, sizeof (pid_t));
		goto out;

	case SIOCGPGRP:			/* int */
		bcopy(&so->so_pgid, data, sizeof (pid_t));
		goto out;

	case SIOCATMARK:		/* int */
		int_arg = (so->so_state & SS_RCVATMARK) != 0;
		bcopy(&int_arg, data, sizeof (int_arg));
		goto out;

	case SIOCSETOT:			/* int; deprecated */
		error = EOPNOTSUPP;
		goto out;

	case SIOCGASSOCIDS32:		/* so_aidreq32 */
	case SIOCGASSOCIDS64:		/* so_aidreq64 */
	case SIOCGCONNIDS32:		/* so_cidreq32 */
	case SIOCGCONNIDS64:		/* so_cidreq64 */
	case SIOCGCONNINFO32:		/* so_cinforeq32 */
	case SIOCGCONNINFO64:		/* so_cinforeq64 */
	case SIOCSCONNORDER:		/* so_cordreq */
	case SIOCGCONNORDER:		/* so_cordreq */
		error = (*so->so_proto->pr_usrreqs->pru_control)(so,
		    cmd, data, NULL, p);
		goto out;
	}

	/*
	 * Interface/routing/protocol specific ioctls:
	 * interface and routing ioctls should have a
	 * different entry since a socket's unnecessary
	 */
	if (IOCGROUP(cmd) == 'i') {
		error = ifioctllocked(so, cmd, data, p);
	} else {
		if (IOCGROUP(cmd) == 'r')
			error = rtioctl(cmd, data, p);
		else
			error = (*so->so_proto->pr_usrreqs->pru_control)(so,
			    cmd, data, NULL, p);
	}

out:
	socket_unlock(so, 1);

	if (error == EJUSTRETURN)
		error = 0;

	return (error);
}
__private_extern__ int
soioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
{
    struct sockopt sopt;
    int error = 0;
    int dropsockref = -1;

    socket_lock(so, 1);

    sopt.sopt_level = cmd;
    sopt.sopt_name = (int)data;
    sopt.sopt_p = p;

    /* Call the socket filter's ioctl handler for most ioctls */
    if (IOCGROUP(cmd) != 'i' && IOCGROUP(cmd) != 'r') {
        int filtered = 0;
        struct socket_filter_entry *filter;

        for (filter = so->so_filt; filter && error == 0;
                filter = filter->sfe_next_onsocket) {
            if (filter->sfe_filter->sf_filter.sf_ioctl) {
                if (filtered == 0) {
                    sflt_use(so);
                    socket_unlock(so, 0);
                    filtered = 1;
                }
                error = filter->sfe_filter->sf_filter.
                        sf_ioctl(filter->sfe_cookie, so, cmd, data);
            }
        }

        if (filtered) {
            socket_lock(so, 0);
            sflt_unuse(so);
        }

        if (error != 0)
            goto out;
    }

    switch (cmd) {

    case FIONBIO:
        if (*(int *)data)
            so->so_state |= SS_NBIO;
        else
            so->so_state &= ~SS_NBIO;

        goto out;

    case FIOASYNC:
        if (*(int *)data) {
            so->so_state |= SS_ASYNC;
            so->so_rcv.sb_flags |= SB_ASYNC;
            so->so_snd.sb_flags |= SB_ASYNC;
        } else {
            so->so_state &= ~SS_ASYNC;
            so->so_rcv.sb_flags &= ~SB_ASYNC;
            so->so_snd.sb_flags &= ~SB_ASYNC;
        }
        goto out;

    case FIONREAD:
        *(int *)data = so->so_rcv.sb_cc;
        goto out;

    case SIOCSPGRP:
        so->so_pgid = *(int *)data;
        goto out;

    case SIOCGPGRP:
        *(int *)data = so->so_pgid;
        goto out;

    case SIOCATMARK:
        *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
        goto out;

    case SIOCSETOT: {
        /*
         * Set socket level options here and then call protocol
         * specific routine.
         */
        struct socket *cloned_so = NULL;
        int cloned_fd = *(int *)data;

        /* let's make sure it's either -1 or a valid file descriptor */
        if (cloned_fd != -1) {
            error = file_socket(cloned_fd, &cloned_so);
            if (error) {
                goto out;
            }
            dropsockref = cloned_fd;
        }

        /* Always set socket non-blocking for OT */
        so->so_state |= SS_NBIO;
        so->so_options |= SO_DONTTRUNC | SO_WANTMORE;
        so->so_flags |= SOF_NOSIGPIPE;

        if (cloned_so && so != cloned_so) {
            /* Flags options */
            so->so_options |=
                cloned_so->so_options & ~SO_ACCEPTCONN;

            /* SO_LINGER */
            if (so->so_options & SO_LINGER)
                so->so_linger = cloned_so->so_linger;

            /* SO_SNDBUF, SO_RCVBUF */
            if (cloned_so->so_snd.sb_hiwat > 0) {
                if (sbreserve(&so->so_snd,
                              cloned_so->so_snd.sb_hiwat) == 0) {
                    error = ENOBUFS;
                    goto out;
                }
            }
            if (cloned_so->so_rcv.sb_hiwat > 0) {
                if (sbreserve(&so->so_rcv,
                              cloned_so->so_rcv.sb_hiwat) == 0) {
                    error = ENOBUFS;
                    goto out;
                }
            }

            /* SO_SNDLOWAT, SO_RCVLOWAT */
            so->so_snd.sb_lowat =
                (cloned_so->so_snd.sb_lowat > so->so_snd.sb_hiwat) ?
                so->so_snd.sb_hiwat : cloned_so->so_snd.sb_lowat;
            so->so_rcv.sb_lowat =
                (cloned_so->so_rcv.sb_lowat > so->so_rcv.sb_hiwat) ?
                so->so_rcv.sb_hiwat : cloned_so->so_rcv.sb_lowat;

            /* SO_SNDTIMEO, SO_RCVTIMEO */
            so->so_snd.sb_timeo = cloned_so->so_snd.sb_timeo;
            so->so_rcv.sb_timeo = cloned_so->so_rcv.sb_timeo;
        }

        error = (*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
                data, 0, p);
        /* Just ignore protocols that do not understand it */
        if (error == EOPNOTSUPP)
            error = 0;

        goto out;
    }
    }
    /*
     * Interface/routing/protocol specific ioctls:
     * interface and routing ioctls should have a
     * different entry since a socket's unnecessary
     */
    if (IOCGROUP(cmd) == 'i') {
        error = ifioctllocked(so, cmd, data, p);
    } else {
        if (IOCGROUP(cmd) == 'r')
            error = rtioctl(cmd, data, p);
        else
            error = (*so->so_proto->pr_usrreqs->pru_control)(so,
                    cmd, data, 0, p);
    }

out:
    if (dropsockref != -1)
        file_drop(dropsockref);
    socket_unlock(so, 1);

    if (error == EJUSTRETURN)
        error = 0;

    return (error);
}