6_addr));
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
			zero_address = 1;
		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
		break;
#endif
	default:
		m_reply = sctp_asconf_error_response(aph->correlation_id,
		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
		    aparam_length);
		return (m_reply);
	}

	/* if 0.0.0.0/::0, use the source address instead */
	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
		sa = src;
		SCTPDBG(SCTP_DEBUG_ASCONF1,
		    "process_asconf_set_primary: using source addr ");
		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
	}
	/* set the primary address */
	if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
		SCTPDBG(SCTP_DEBUG_ASCONF1,
		    "process_asconf_set_primary: primary address set\n");
		/* notify upper layer */
		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
		if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
		    (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
		    (stcb->asoc.alternate)) {
			sctp_free_remote_addr(stcb->asoc.alternate);
			stcb->asoc.alternate = NULL;
		}
		if (response_required) {
			m_reply = sctp_asconf_success_response(aph->correlation_id);
		}
		/*
		 * Mobility adaptation. Ideally, when the reception of SET
		 * PRIMARY with DELETE IP ADDRESS of the previous primary
		 * destination, unacknowledged DATA are retransmitted
		 * immediately to the new primary destination for seamless
		 * handover. If the destination is UNCONFIRMED and marked to
		 * REQ_PRIM, The retransmission occur when reception of the
		 * HEARTBEAT-ACK.  (See sctp_handle_heartbeat_ack in
		 * sctp_input.c) Also, when change of the primary
		 * destination, it is better that all subsequent new DATA
		 * containing already queued DATA are transmitted to the new
		 * primary destination. (by micchie)
		 */
		if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
		    SCTP_MOBILITY_BASE) ||
		    sctp_is_mobility_feature_on(stcb->sctp_ep,
		    SCTP_MOBILITY_FASTHANDOFF)) &&
		    sctp_is_mobility_feature_on(stcb->sctp_ep,
		    SCTP_MOBILITY_PRIM_DELETED) &&
		    (stcb->asoc.primary_destination->dest_state &
		    SCTP_ADDR_UNCONFIRMED) == 0) {

			sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED,
			    stcb->sctp_ep, stcb, NULL,
			    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
			    SCTP_MOBILITY_FASTHANDOFF)) {
				sctp_assoc_immediate_retrans(stcb,
				    stcb->asoc.primary_destination);
			}
			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
			    SCTP_MOBILITY_BASE)) {
				sctp_move_chunks_from_net(stcb,
				    stcb->asoc.deleted_primary);
			}
			sctp_delete_prim_timer(stcb->sctp_ep, stcb,
			    stcb->asoc.deleted_primary);
		}
	} else {
		/* couldn't set the requested primary address! */
		SCTPDBG(SCTP_DEBUG_ASCONF1,
		    "process_asconf_set_primary: set primary failed!\n");
		/* must have been an invalid address, so report */
		m_reply = sctp_asconf_error_response(aph->correlation_id,
		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
		    aparam_length);
	}

	return (m_reply);
}

/*
 * handles an ASCONF chunk.
 * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
 */
void
sctp_handle_asconf(struct mbuf *m, unsigned int offset,
    struct sockaddr *src,
    struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb,
    int first)
{
	struct sctp_association *asoc;
	uint32_t serial_num;
	struct mbuf *n, *m_ack, *m_result, *m_tail;
	struct sctp_asconf_ack_chunk *ack_cp;
	struct sctp_asconf_paramhdr *aph;
	struct sctp_ipv6addr_param *p_addr;
	unsigned int asconf_limit, cnt;
	int error = 0;		/* did an error occur? */

	/* asconf param buffer */
	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
	struct sctp_asconf_ack *ack, *ack_next;

	/* verify minimum length */
	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
		SCTPDBG(SCTP_DEBUG_ASCONF1,
		    "handle_asconf: chunk too small = %xh\n",
		    ntohs(cp->ch.chunk_length));
		return;
	}
	asoc = &stcb->asoc;
	serial_num = ntohl(cp->serial_number);

	if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) {
		/* got a duplicate ASCONF */
		SCTPDBG(SCTP_DEBUG_ASCONF1,
		    "handle_asconf: got duplicate serial number = %xh\n",
		    serial_num);
		return;
	} else if (serial_num!= (asoc->asconf_seq_in + 1)) {
		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
		    serial_num, asoc->asconf_seq_in + 1);
		return;
	}
	/* it's the expected "next" sequence number, so process it */
	asoc->asconf_seq_in = serial_num;	/* update sequence */
	/* get length of all the param's in the ASCONF */
	asconf_limit = offset + ntohs(cp->ch.chunk_length);
	SCTPDBG(SCTP_DEBUG_ASCONF1,
	    "handle_asconf: asconf_limit=%u, sequence=%xh\n",
	    asconf_limit, serial_num);

	if (first) {
		/* delete old cache */
		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: Now processing first ASCONF. Try to delete old cache\n");

		TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) {
			if (ack->serial_number == serial_num)
				break;
			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: delete