FreeBSD/sys/netinet/sctp_asconf.c
/*
 * processes the (local) addresses in the INIT-ACK chunk
 */
processes the (local) addresses in the INIT-ACK chunk
processes the ( local ) addresses in the INIT - ACK chunk
static void
sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
    unsigned int offset, unsigned int length)
{
	struct sctp_paramhdr tmp_param, *ph;
	uint16_t plen, ptype;
	struct sctp_ifa *sctp_ifa;
	union sctp_sockstore store;
#ifdef INET6
	struct sctp_ipv6addr_param addr6_store;
#endif
#ifdef INET
	struct sctp_ipv4addr_param addr4_store;
#endif
	SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n");
	if (stcb == NULL)	
		return;
	length += offset;
	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
		return;
	}
	ph = (struct sctp_paramhdr *)
	    sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
	    (uint8_t *) & tmp_param);
	while (ph != NULL) {
		ptype = ntohs(ph->param_type);
		plen = ntohs(ph->param_length);
		switch (ptype) {
#ifdef INET6
		case SCTP_IPV6_ADDRESS:
			{
				struct sctp_ipv6addr_param *a6p;
				a6p = (struct sctp_ipv6addr_param *)
				    sctp_m_getptr(m, offset,
				    sizeof(struct sctp_ipv6addr_param),
				    (uint8_t *) & addr6_store);
				if (plen != sizeof(struct sctp_ipv6addr_param) ||
				    a6p == NULL) {
					return;
				}
				memset(&store, 0, sizeof(union sctp_sockstore));
				store.sin6.sin6_family = AF_INET6;
				store.sin6.sin6_len = sizeof(struct sockaddr_in6);
				store.sin6.sin6_port = stcb->rport;
				memcpy(&store.sin6.sin6_addr, a6p->addr, sizeof(struct in6_addr));
				break;
			}
#endif
#ifdef INET
		case SCTP_IPV4_ADDRESS:
			{
				struct sctp_ipv4addr_param *a4p;
				a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
				    sizeof(struct sctp_ipv4addr_param),
				    (uint8_t *) & addr4_store);
				if (plen != sizeof(struct sctp_ipv4addr_param) ||
				    a4p == NULL) {
					return;
				}
				memset(&store, 0, sizeof(union sctp_sockstore));
				store.sin.sin_family = AF_INET;
				store.sin.sin_len = sizeof(struct sockaddr_in);
				store.sin.sin_port = stcb->rport;
				store.sin.sin_addr.s_addr = a4p->addr;
				break;
			}
#endif
		default:
			goto next_addr;
		}
		sctp_ifa = sctp_find_ifa_by_addr(&store.sa, stcb->asoc.vrf_id,
		    SCTP_ADDR_NOT_LOCKED);
		if (sctp_ifa == NULL) {
			int status;
			if ((sctp_is_feature_on(stcb->sctp_ep,
			    SCTP_PCB_FLAGS_DO_ASCONF)) &&
			    stcb->asoc.asconf_supported) {
				status = sctp_asconf_queue_sa_delete(stcb, &store.sa);
				if (status == 0 &&
				    SCTP_GET_STATE(&stcb->asoc) ==
				    SCTP_STATE_OPEN) {
#ifdef SCTP_TIMER_BASED_ASCONF
					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
					    stcb->sctp_ep, stcb,
					    stcb->asoc.primary_destination);
#else
					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
#endif
				}
			}
		}
next_addr:
		if (SCTP_SIZE32(plen) == 0) {
			SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n",
			    plen, ptype);
			return;
		}
		offset += SCTP_SIZE32(plen);
		if ((offset + sizeof(struct sctp_paramhdr)) > length)
			return;
		ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
		    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
	}			
}
static void sctp_process_initack_addresses ( struct sctp_tcb * stcb , struct mbuf * m , unsigned int offset , unsigned int length ) { struct sctp_paramhdr tmp_param , * ph ; uint16_t plen , ptype ; struct sctp_ifa * sctp_ifa ; union sctp_sockstore store ; #ifdef INET6 struct sctp_ipv6addr_param addr6_store ; #endif #ifdef INET struct sctp_ipv4addr_param addr4_store ; #endif SCTPDBG ( SCTP_DEBUG_ASCONF2 , " \n " ) ; if ( stcb == NULL ) return ; length += offset ; if ( ( offset + sizeof ( struct sctp_paramhdr ) ) > length ) { return ; } ph = ( struct sctp_paramhdr * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_paramhdr ) , ( uint8_t * ) & tmp_param ) ; while ( ph != NULL ) { ptype = ntohs ( ph -> param_type ) ; plen = ntohs ( ph -> param_length ) ; switch ( ptype ) { #ifdef INET6 case SCTP_IPV6_ADDRESS : { struct sctp_ipv6addr_param * a6p ; a6p = ( struct sctp_ipv6addr_param * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_ipv6addr_param ) , ( uint8_t * ) & addr6_store ) ; if ( plen != sizeof ( struct sctp_ipv6addr_param ) || a6p == NULL ) { return ; } memset ( & store , 0 , sizeof ( union sctp_sockstore ) ) ; store . sin6 . sin6_family = AF_INET6 ; store . sin6 . sin6_len = sizeof ( struct sockaddr_in6 ) ; store . sin6 . sin6_port = stcb -> rport ; memcpy ( & store . sin6 . sin6_addr , a6p -> addr , sizeof ( struct in6_addr ) ) ; break ; } #endif #ifdef INET case SCTP_IPV4_ADDRESS : { struct sctp_ipv4addr_param * a4p ; a4p = ( struct sctp_ipv4addr_param * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_ipv4addr_param ) , ( uint8_t * ) & addr4_store ) ; if ( plen != sizeof ( struct sctp_ipv4addr_param ) || a4p == NULL ) { return ; } memset ( & store , 0 , sizeof ( union sctp_sockstore ) ) ; store . sin . sin_family = AF_INET ; store . sin . sin_len = sizeof ( struct sockaddr_in ) ; store . sin . sin_port = stcb -> rport ; store . sin . sin_addr . s_addr = a4p -> addr ; break ; } #endif default : goto next_addr ; } sctp_ifa = sctp_find_ifa_by_addr ( & store . sa , stcb -> asoc . vrf_id , SCTP_ADDR_NOT_LOCKED ) ; if ( sctp_ifa == NULL ) { int status ; if ( ( sctp_is_feature_on ( stcb -> sctp_ep , SCTP_PCB_FLAGS_DO_ASCONF ) ) && stcb -> asoc . asconf_supported ) { status = sctp_asconf_queue_sa_delete ( stcb , & store . sa ) ; if ( status == 0 && SCTP_GET_STATE ( & stcb -> asoc ) == SCTP_STATE_OPEN ) { #ifdef SCTP_TIMER_BASED_ASCONF sctp_timer_start ( SCTP_TIMER_TYPE_ASCONF , stcb -> sctp_ep , stcb , stcb -> asoc . primary_destination ) ; #else sctp_send_asconf ( stcb , NULL , SCTP_ADDR_NOT_LOCKED ) ; #endif } } } next_addr : if ( SCTP_SIZE32 ( plen ) == 0 ) { SCTP_PRINTF ( " \n " , plen , ptype ) ; return ; } offset += SCTP_SIZE32 ( plen ) ; if ( ( offset + sizeof ( struct sctp_paramhdr ) ) > length ) return ; ph = ( struct sctp_paramhdr * ) sctp_m_getptr ( m , offset , sizeof ( struct sctp_paramhdr ) , ( uint8_t * ) & tmp_param ) ; } }
processes the (local) addresses in the INIT-ACK chunk
processes the ( local ) addresses in the INIT - ACK chunk
/* Un-needed check for SA */ /* convert to upper bound */ /* go through the addresses in the init-ack */ /* get the entire IPv6 address param */ /* get the entire IPv4 address param */ /* see if this address really (still) exists */ /* address doesn't exist anymore */ /* are ASCONFs allowed ? */ /* queue an ASCONF DEL_IP_ADDRESS */ /*
				 * if queued ok, and in correct state, send
				 * out the ASCONF.
				 */ /*
		 * Sanity check:  Make sure the length isn't 0, otherwise
		 * we'll be stuck in this loop for a long time...
		 */ /* get next parameter */ /* while */