__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); }