sockets: make pr_shutdown fully protocol specific method

Disassemble a one-for-all soshutdown() into protocol specific methods.
This creates a small amount of copy & paste, but makes code a lot more
self documented, as protocol specific method would execute only the code
that is relevant to that protocol and nothing else.  This also fixes a
couple recent regressions and reduces risk of future regressions.  The
extended KPI for the new pr_shutdown removes need for the extra pr_flush
which was added for the sake of SCTP which could not perform its shutdown
properly with the old one.  Particularly for SCTP this change streamlines
a lot of code.

Some notes on why certain parts of code were copied or were not to certain
protocols:
* The (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING) check is
  needed only for those protocols that may be connected or disconnected.
* The above reduces into only SS_ISCONNECTED for those protocols that
  always connect instantly.
* The ENOTCONN and continue processing hack is left only for datagram
  protocols.
* The SOLISTENING(so) block is copied to those protocols that listen(2).
* sorflush() on SHUT_RD is copied almost to every protocol, but that
  will be refactored later.
* wakeup(&so->so_timeo) is copied to protocols that can make a non-instant
  connect(2), can SO_LINGER or can accept(2).

There are three protocols (netgraph(4), Bluetooth, SDP) that did not have
pr_shutdown, but old soshutdown() would still perform sorflush() on
SHUT_RD for them and also wakeup(9).  Those protocols partially supported
shutdown(2) returning EOPNOTSUP for SHUT_WR/SHUT_RDWR, now they fully lost
shutdown(2) support.  I'm pretty sure netgraph(4) and Bluetooth are okay
about that and SDP is almost abandoned anyway.

Reviewed by:		tuexen
Differential Revision:	https://reviews.freebsd.org/D43413
This commit is contained in:
Gleb Smirnoff 2024-01-16 10:26:10 -08:00
parent c3276e02be
commit 5bba272807
16 changed files with 311 additions and 238 deletions

View file

@ -978,43 +978,43 @@ hvs_trans_abort(struct socket *so)
}
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);
}

View file

@ -110,7 +110,7 @@ int hvs_trans_soreceive(struct socket *, struct sockaddr **,
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);

View file

@ -151,7 +151,7 @@ pr_ready_notsupp(struct socket *so, struct mbuf *m, int count)
}
static int
pr_shutdown_notsupp(struct socket *so)
pr_shutdown_notsupp(struct socket *so, enum shutdown_how how)
{
return (EOPNOTSUPP);
}

View file

@ -2966,59 +2966,18 @@ soreceive(struct socket *so, struct sockaddr **psa, struct uio *uio,
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)
{

View file

@ -1660,18 +1660,65 @@ uipc_sense(struct socket *so, struct stat *sb)
}
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

View file

@ -450,10 +450,22 @@ rts_disconnect(struct socket *so)
}
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);
}

View file

@ -982,16 +982,27 @@ rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
}
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 */

View file

@ -775,14 +775,39 @@ sctp_disconnect(struct socket *so)
}
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 @@ sctp_flush(struct socket *so, int how)
* 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;
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);
}
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_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;
}
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;
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);
error = ECONNABORTED;
goto out;
}
if (stcb != NULL) {
SCTP_TCB_UNLOCK(stcb);
}
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;
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 {
/*
* 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 @@ sctp_shutdown(struct socket *so)
* 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_shutdown(struct socket *so)
*/
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_shutdown(struct socket *so)
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_shutdown(struct socket *so)
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 @@ sctp_peeraddr(struct socket *so, struct sockaddr *sa)
.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, \

View file

@ -331,7 +331,7 @@ void
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 *);

View file

@ -799,31 +799,57 @@ tcp6_usr_accept(struct socket *so, struct sockaddr *sa)
* 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);
}

View file

@ -1670,16 +1670,42 @@ udp_disconnect(struct socket *so)
#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

View file

@ -168,7 +168,7 @@ udp_get_inpcbinfo(int protocol)
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);

View file

@ -827,16 +827,27 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
}
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);
}

View file

@ -1095,7 +1095,6 @@ sctp6_getpeeraddr(struct socket *so, struct sockaddr *sa)
.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, \

View file

@ -39,6 +39,7 @@ struct thread;
struct sockaddr;
struct socket;
struct sockopt;
enum shutdown_how;
/*#ifdef _KERNEL*/
/*
@ -84,8 +85,7 @@ typedef int pr_send_t(struct socket *, int, struct mbuf *,
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 @@ struct protosw {
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 */
};

View file

@ -633,14 +633,6 @@ enum shutdown_how {
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