sys/netinet/sctp_usrreq.c
void
sctp_shutdown(netmsg_t msg)
{
	struct socket *so = msg->shutdown.base.nm_so;
	struct sctp_inpcb *inp;
	int error;

	inp = (struct sctp_inpcb *)so->so_pcb;
	if (inp == NULL) {
		error = EINVAL;
		goto out;
	}
	SCTP_INP_RLOCK(inp);
	/* For UDP model this is a invalid call */
	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
		/* Restore the flags that the soshutdown took away. */
#if defined(__FreeBSD__) && __FreeBSD_version >= 502115
		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
#else
		soclrstate(so, SS_CANTRCVMORE);
#endif
		/* This proc will wakeup for read and do nothing (I hope) */
		SCTP_INP_RUNLOCK(inp);
		error = EOPNOTSUPP;
		goto out;
	}
	/*
	 * 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.
	 */
	{
		int some_on_streamwheel = 0;
		struct sctp_tcb *stcb;
		struct sctp_association *asoc;
		socantsendmore(so);

		stcb = LIST_FIRST(&inp->sctp_asoc_list);
		if (stcb == NULL) {
			/*
			 * Ok we hit the case that the shutdown call was made
			 * after an abort or something. Nothing to do now.
			 */
			error = 0;
			goto out;
		}
		SCTP_TCB_LOCK(stcb);
		asoc = &stcb->asoc;

		if (!TAILQ_EMPTY(&asoc->out_wheel)) {
			/* Check to see if some data queued */
			struct sctp_stream_out *outs;
			TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
				if (!TAILQ_EMPTY(&outs->outqueue)) {
					some_on_streamwheel = 1;
					break;
				}
			}
		}
		if (TAILQ_EMPTY(&asoc->send_queue) &&
		    TAILQ_EMPTY(&asoc->sent_queue) &&
		    (some_on_streamwheel == 0)) {
			/* there is nothing queued to send, so I'm done... */
			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
				/* only send SHUTDOWN the first time through */
#ifdef SCTP_DEBUG
				if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
					kprintf("%s:%d sends a shutdown\n",
					       __FILE__,
					       __LINE__
						);
				}
#endif
				sctp_send_shutdown(stcb,
						   stcb->asoc.primary_destination);
				sctp_chunk_output(stcb->sctp_ep, stcb, 1);
				asoc->state = SCTP_STATE_SHUTDOWN_SENT;
				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
						 stcb->sctp_ep, stcb,
						 asoc->primary_destination);
				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
						 stcb->sctp_ep, stcb,
						 asoc->primary_destination);
			}
		} else {
			/*
			 * we still got (or just got) data to send, so
			 * set SHUTDOWN_PENDING
			 */
			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
		}
		SCTP_TCB_UNLOCK(stcb);
	}
	SCTP_INP_RUNLOCK(inp);
	error = 0;
out:
	lwkt_replymsg(&msg->lmsg, error);
}
/* also called from ipv6 sctp code */
also called from ipv6 sctp code
also called from ipv6 sctp code
void
sctp_shutdown(netmsg_t msg)
{
	struct socket *so = msg->shutdown.base.nm_so;
	struct sctp_inpcb *inp;
	int error;
	inp = (struct sctp_inpcb *)so->so_pcb;
	if (inp == NULL) {
		error = EINVAL;
		goto out;
	}
	SCTP_INP_RLOCK(inp);
	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
#if defined(__FreeBSD__) && __FreeBSD_version >= 502115
		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
#else
		soclrstate(so, SS_CANTRCVMORE);
#endif
		SCTP_INP_RUNLOCK(inp);
		error = EOPNOTSUPP;
		goto out;
	}
	{
		int some_on_streamwheel = 0;
		struct sctp_tcb *stcb;
		struct sctp_association *asoc;
		socantsendmore(so);
		stcb = LIST_FIRST(&inp->sctp_asoc_list);
		if (stcb == NULL) {
			error = 0;
			goto out;
		}
		SCTP_TCB_LOCK(stcb);
		asoc = &stcb->asoc;
		if (!TAILQ_EMPTY(&asoc->out_wheel)) {
			struct sctp_stream_out *outs;
			TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
				if (!TAILQ_EMPTY(&outs->outqueue)) {
					some_on_streamwheel = 1;
					break;
				}
			}
		}
		if (TAILQ_EMPTY(&asoc->send_queue) &&
		    TAILQ_EMPTY(&asoc->sent_queue) &&
		    (some_on_streamwheel == 0)) {
			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
#ifdef SCTP_DEBUG
				if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
					kprintf("%s:%d sends a shutdown\n",
					       __FILE__,
					       __LINE__
						);
				}
#endif
				sctp_send_shutdown(stcb,
						   stcb->asoc.primary_destination);
				sctp_chunk_output(stcb->sctp_ep, stcb, 1);
				asoc->state = SCTP_STATE_SHUTDOWN_SENT;
				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
						 stcb->sctp_ep, stcb,
						 asoc->primary_destination);
				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
						 stcb->sctp_ep, stcb,
						 asoc->primary_destination);
			}
		} else {
			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
		}
		SCTP_TCB_UNLOCK(stcb);
	}
	SCTP_INP_RUNLOCK(inp);
	error = 0;
out:
	lwkt_replymsg(&msg->lmsg, error);
}
void sctp_shutdown ( netmsg_t msg ) { struct socket * so = msg -> shutdown . base . nm_so ; struct sctp_inpcb * inp ; int error ; inp = ( struct sctp_inpcb * ) so -> so_pcb ; if ( inp == NULL ) { error = EINVAL ; goto out ; } SCTP_INP_RLOCK ( inp ) ; if ( inp -> sctp_flags & SCTP_PCB_FLAGS_UDPTYPE ) { #if defined ( __FreeBSD__ ) && __FreeBSD_version >= 502115 so -> so_rcv . sb_state &= ~ SBS_CANTRCVMORE ; #else soclrstate ( so , SS_CANTRCVMORE ) ; #endif SCTP_INP_RUNLOCK ( inp ) ; error = EOPNOTSUPP ; goto out ; } { int some_on_streamwheel = 0 ; struct sctp_tcb * stcb ; struct sctp_association * asoc ; socantsendmore ( so ) ; stcb = LIST_FIRST ( & inp -> sctp_asoc_list ) ; if ( stcb == NULL ) { error = 0 ; goto out ; } SCTP_TCB_LOCK ( stcb ) ; asoc = & stcb -> asoc ; if ( ! TAILQ_EMPTY ( & asoc -> out_wheel ) ) { struct sctp_stream_out * outs ; TAILQ_FOREACH ( outs , & asoc -> out_wheel , next_spoke ) { if ( ! TAILQ_EMPTY ( & outs -> outqueue ) ) { some_on_streamwheel = 1 ; break ; } } } if ( TAILQ_EMPTY ( & asoc -> send_queue ) && TAILQ_EMPTY ( & asoc -> sent_queue ) && ( some_on_streamwheel == 0 ) ) { if ( SCTP_GET_STATE ( asoc ) != SCTP_STATE_SHUTDOWN_SENT ) { #ifdef SCTP_DEBUG if ( sctp_debug_on & SCTP_DEBUG_OUTPUT4 ) { kprintf ( " \n " , __FILE__ , __LINE__ ) ; } #endif sctp_send_shutdown ( stcb , stcb -> asoc . primary_destination ) ; sctp_chunk_output ( stcb -> sctp_ep , stcb , 1 ) ; asoc -> state = SCTP_STATE_SHUTDOWN_SENT ; sctp_timer_start ( SCTP_TIMER_TYPE_SHUTDOWN , stcb -> sctp_ep , stcb , asoc -> primary_destination ) ; sctp_timer_start ( SCTP_TIMER_TYPE_SHUTDOWNGUARD , stcb -> sctp_ep , stcb , asoc -> primary_destination ) ; } } else { asoc -> state |= SCTP_STATE_SHUTDOWN_PENDING ; } SCTP_TCB_UNLOCK ( stcb ) ; } SCTP_INP_RUNLOCK ( inp ) ; error = 0 ; out : lwkt_replymsg ( & msg -> lmsg , error ) ; }
also called from ipv6 sctp code
also called from ipv6 sctp code
/* For UDP model this is a invalid call */ /* Restore the flags that the soshutdown took away. */ /* This proc will wakeup for read and do nothing (I hope) */ /*
	 * 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.
	 */ /*
			 * Ok we hit the case that the shutdown call was made
			 * after an abort or something. Nothing to do now.
			 */ /* Check to see if some data queued */ /* there is nothing queued to send, so I'm done... */ /* only send SHUTDOWN the first time through */ /*
			 * we still got (or just got) data to send, so
			 * set SHUTDOWN_PENDING
			 */