diff --git a/sys/dev/hyperv/hvsock/hv_sock.h b/sys/dev/hyperv/hvsock/hv_sock.h --- a/sys/dev/hyperv/hvsock/hv_sock.h +++ b/sys/dev/hyperv/hvsock/hv_sock.h @@ -110,7 +110,7 @@ int hvs_trans_sosend(struct socket *, struct sockaddr *, struct uio *, struct mbuf *, struct mbuf *, int, struct thread *); int hvs_trans_disconnect(struct socket *); -int hvs_trans_shutdown(struct socket *); +int hvs_trans_shutdown(struct socket *, enum shutdown_how); int hvs_trans_lock(void); void hvs_trans_unlock(void); diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c --- a/sys/dev/hyperv/hvsock/hv_sock.c +++ b/sys/dev/hyperv/hvsock/hv_sock.c @@ -978,43 +978,43 @@ } int -hvs_trans_shutdown(struct socket *so) +hvs_trans_shutdown(struct socket *so, enum shutdown_how how) { struct hvs_pcb *pcb = so2hvspcb(so); - struct sockbuf *sb; HVSOCK_DBG(HVSOCK_DBG_VERBOSE, "%s: HyperV Socket hvs_trans_shutdown called\n", __func__); + SOCK_LOCK(so); + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SOCK_UNLOCK(so); + return (ENOTCONN); + } + SOCK_UNLOCK(so); + if (pcb == NULL) return (EINVAL); - /* - * Only get called with the shutdown method is SHUT_WR or - * SHUT_RDWR. - * When the method is SHUT_RD or SHUT_RDWR, the caller - * already set the SBS_CANTRCVMORE on receive side socket - * buffer. - */ - if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) == 0) { - /* - * SHUT_WR only case. - * Receive side is still open. Just close - * the send side. - */ - socantsendmore(so); - } else { - /* SHUT_RDWR case */ + switch (how) { + case SHUT_RD: + socantrcvmore(so); + break; + case SHUT_RDWR: + socantrcvmore(so); if (so->so_state & SS_ISCONNECTED) { /* Send a FIN to peer */ - sb = &so->so_snd; - SOCKBUF_LOCK(sb); - (void) hvsock_send_data(pcb->chan, NULL, 0, sb); - SOCKBUF_UNLOCK(sb); - + SOCK_SENDBUF_LOCK(so); + (void) hvsock_send_data(pcb->chan, NULL, 0, + &so->so_snd); + SOCK_SENDBUF_UNLOCK(so); soisdisconnecting(so); } + /* FALLTHROUGH */ + case SHUT_WR: + socantsendmore(so); } + wakeup(&so->so_timeo); return (0); } diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -151,7 +151,7 @@ } static int -pr_shutdown_notsupp(struct socket *so) +pr_shutdown_notsupp(struct socket *so, enum shutdown_how how) { return (EOPNOTSUPP); } diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -2966,59 +2966,18 @@ int soshutdown(struct socket *so, enum shutdown_how how) { - struct protosw *pr; - int error, soerror_enotconn; - - soerror_enotconn = 0; - SOCK_LOCK(so); - if ((so->so_state & - (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { - /* - * POSIX mandates us to return ENOTCONN when shutdown(2) is - * invoked on a datagram sockets, however historically we would - * actually tear socket down. This is known to be leveraged by - * some applications to unblock process waiting in recvXXX(2) - * by other process that it shares that socket with. Try to meet - * both backward-compatibility and POSIX requirements by forcing - * ENOTCONN but still asking protocol to perform pru_shutdown(). - */ - if (so->so_type != SOCK_DGRAM && !SOLISTENING(so)) { - SOCK_UNLOCK(so); - return (ENOTCONN); - } - soerror_enotconn = 1; - } - - if (SOLISTENING(so)) { - if (how != SHUT_WR) { - so->so_error = ECONNABORTED; - solisten_wakeup(so); /* unlocks so */ - } else { - SOCK_UNLOCK(so); - } - goto done; - } - SOCK_UNLOCK(so); + int error; CURVNET_SET(so->so_vnet); - pr = so->so_proto; - if (pr->pr_flush != NULL) - pr->pr_flush(so, how); - if (how != SHUT_WR && !(pr->pr_flags & PR_SOCKBUF)) - sorflush(so); - if (how != SHUT_RD) { - error = pr->pr_shutdown(so); - wakeup(&so->so_timeo); - CURVNET_RESTORE(); - return ((error == 0 && soerror_enotconn) ? ENOTCONN : error); - } - wakeup(&so->so_timeo); + error = so->so_proto->pr_shutdown(so, how); CURVNET_RESTORE(); -done: - return (soerror_enotconn ? ENOTCONN : 0); + return (error); } +/* + * Used by several pr_shutdown implementations that use generic socket buffers. + */ void sorflush(struct socket *so) { diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1660,18 +1660,65 @@ } static int -uipc_shutdown(struct socket *so) +uipc_shutdown(struct socket *so, enum shutdown_how how) { - struct unpcb *unp; + struct unpcb *unp = sotounpcb(so); + int error; - unp = sotounpcb(so); - KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); + SOCK_LOCK(so); + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + /* + * POSIX mandates us to just return ENOTCONN when shutdown(2) is + * invoked on a datagram sockets, however historically we would + * actually tear socket down. This is known to be leveraged by + * some applications to unblock process waiting in recv(2) by + * other process that it shares that socket with. Try to meet + * both backward-compatibility and POSIX requirements by forcing + * ENOTCONN but still flushing buffers and performing wakeup(9). + * + * XXXGL: it remains unknown what applications expect this + * behavior and is this isolated to unix/dgram or inet/dgram or + * both. See: D10351, D3039. + */ + error = ENOTCONN; + if (so->so_type != SOCK_DGRAM) { + SOCK_UNLOCK(so); + return (error); + } + } else + error = 0; + if (SOLISTENING(so)) { + if (how != SHUT_WR) { + so->so_error = ECONNABORTED; + solisten_wakeup(so); /* unlocks so */ + } else + SOCK_UNLOCK(so); + return (0); + } + SOCK_UNLOCK(so); - UNP_PCB_LOCK(unp); - socantsendmore(so); - unp_shutdown(unp); - UNP_PCB_UNLOCK(unp); - return (0); + switch (how) { + case SHUT_RD: + /* + * XXXGL: so far it is safe to call sorflush() on unix/dgram, + * because PR_RIGHTS flag saves us from destructive sbrelease() + * on our protocol specific buffers. + */ + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + UNP_PCB_LOCK(unp); + socantsendmore(so); + unp_shutdown(unp); + UNP_PCB_UNLOCK(unp); + } + wakeup(&so->so_timeo); + + return (error); } static int diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -450,10 +450,22 @@ } static int -rts_shutdown(struct socket *so) +rts_shutdown(struct socket *so, enum shutdown_how how) { + /* + * Note: route socket marks itself as connected through its lifetime. + */ + switch (how) { + case SHUT_RD: + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + socantsendmore(so); + } - socantsendmore(so); return (0); } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -982,16 +982,27 @@ } static int -rip_shutdown(struct socket *so) +rip_shutdown(struct socket *so, enum shutdown_how how) { - struct inpcb *inp; - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("rip_shutdown: inp == NULL")); + SOCK_LOCK(so); + if (!(so->so_state & SS_ISCONNECTED)) { + SOCK_UNLOCK(so); + return (ENOTCONN); + } + SOCK_UNLOCK(so); + + switch (how) { + case SHUT_RD: + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + socantsendmore(so); + } - INP_WLOCK(inp); - socantsendmore(so); - INP_WUNLOCK(inp); return (0); } #endif /* INET */ diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -775,14 +775,39 @@ } int -sctp_flush(struct socket *so, int how) +sctp_shutdown(struct socket *so, enum shutdown_how how) { + struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb; struct epoch_tracker et; struct sctp_tcb *stcb; + struct sctp_association *asoc; + struct sctp_nets *netp; struct sctp_queued_to_read *control, *ncontrol; - struct sctp_inpcb *inp; struct mbuf *m, *op_err; bool need_to_abort = false; + int error = 0; + + MPASS(inp); + + if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) + return (EOPNOTSUPP); + + SOCK_LOCK(so); + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SOCK_UNLOCK(so); + return (ENOTCONN); + } + if (SOLISTENING(so)) { + if (how != SHUT_WR) { + so->so_error = ECONNABORTED; + solisten_wakeup(so); /* unlocks so */ + } else + SOCK_UNLOCK(so); + return (0); + } + SOCK_UNLOCK(so); /* * For 1-to-1 style sockets, flush the read queue and trigger an @@ -790,106 +815,70 @@ * messages are lost. Loosing notifications does not need to be * signalled to the peer. */ - if (how == PRU_FLUSH_WR) { - /* This function is only relevant for the read directions. */ - return (0); - } - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_INP_WLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { - /* For 1-to-many style sockets this function does nothing. */ - SCTP_INP_WUNLOCK(inp); - return (0); - } - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb != NULL) { - SCTP_TCB_LOCK(stcb); - } - SCTP_INP_READ_LOCK(inp); - inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; - SOCK_LOCK(so); - TAILQ_FOREACH_SAFE(control, &inp->read_queue, next, ncontrol) { - if ((control->spec_flags & M_NOTIFICATION) == 0) { - need_to_abort = true; - } - TAILQ_REMOVE(&inp->read_queue, control, next); - control->on_read_q = 0; - for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { - sctp_sbfree(control, control->stcb, &so->so_rcv, m); - } - if (control->on_strm_q == 0) { - sctp_free_remote_addr(control->whoFrom); - if (control->data) { - sctp_m_freem(control->data); - control->data = NULL; - } - sctp_free_a_readq(stcb, control); - } else { - stcb->asoc.size_on_all_streams += control->length; + switch (how) { + case SHUT_RD: + case SHUT_RDWR: + SCTP_INP_WLOCK(inp); + stcb = LIST_FIRST(&inp->sctp_asoc_list); + if (stcb != NULL) { + SCTP_TCB_LOCK(stcb); } - } - SOCK_UNLOCK(so); - SCTP_INP_READ_UNLOCK(inp); - if (need_to_abort && (stcb != NULL)) { - inp->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; - SCTP_INP_WUNLOCK(inp); - op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, ""); - NET_EPOCH_ENTER(et); - sctp_abort_an_association(inp, stcb, op_err, false, SCTP_SO_LOCKED); - NET_EPOCH_EXIT(et); - return (ECONNABORTED); - } - if (stcb != NULL) { - SCTP_TCB_UNLOCK(stcb); - } - SCTP_INP_WUNLOCK(inp); - return (0); -} - -int -sctp_shutdown(struct socket *so) -{ - struct sctp_inpcb *inp; + SCTP_INP_READ_LOCK(inp); + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; + SOCK_LOCK(so); + TAILQ_FOREACH_SAFE(control, &inp->read_queue, next, ncontrol) { + if ((control->spec_flags & M_NOTIFICATION) == 0) { + need_to_abort = true; + } + TAILQ_REMOVE(&inp->read_queue, control, next); + control->on_read_q = 0; + for (m = control->data; m; m = SCTP_BUF_NEXT(m)) { + sctp_sbfree(control, control->stcb, + &so->so_rcv, m); + } + if (control->on_strm_q == 0) { + sctp_free_remote_addr(control->whoFrom); + if (control->data) { + sctp_m_freem(control->data); + control->data = NULL; + } + sctp_free_a_readq(stcb, control); + } else { + stcb->asoc.size_on_all_streams += + control->length; + } + } + SOCK_UNLOCK(so); + SCTP_INP_READ_UNLOCK(inp); + if (need_to_abort && (stcb != NULL)) { + inp->last_abort_code = SCTP_FROM_SCTP_USRREQ + + SCTP_LOC_6; + SCTP_INP_WUNLOCK(inp); + op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, + ""); + NET_EPOCH_ENTER(et); + sctp_abort_an_association(inp, stcb, op_err, false, + SCTP_SO_LOCKED); + NET_EPOCH_EXIT(et); - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_INP_RLOCK(inp); - /* For UDP model this is a invalid call */ - if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { - /* Restore the flags that the soshutdown took away. */ - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; - SOCKBUF_UNLOCK(&so->so_rcv); - /* This proc will wakeup for read and do nothing (I hope) */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); - return (EOPNOTSUPP); - } else { + error = ECONNABORTED; + goto out; + } + if (stcb != NULL) { + SCTP_TCB_UNLOCK(stcb); + } + SCTP_INP_WUNLOCK(inp); /* - * Ok, if we reach here its the TCP model and it is either a - * SHUT_WR or SHUT_RDWR. This means we put the shutdown flag - * against it. + * XXXGL: does SCTP need sorflush()? This is what old + * soshutdown() used to do for all kinds of sockets. */ - struct epoch_tracker et; - struct sctp_tcb *stcb; - struct sctp_association *asoc; - struct sctp_nets *netp; + sorflush(so); + if (how == SHUT_RD) + break; + /* FALLTHROUGH */ - if ((so->so_state & - (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { - SCTP_INP_RUNLOCK(inp); - return (ENOTCONN); - } + case SHUT_WR: socantsendmore(so); - stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { /* @@ -898,14 +887,14 @@ * now. */ SCTP_INP_RUNLOCK(inp); - return (0); + goto out; } SCTP_TCB_LOCK(stcb); asoc = &stcb->asoc; if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { SCTP_TCB_UNLOCK(stcb); SCTP_INP_RUNLOCK(inp); - return (0); + goto out; } if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) && (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_ECHOED) && @@ -916,7 +905,7 @@ */ SCTP_TCB_UNLOCK(stcb); SCTP_INP_RUNLOCK(inp); - return (0); + goto out; } NET_EPOCH_ENTER(et); if (stcb->asoc.alternate) { @@ -961,7 +950,7 @@ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_LOCKED); NET_EPOCH_EXIT(et); - return (0); + goto out; } } /* @@ -972,8 +961,11 @@ SCTP_TCB_UNLOCK(stcb); SCTP_INP_RUNLOCK(inp); NET_EPOCH_EXIT(et); - return (0); } +out: + wakeup(&so->so_timeo); + + return (error); } /* @@ -7523,7 +7515,6 @@ .pr_close = sctp_close, \ .pr_detach = sctp_close, \ .pr_sopoll = sopoll_generic, \ - .pr_flush = sctp_flush, \ .pr_disconnect = sctp_disconnect, \ .pr_listen = sctp_listen, \ .pr_peeraddr = sctp_peeraddr, \ diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -331,7 +331,7 @@ sctp_notify(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint8_t, uint8_t, uint16_t, uint32_t); int sctp_flush(struct socket *, int); -int sctp_shutdown(struct socket *); +int sctp_shutdown(struct socket *, enum shutdown_how); int sctp_bindx(struct socket *, int, struct sockaddr_storage *, int, int, struct proc *); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -799,31 +799,57 @@ * Mark the connection as being incapable of further output. */ static int -tcp_usr_shutdown(struct socket *so) +tcp_usr_shutdown(struct socket *so, enum shutdown_how how) { - int error = 0; - struct inpcb *inp; - struct tcpcb *tp; struct epoch_tracker et; + struct inpcb *inp = sotoinpcb(so); + struct tcpcb *tp = intotcpcb(inp); + int error = 0; - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("inp == NULL")); - INP_WLOCK(inp); - if (inp->inp_flags & INP_DROPPED) { - INP_WUNLOCK(inp); - return (ECONNRESET); + SOCK_LOCK(so); + if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SOCK_UNLOCK(so); + return (ENOTCONN); } - tp = intotcpcb(inp); + if (SOLISTENING(so)) { + if (how != SHUT_WR) { + so->so_error = ECONNABORTED; + solisten_wakeup(so); /* unlocks so */ + } else + SOCK_UNLOCK(so); + return (0); + } + SOCK_UNLOCK(so); - NET_EPOCH_ENTER(et); - socantsendmore(so); - tcp_usrclosed(tp); - if (!(inp->inp_flags & INP_DROPPED)) + switch (how) { + case SHUT_RD: + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + /* + * XXXGL: mimicing old soshutdown() here. But shouldn't we + * return ECONNRESEST for SHUT_RD as well? + */ + INP_WLOCK(inp); + if (inp->inp_flags & INP_DROPPED) { + INP_WUNLOCK(inp); + return (ECONNRESET); + } + + socantsendmore(so); + NET_EPOCH_ENTER(et); + tcp_usrclosed(tp); error = tcp_output_nodrop(tp); - tcp_bblog_pru(tp, PRU_SHUTDOWN, error); - TCP_PROBE2(debug__user, tp, PRU_SHUTDOWN); - error = tcp_unlock_or_drop(tp, error); - NET_EPOCH_EXIT(et); + tcp_bblog_pru(tp, PRU_SHUTDOWN, error); + TCP_PROBE2(debug__user, tp, PRU_SHUTDOWN); + error = tcp_unlock_or_drop(tp, error); + NET_EPOCH_EXIT(et); + } + wakeup(&so->so_timeo); return (error); } diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1670,16 +1670,42 @@ #endif /* INET */ int -udp_shutdown(struct socket *so) +udp_shutdown(struct socket *so, enum shutdown_how how) { - struct inpcb *inp; + int error; - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("udp_shutdown: inp == NULL")); - INP_WLOCK(inp); - socantsendmore(so); - INP_WUNLOCK(inp); - return (0); + SOCK_LOCK(so); + if (!(so->so_state & SS_ISCONNECTED)) + /* + * POSIX mandates us to just return ENOTCONN when shutdown(2) is + * invoked on a datagram sockets, however historically we would + * actually tear socket down. This is known to be leveraged by + * some applications to unblock process waiting in recv(2) by + * other process that it shares that socket with. Try to meet + * both backward-compatibility and POSIX requirements by forcing + * ENOTCONN but still flushing buffers and performing wakeup(9). + * + * XXXGL: it remains unknown what applications expect this + * behavior and is this isolated to unix/dgram or inet/dgram or + * both. See: D10351, D3039. + */ + error = ENOTCONN; + else + error = 0; + SOCK_UNLOCK(so); + + switch (how) { + case SHUT_RD: + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + socantsendmore(so); + } + + return (error); } #ifdef INET diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -168,7 +168,7 @@ int udp_ctloutput(struct socket *, struct sockopt *); void udplite_input(struct mbuf *, int); struct inpcb *udp_notify(struct inpcb *inp, int errno); -int udp_shutdown(struct socket *so); +int udp_shutdown(struct socket *, enum shutdown_how); int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f, udp_tun_icmp_t i, void *ctx); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -827,16 +827,27 @@ } static int -rip6_shutdown(struct socket *so) +rip6_shutdown(struct socket *so, enum shutdown_how how) { - struct inpcb *inp; - inp = sotoinpcb(so); - KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL")); + SOCK_LOCK(so); + if (!(so->so_state & SS_ISCONNECTED)) { + SOCK_UNLOCK(so); + return (ENOTCONN); + } + SOCK_UNLOCK(so); + + switch (how) { + case SHUT_RD: + sorflush(so); + break; + case SHUT_RDWR: + sorflush(so); + /* FALLTHROUGH */ + case SHUT_WR: + socantsendmore(so); + } - INP_WLOCK(inp); - socantsendmore(so); - INP_WUNLOCK(inp); return (0); } diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -1095,7 +1095,6 @@ .pr_close = sctp6_close, \ .pr_detach = sctp6_close, \ .pr_sopoll = sopoll_generic, \ - .pr_flush = sctp_flush, \ .pr_disconnect = sctp_disconnect, \ .pr_listen = sctp_listen, \ .pr_peeraddr = sctp6_getpeeraddr, \ diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -39,6 +39,7 @@ struct sockaddr; struct socket; struct sockopt; +enum shutdown_how; /*#ifdef _KERNEL*/ /* @@ -84,8 +85,7 @@ struct sockaddr *, struct mbuf *, struct thread *); typedef int pr_ready_t(struct socket *, struct mbuf *, int); typedef int pr_sense_t(struct socket *, struct stat *); -typedef int pr_shutdown_t(struct socket *); -typedef int pr_flush_t(struct socket *, int); +typedef int pr_shutdown_t(struct socket *, enum shutdown_how); typedef int pr_sockaddr_t(struct socket *, struct sockaddr *); typedef int pr_sosend_t(struct socket *, struct sockaddr *, struct uio *, struct mbuf *, struct mbuf *, int, struct thread *); @@ -137,7 +137,6 @@ pr_peeraddr_t *pr_peeraddr; /* getpeername(2) */ pr_sockaddr_t *pr_sockaddr; /* getsockname(2) */ pr_sense_t *pr_sense; /* stat(2) */ - pr_flush_t *pr_flush; /* XXXGL: merge with pr_shutdown_t! */ pr_sosetlabel_t *pr_sosetlabel; /* MAC, XXXGL: remove */ pr_setsbopt_t *pr_setsbopt; /* Socket buffer ioctls */ }; diff --git a/sys/sys/socket.h b/sys/sys/socket.h --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -633,14 +633,6 @@ SHUT_RDWR /* shut down both sides */ }; -#if __BSD_VISIBLE -/* for SCTP */ -/* we cheat and use the SHUT_XX defines for these */ -#define PRU_FLUSH_RD SHUT_RD -#define PRU_FLUSH_WR SHUT_WR -#define PRU_FLUSH_RDWR SHUT_RDWR -#endif - #if __BSD_VISIBLE /* * sendfile(2) header/trailer struct