FreeBSD/sys/netinet/sctp_asconf.c
/*
 * add an asconf operation for the given ifa and type.
 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
 * returns 0 if completed, -1 if not completed, 1 if immediate send is
 * advisable.
 */
add an asconf operation for the given ifa and type.
add an asconf operation for the given ifa and type .
static int
sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
    uint16_t type)
{
	uint32_t status;
	int pending_delete_queued = 0;
	int last;
	if (stcb->asoc.asconf_supported == 0) {
		return (-1);
	}
	if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending) {
		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
			last = (sctp_local_addr_count(stcb) == 0);
		} else {
			last = (sctp_local_addr_count(stcb) == 1);
		}
		if (last) {
			stcb->asoc.asconf_del_pending = 1;
			stcb->asoc.asconf_addr_del_pending = ifa;
			atomic_add_int(&ifa->refcount, 1);
			SCTPDBG(SCTP_DEBUG_ASCONF2,
			    "asconf_queue_add: mark delete last address pending\n");
			return (-1);
		}
	}
	status = sctp_asconf_queue_mgmt(stcb, ifa, type);
	if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
		if (sctp_asconf_queue_mgmt(stcb,
		    stcb->asoc.asconf_addr_del_pending,
		    SCTP_DEL_IP_ADDRESS) == 0) {
			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n");
			pending_delete_queued = 1;
			stcb->asoc.asconf_del_pending = 0;
			sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
			stcb->asoc.asconf_addr_del_pending = NULL;
		}
	}
	if (pending_delete_queued) {
		struct sctp_nets *net;
		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
			stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
			    net);
			net->RTO = 0;
			net->error_count = 0;
		}
		stcb->asoc.overall_error_count = 0;
		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
			    stcb->asoc.overall_error_count,
			    0,
			    SCTP_FROM_SCTP_ASCONF,
			    __LINE__);
		}
		(void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
		status = 1;
	}
	return (status);
}
static int sctp_asconf_queue_add ( struct sctp_tcb * stcb , struct sctp_ifa * ifa , uint16_t type ) { uint32_t status ; int pending_delete_queued = 0 ; int last ; if ( stcb -> asoc . asconf_supported == 0 ) { return ( -1 ) ; } if ( ( type == SCTP_DEL_IP_ADDRESS ) && ! stcb -> asoc . asconf_del_pending ) { if ( stcb -> sctp_ep -> sctp_flags & SCTP_PCB_FLAGS_BOUNDALL ) { last = ( sctp_local_addr_count ( stcb ) == 0 ) ; } else { last = ( sctp_local_addr_count ( stcb ) == 1 ) ; } if ( last ) { stcb -> asoc . asconf_del_pending = 1 ; stcb -> asoc . asconf_addr_del_pending = ifa ; atomic_add_int ( & ifa -> refcount , 1 ) ; SCTPDBG ( SCTP_DEBUG_ASCONF2 , " \n " ) ; return ( -1 ) ; } } status = sctp_asconf_queue_mgmt ( stcb , ifa , type ) ; if ( ( type == SCTP_ADD_IP_ADDRESS ) && stcb -> asoc . asconf_del_pending && ( status == 0 ) ) { if ( sctp_asconf_queue_mgmt ( stcb , stcb -> asoc . asconf_addr_del_pending , SCTP_DEL_IP_ADDRESS ) == 0 ) { SCTPDBG ( SCTP_DEBUG_ASCONF2 , " \n " ) ; pending_delete_queued = 1 ; stcb -> asoc . asconf_del_pending = 0 ; sctp_free_ifa ( stcb -> asoc . asconf_addr_del_pending ) ; stcb -> asoc . asconf_addr_del_pending = NULL ; } } if ( pending_delete_queued ) { struct sctp_nets * net ; TAILQ_FOREACH ( net , & stcb -> asoc . nets , sctp_next ) { stcb -> asoc . cc_functions . sctp_set_initial_cc_param ( stcb , net ) ; net -> RTO = 0 ; net -> error_count = 0 ; } stcb -> asoc . overall_error_count = 0 ; if ( SCTP_BASE_SYSCTL ( sctp_logging_level ) & SCTP_THRESHOLD_LOGGING ) { sctp_misc_ints ( SCTP_THRESHOLD_CLEAR , stcb -> asoc . overall_error_count , 0 , SCTP_FROM_SCTP_ASCONF , __LINE__ ) ; } ( void ) sctp_asconf_queue_mgmt ( stcb , ifa , SCTP_SET_PRIM_ADDR ) ; status = 1 ; } return ( status ) ; }
add an asconf operation for the given ifa and type.
add an asconf operation for the given ifa and type .
/* see if peer supports ASCONF */ /*
	 * if this is deleting the last address from the assoc, mark it as
	 * pending.
	 */ /* set the pending delete info only */ /* queue an asconf parameter */ /*
	 * if this is an add, and there is a delete also pending (i.e. the
	 * last local address is being changed), queue the pending delete
	 * too.
	 */ /* queue in the pending delete */ /* clear out the pending delete info */ /*
		 * since we know that the only/last address is now being
		 * changed in this case, reset the cwnd/rto on all nets to
		 * start as a new address and path.  Also clear the error
		 * counts to give the assoc the best chance to complete the
		 * address change.
		 */ /* queue in an advisory set primary too */ /* let caller know we should send this out immediately */