diff options
Diffstat (limited to 'freebsd/sys/netinet/sctp_asconf.c')
-rw-r--r-- | freebsd/sys/netinet/sctp_asconf.c | 1198 |
1 files changed, 637 insertions, 561 deletions
diff --git a/freebsd/sys/netinet/sctp_asconf.c b/freebsd/sys/netinet/sctp_asconf.c index 3c24b75d..3e51ed72 100644 --- a/freebsd/sys/netinet/sctp_asconf.c +++ b/freebsd/sys/netinet/sctp_asconf.c @@ -2,16 +2,18 @@ /*- * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. + * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the distribution. + * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived @@ -30,10 +32,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -/* $KAME: sctp_asconf.c,v 1.24 2005/03/06 16:04:16 itojun Exp $ */ - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); + #include <netinet/sctp_os.h> #include <netinet/sctp_var.h> #include <netinet/sctp_sysctl.h> @@ -49,53 +50,10 @@ __FBSDID("$FreeBSD$"); * SCTP_DEBUG_ASCONF1: protocol info, general info and errors * SCTP_DEBUG_ASCONF2: detailed info */ -#ifdef SCTP_DEBUG -#endif /* SCTP_DEBUG */ - - -static void -sctp_asconf_get_source_ip(struct mbuf *m, struct sockaddr *sa) -{ - struct ip *iph; - struct sockaddr_in *sin; - -#ifdef INET6 - struct sockaddr_in6 *sin6; - -#endif - - iph = mtod(m, struct ip *); - if (iph->ip_v == IPVERSION) { - /* IPv4 source */ - sin = (struct sockaddr_in *)sa; - bzero(sin, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - sin->sin_port = 0; - sin->sin_addr.s_addr = iph->ip_src.s_addr; - return; - } -#ifdef INET6 - else if (iph->ip_v == (IPV6_VERSION >> 4)) { - /* IPv6 source */ - struct ip6_hdr *ip6; - sin6 = (struct sockaddr_in6 *)sa; - bzero(sin6, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_port = 0; - ip6 = mtod(m, struct ip6_hdr *); - sin6->sin6_addr = ip6->ip6_src; - return; - } -#endif /* INET6 */ - else - return; -} /* - * draft-ietf-tsvwg-addip-sctp + * RFC 5061 * * An ASCONF parameter queue exists per asoc which holds the pending address * operations. Lists are updated upon receipt of ASCONF-ACK. @@ -128,7 +86,7 @@ sctp_asconf_success_response(uint32_t id) if (m_reply == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_success_response: couldn't get mbuf!\n"); - return NULL; + return (NULL); } aph = mtod(m_reply, struct sctp_asconf_paramhdr *); aph->correlation_id = id; @@ -137,7 +95,7 @@ sctp_asconf_success_response(uint32_t id) SCTP_BUF_LEN(m_reply) = aph->ph.param_length; aph->ph.param_length = htons(aph->ph.param_length); - return m_reply; + return (m_reply); } static struct mbuf * @@ -156,7 +114,7 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv, if (m_reply == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_error_response: couldn't get mbuf!\n"); - return NULL; + return (NULL); } aph = mtod(m_reply, struct sctp_asconf_paramhdr *); error = (struct sctp_error_cause *)(aph + 1); @@ -173,7 +131,7 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv, "asconf_error_response: tlv_length (%xh) too big\n", tlv_length); sctp_m_freem(m_reply); /* discard */ - return NULL; + return (NULL); } if (error_tlv != NULL) { tlv = (uint8_t *) (error + 1); @@ -183,59 +141,70 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv, error->length = htons(error->length); aph->ph.param_length = htons(aph->ph.param_length); - return m_reply; + return (m_reply); } static struct mbuf * -sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, - struct sctp_tcb *stcb, int response_required) +sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph, + struct sctp_tcb *stcb, int send_hb, int response_required) { + struct sctp_nets *net; struct mbuf *m_reply = NULL; - struct sockaddr_storage sa_source, sa_store; - struct sctp_ipv4addr_param *v4addr; + struct sockaddr_storage sa_store; + struct sctp_paramhdr *ph; uint16_t param_type, param_length, aparam_length; struct sockaddr *sa; - struct sockaddr_in *sin; int zero_address = 0; + int bad_address = 0; + +#ifdef INET + struct sockaddr_in *sin; + struct sctp_ipv4addr_param *v4addr; +#endif #ifdef INET6 struct sockaddr_in6 *sin6; struct sctp_ipv6addr_param *v6addr; -#endif /* INET6 */ +#endif aparam_length = ntohs(aph->ph.param_length); - v4addr = (struct sctp_ipv4addr_param *)(aph + 1); -#ifdef INET6 - v6addr = (struct sctp_ipv6addr_param *)(aph + 1); -#endif /* INET6 */ - param_type = ntohs(v4addr->ph.param_type); - param_length = ntohs(v4addr->ph.param_length); + ph = (struct sctp_paramhdr *)(aph + 1); + param_type = ntohs(ph->param_type); + param_length = ntohs(ph->param_length); sa = (struct sockaddr *)&sa_store; switch (param_type) { +#ifdef INET case SCTP_IPV4_ADDRESS: if (param_length != sizeof(struct sctp_ipv4addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } + v4addr = (struct sctp_ipv4addr_param *)ph; sin = (struct sockaddr_in *)&sa_store; bzero(sin, sizeof(*sin)); sin->sin_family = AF_INET; sin->sin_len = sizeof(struct sockaddr_in); sin->sin_port = stcb->rport; sin->sin_addr.s_addr = v4addr->addr; + if ((sin->sin_addr.s_addr == INADDR_BROADCAST) || + IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { + bad_address = 1; + } if (sin->sin_addr.s_addr == INADDR_ANY) zero_address = 1; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); break; - case SCTP_IPV6_ADDRESS: +#endif #ifdef INET6 + case SCTP_IPV6_ADDRESS: if (param_length != sizeof(struct sctp_ipv6addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } + v6addr = (struct sctp_ipv6addr_param *)ph; sin6 = (struct sockaddr_in6 *)&sa_store; bzero(sin6, sizeof(*sin6)); sin6->sin6_family = AF_INET6; @@ -243,38 +212,35 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, sin6->sin6_port = stcb->rport; memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr, sizeof(struct in6_addr)); + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + bad_address = 1; + } if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) zero_address = 1; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); -#else - /* IPv6 not enabled! */ - /* FIX ME: currently sends back an invalid param error */ - m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, aparam_length); - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_add_ip: v6 disabled- skipping "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - return m_reply; -#endif break; +#endif default: m_reply = sctp_asconf_error_response(aph->correlation_id, - SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, + SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, aparam_length); - return m_reply; + return (m_reply); } /* end switch */ /* if 0.0.0.0/::0, add the source address instead */ if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - sa = (struct sockaddr *)&sa_source; - sctp_asconf_get_source_ip(m, sa); + sa = src; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: using source addr "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); } /* add the address */ - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, + if (bad_address) { + m_reply = sctp_asconf_error_response(aph->correlation_id, + SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, + aparam_length); + } else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE, SCTP_ADDR_DYNAMIC_ADDED) != 0) { SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: error adding address\n"); @@ -288,13 +254,14 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, m_reply = sctp_asconf_success_response(aph->correlation_id); } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, - NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, - stcb, NULL); + stcb, net); + if (send_hb) { + sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); + } } - - return m_reply; + return (m_reply); } static int @@ -306,7 +273,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src) src_net = sctp_findnet(stcb, src); if (src_net == NULL) { /* not found */ - return -1; + return (-1); } /* delete all destination addresses except the source */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { @@ -322,46 +289,47 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src) (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED); } } - return 0; + return (0); } static struct mbuf * -sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, +sctp_process_asconf_delete_ip(struct sockaddr *src, + struct sctp_asconf_paramhdr *aph, struct sctp_tcb *stcb, int response_required) { struct mbuf *m_reply = NULL; - struct sockaddr_storage sa_source, sa_store; - struct sctp_ipv4addr_param *v4addr; + struct sockaddr_storage sa_store; + struct sctp_paramhdr *ph; uint16_t param_type, param_length, aparam_length; struct sockaddr *sa; - struct sockaddr_in *sin; int zero_address = 0; int result; +#ifdef INET + struct sockaddr_in *sin; + struct sctp_ipv4addr_param *v4addr; + +#endif #ifdef INET6 struct sockaddr_in6 *sin6; struct sctp_ipv6addr_param *v6addr; -#endif /* INET6 */ - - /* get the source IP address for src and 0.0.0.0/::0 delete checks */ - sctp_asconf_get_source_ip(m, (struct sockaddr *)&sa_source); +#endif aparam_length = ntohs(aph->ph.param_length); - v4addr = (struct sctp_ipv4addr_param *)(aph + 1); -#ifdef INET6 - v6addr = (struct sctp_ipv6addr_param *)(aph + 1); -#endif /* INET6 */ - param_type = ntohs(v4addr->ph.param_type); - param_length = ntohs(v4addr->ph.param_length); + ph = (struct sctp_paramhdr *)(aph + 1); + param_type = ntohs(ph->param_type); + param_length = ntohs(ph->param_length); sa = (struct sockaddr *)&sa_store; switch (param_type) { +#ifdef INET case SCTP_IPV4_ADDRESS: if (param_length != sizeof(struct sctp_ipv4addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } + v4addr = (struct sctp_ipv4addr_param *)ph; sin = (struct sockaddr_in *)&sa_store; bzero(sin, sizeof(*sin)); sin->sin_family = AF_INET; @@ -374,12 +342,14 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, "process_asconf_delete_ip: deleting "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); break; +#endif +#ifdef INET6 case SCTP_IPV6_ADDRESS: if (param_length != sizeof(struct sctp_ipv6addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } -#ifdef INET6 + v6addr = (struct sctp_ipv6addr_param *)ph; sin6 = (struct sockaddr_in6 *)&sa_store; bzero(sin6, sizeof(*sin6)); sin6->sin6_family = AF_INET6; @@ -392,35 +362,27 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: deleting "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); -#else - /* IPv6 not enabled! No "action" needed; just ack it */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_delete_ip: v6 disabled- ignoring: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - /* just respond with a "success" ASCONF-ACK */ - return NULL; -#endif break; +#endif default: m_reply = sctp_asconf_error_response(aph->correlation_id, SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, aparam_length); - return m_reply; + return (m_reply); } /* make sure the source address is not being deleted */ - if (sctp_cmpaddr(sa, (struct sockaddr *)&sa_source)) { + if (sctp_cmpaddr(sa, src)) { /* trying to delete the source address! */ SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n"); m_reply = sctp_asconf_error_response(aph->correlation_id, SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph, aparam_length); - return m_reply; + return (m_reply); } /* if deleting 0.0.0.0/::0, delete all addresses except src addr */ if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - result = sctp_asconf_del_remote_addrs_except(stcb, - (struct sockaddr *)&sa_source); + result = sctp_asconf_del_remote_addrs_except(stcb, src); if (result) { /* src address did not exist? */ @@ -434,7 +396,7 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, m_reply = sctp_asconf_success_response(aph->correlation_id); } - return m_reply; + return (m_reply); } /* delete the address */ result = sctp_del_remote_addr(stcb, sa); @@ -456,43 +418,46 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, /* notify upper layer */ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED); } - return m_reply; + return (m_reply); } static struct mbuf * -sctp_process_asconf_set_primary(struct mbuf *m, +sctp_process_asconf_set_primary(struct sockaddr *src, struct sctp_asconf_paramhdr *aph, struct sctp_tcb *stcb, int response_required) { struct mbuf *m_reply = NULL; - struct sockaddr_storage sa_source, sa_store; - struct sctp_ipv4addr_param *v4addr; + struct sockaddr_storage sa_store; + struct sctp_paramhdr *ph; uint16_t param_type, param_length, aparam_length; struct sockaddr *sa; - struct sockaddr_in *sin; int zero_address = 0; +#ifdef INET + struct sockaddr_in *sin; + struct sctp_ipv4addr_param *v4addr; + +#endif #ifdef INET6 struct sockaddr_in6 *sin6; struct sctp_ipv6addr_param *v6addr; -#endif /* INET6 */ +#endif aparam_length = ntohs(aph->ph.param_length); - v4addr = (struct sctp_ipv4addr_param *)(aph + 1); -#ifdef INET6 - v6addr = (struct sctp_ipv6addr_param *)(aph + 1); -#endif /* INET6 */ - param_type = ntohs(v4addr->ph.param_type); - param_length = ntohs(v4addr->ph.param_length); + ph = (struct sctp_paramhdr *)(aph + 1); + param_type = ntohs(ph->param_type); + param_length = ntohs(ph->param_length); sa = (struct sockaddr *)&sa_store; switch (param_type) { +#ifdef INET case SCTP_IPV4_ADDRESS: if (param_length != sizeof(struct sctp_ipv4addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } + v4addr = (struct sctp_ipv4addr_param *)ph; sin = (struct sockaddr_in *)&sa_store; bzero(sin, sizeof(*sin)); sin->sin_family = AF_INET; @@ -503,12 +468,14 @@ sctp_process_asconf_set_primary(struct mbuf *m, SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); break; +#endif +#ifdef INET6 case SCTP_IPV6_ADDRESS: if (param_length != sizeof(struct sctp_ipv6addr_param)) { /* invalid param size */ - return NULL; + return (NULL); } -#ifdef INET6 + v6addr = (struct sctp_ipv6addr_param *)ph; sin6 = (struct sockaddr_in6 *)&sa_store; bzero(sin6, sizeof(*sin6)); sin6->sin6_family = AF_INET6; @@ -519,29 +486,21 @@ sctp_process_asconf_set_primary(struct mbuf *m, zero_address = 1; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); -#else - /* IPv6 not enabled! No "action" needed; just ack it */ - SCTPDBG(SCTP_DEBUG_ASCONF1, - "process_asconf_set_primary: v6 disabled- ignoring: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - /* just respond with a "success" ASCONF-ACK */ - return NULL; -#endif break; +#endif default: m_reply = sctp_asconf_error_response(aph->correlation_id, SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph, aparam_length); - return m_reply; + return (m_reply); } /* if 0.0.0.0/::0, use the source address instead */ if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) { - sa = (struct sockaddr *)&sa_source; - sctp_asconf_get_source_ip(m, sa); + sa = src; SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: using source addr "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); } /* set the primary address */ if (sctp_set_primary_addr(stcb, sa, NULL) == 0) { @@ -549,7 +508,12 @@ sctp_process_asconf_set_primary(struct mbuf *m, "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); } @@ -599,7 +563,7 @@ sctp_process_asconf_set_primary(struct mbuf *m, aparam_length); } - return m_reply; + return (m_reply); } /* @@ -608,6 +572,7 @@ sctp_process_asconf_set_primary(struct mbuf *m, */ void sctp_handle_asconf(struct mbuf *m, unsigned int offset, + struct sockaddr *src, struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb, int first) { @@ -617,7 +582,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, struct sctp_asconf_ack_chunk *ack_cp; struct sctp_asconf_paramhdr *aph, *ack_aph; struct sctp_ipv6addr_param *p_addr; - unsigned int asconf_limit; + unsigned int asconf_limit, cnt; int error = 0; /* did an error occur? */ /* asconf param buffer */ @@ -634,8 +599,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, asoc = &stcb->asoc; serial_num = ntohl(cp->serial_number); - if (compare_with_wrap(asoc->asconf_seq_in, serial_num, MAX_SEQ) || - serial_num == asoc->asconf_seq_in) { + 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", @@ -656,21 +620,18 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, if (first) { /* delete old cache */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: Now processing firstASCONF. Try to delte old cache\n"); + SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: Now processing first ASCONF. Try to delete old cache\n"); - ack = TAILQ_FIRST(&stcb->asoc.asconf_ack_sent); - while (ack != NULL) { - ack_next = TAILQ_NEXT(ack, next); + 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 old(%u) < first(%u)\n", ack->serial_number, serial_num); - TAILQ_REMOVE(&stcb->asoc.asconf_ack_sent, ack, next); + TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next); if (ack->data != NULL) { sctp_m_freem(ack->data); } SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack); - ack = ack_next; } } m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0, @@ -716,6 +677,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, goto send_reply; } /* process through all parameters */ + cnt = 0; while (aph != NULL) { unsigned int param_length, param_type; @@ -747,12 +709,13 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, switch (param_type) { case SCTP_ADD_IP_ADDRESS: asoc->peer_supports_asconf = 1; - m_result = sctp_process_asconf_add_ip(m, aph, stcb, - error); + m_result = sctp_process_asconf_add_ip(src, aph, stcb, + (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error); + cnt++; break; case SCTP_DEL_IP_ADDRESS: asoc->peer_supports_asconf = 1; - m_result = sctp_process_asconf_delete_ip(m, aph, stcb, + m_result = sctp_process_asconf_delete_ip(src, aph, stcb, error); break; case SCTP_ERROR_CAUSE_IND: @@ -760,7 +723,7 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, break; case SCTP_SET_PRIM_ADDR: asoc->peer_supports_asconf = 1; - m_result = sctp_process_asconf_set_primary(m, aph, + m_result = sctp_process_asconf_set_primary(src, aph, stcb, error); break; case SCTP_NAT_VTAGS: @@ -829,10 +792,8 @@ send_reply: ack->last_sent_to = NULL; ack->data = m_ack; ack->len = 0; - n = m_ack; - while (n) { + for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) { ack->len += SCTP_BUF_LEN(n); - n = SCTP_BUF_NEXT(n); } TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next); @@ -842,67 +803,16 @@ send_reply: * this could happen if the source address was just newly * added */ - struct ip *iph; - struct sctphdr *sh; - struct sockaddr_storage from_store; - struct sockaddr *from = (struct sockaddr *)&from_store; - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n"); - /* pullup already done, IP options already stripped */ - iph = mtod(m, struct ip *); - sh = (struct sctphdr *)((caddr_t)iph + sizeof(*iph)); - switch (iph->ip_v) { - case IPVERSION: - { - struct sockaddr_in *from4; - - from4 = (struct sockaddr_in *)&from_store; - bzero(from4, sizeof(*from4)); - from4->sin_family = AF_INET; - from4->sin_len = sizeof(struct sockaddr_in); - from4->sin_addr.s_addr = iph->ip_src.s_addr; - from4->sin_port = sh->src_port; - break; - } -#ifdef INET6 - case IPV6_VERSION >> 4: - { - struct ip6_hdr *ip6; - struct sockaddr_in6 *from6; - - ip6 = mtod(m, struct ip6_hdr *); - from6 = (struct sockaddr_in6 *)&from_store; - bzero(from6, sizeof(*from6)); - from6->sin6_family = AF_INET6; - from6->sin6_len = sizeof(struct sockaddr_in6); - from6->sin6_addr = ip6->ip6_src; - from6->sin6_port = sh->src_port; - /* - * Get the scopes in properly to the sin6 - * addr's - */ - /* we probably don't need these operations */ - (void)sa6_recoverscope(from6); - sa6_embedscope(from6, - MODULE_GLOBAL(ip6_use_defzone)); - - break; - } -#endif - default: - /* unknown address type */ - from = NULL; - } - if (from != NULL) { - SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: "); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, from); - /* look up the from address */ - stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, from); + SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: "); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src); + /* look up the from address */ + stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src); #ifdef SCTP_DEBUG - if (stcb->asoc.last_control_chunk_from == NULL) - SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n"); -#endif + if (stcb->asoc.last_control_chunk_from == NULL) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n"); } +#endif } } @@ -912,28 +822,36 @@ send_reply: static uint32_t sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa) { + switch (sa->sa_family) { #ifdef INET6 - if (sa->sa_family == AF_INET6) { - /* IPv6 sa address */ - /* XXX scopeid */ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) && - (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)) == 0)) { - return (1); + case AF_INET6: + { + /* XXX scopeid */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) && + (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr, + sizeof(struct in6_addr)) == 0)) { + return (1); + } + break; } - } else -#endif /* INET6 */ - if (sa->sa_family == AF_INET) { - /* IPv4 sa address */ - struct sockaddr_in *sin = (struct sockaddr_in *)sa; +#endif +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; - if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) && - (memcmp(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)) == 0)) { - return (1); + if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) && + (memcmp(&aa->ap.addrp.addr, &sin->sin_addr, + sizeof(struct in_addr)) == 0)) { + return (1); + } + break; } +#endif + default: + break; } return (0); } @@ -942,43 +860,48 @@ sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa) * does the address match? returns 0 if not, 1 if so */ static uint32_t -sctp_addr_match( - struct sctp_ipv6addr_param *v6addr, - struct sockaddr *sa) +sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa) { uint16_t param_type, param_length; - struct sctp_ipv4addr_param *v4addr = (struct sctp_ipv4addr_param *)v6addr; + param_type = ntohs(ph->param_type); + param_length = ntohs(ph->param_length); + switch (sa->sa_family) { #ifdef INET6 - if (sa->sa_family == AF_INET6) { - /* IPv6 sa address */ - /* XXX scopeid */ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - param_type = ntohs(v6addr->ph.param_type); - param_length = ntohs(v6addr->ph.param_length); - - if ((param_type == SCTP_IPV6_ADDRESS) && - param_length == sizeof(struct sctp_ipv6addr_param) && - (memcmp(&v6addr->addr, &sin6->sin6_addr, - sizeof(struct in6_addr)) == 0)) { - return (1); + case AF_INET6: + { + /* XXX scopeid */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + struct sctp_ipv6addr_param *v6addr; + + v6addr = (struct sctp_ipv6addr_param *)ph; + if ((param_type == SCTP_IPV6_ADDRESS) && + param_length == sizeof(struct sctp_ipv6addr_param) && + (memcmp(&v6addr->addr, &sin6->sin6_addr, + sizeof(struct in6_addr)) == 0)) { + return (1); + } + break; } - } #endif - if (sa->sa_family == AF_INET) { - /* IPv4 sa address */ - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - param_type = ntohs(v4addr->ph.param_type); - param_length = ntohs(v4addr->ph.param_length); - - if ((param_type == SCTP_IPV4_ADDRESS) && - param_length == sizeof(struct sctp_ipv4addr_param) && - (memcmp(&v4addr->addr, &sin->sin_addr, - sizeof(struct in_addr)) == 0)) { - return (1); +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + struct sctp_ipv4addr_param *v4addr; + + v4addr = (struct sctp_ipv4addr_param *)ph; + if ((param_type == SCTP_IPV4_ADDRESS) && + param_length == sizeof(struct sctp_ipv4addr_param) && + (memcmp(&v4addr->addr, &sin->sin_addr, + sizeof(struct in_addr)) == 0)) { + return (1); + } + break; } +#endif + default: + break; } return (0); } @@ -1183,17 +1106,25 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa) continue; changed = 0; - if (net->ro._l_addr.sa.sa_family == AF_INET) { - if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *) & net->ro)) + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: + if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *) & net->ro)) { changed = 1; - } + } + break; +#endif #ifdef INET6 - if (net->ro._l_addr.sa.sa_family == AF_INET6) { + case AF_INET6: if (sctp_v6src_match_nexthop( - &newifa->address.sin6, (sctp_route_t *) & net->ro)) + &newifa->address.sin6, (sctp_route_t *) & net->ro)) { changed = 1; - } + } + break; #endif + default: + break; + } /* * if the newly added address does not relate routing * information, we skip. @@ -1220,8 +1151,7 @@ sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa) * flag: 1=success, 0=failure. */ static void -sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, - uint16_t type, uint32_t flag) +sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag) { /* * do the necessary asoc list work- if we get a failure indication, @@ -1266,9 +1196,7 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, struct sockaddr *sa; /* make sure the request isn't already in the queue */ - for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL; - aa = aa_next) { - aa_next = TAILQ_NEXT(aa, next); + TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { /* address match? */ if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0) continue; @@ -1322,31 +1250,40 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, aa->ifa = ifa; atomic_add_int(&ifa->refcount, 1); /* correlation_id filled in during send routine later... */ - if (ifa->address.sa.sa_family == AF_INET6) { - /* IPv6 address */ - struct sockaddr_in6 *sin6; + switch (ifa->address.sa.sa_family) { +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)&ifa->address.sa; - sa = (struct sockaddr *)sin6; - aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + - sizeof(struct sctp_ipv6addr_param); - memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - } else if (ifa->address.sa.sa_family == AF_INET) { - /* IPv4 address */ - struct sockaddr_in *sin; + sin6 = (struct sockaddr_in6 *)&ifa->address.sa; + sa = (struct sockaddr *)sin6; + aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; + aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); + aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + + sizeof(struct sctp_ipv6addr_param); + memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, + sizeof(struct in6_addr)); + break; + } +#endif +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin; - sin = (struct sockaddr_in *)&ifa->address.sa; - sa = (struct sockaddr *)sin; - aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + - sizeof(struct sctp_ipv4addr_param); - memcpy(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)); - } else { + sin = (struct sockaddr_in *)&ifa->address.sa; + sa = (struct sockaddr *)sin; + aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; + aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); + aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + + sizeof(struct sctp_ipv4addr_param); + memcpy(&aa->ap.addrp.addr, &sin->sin_addr, + sizeof(struct in_addr)); + break; + } +#endif + default: /* invalid family! */ SCTP_FREE(aa, SCTP_M_ASC_ADDR); sctp_free_ifa(ifa); @@ -1356,7 +1293,7 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa, TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); #ifdef SCTP_DEBUG - if (SCTP_BASE_SYSCTL(sctp_debug_on) && SCTP_DEBUG_ASCONF2) { + if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) { if (type == SCTP_ADD_IP_ADDRESS) { SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa); @@ -1482,9 +1419,7 @@ sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa) return (-1); } /* make sure the request isn't already in the queue */ - for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL; - aa = aa_next) { - aa_next = TAILQ_NEXT(aa, next); + TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { /* address match? */ if (sctp_asconf_addr_match(aa, sa) == 0) continue; @@ -1530,26 +1465,37 @@ sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa) if (ifa) atomic_add_int(&ifa->refcount, 1); /* correlation_id filled in during send routine later... */ - if (sa->sa_family == AF_INET6) { - /* IPv6 address */ - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)sa; - aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param); - memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - } else if (sa->sa_family == AF_INET) { - /* IPv4 address */ - struct sockaddr_in *sin = (struct sockaddr_in *)sa; + switch (sa->sa_family) { +#ifdef INET6 + case AF_INET6: + { + /* IPv6 address */ + struct sockaddr_in6 *sin6; - aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; - aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); - aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param); - memcpy(&aa->ap.addrp.addr, &sin->sin_addr, - sizeof(struct in_addr)); - } else { + sin6 = (struct sockaddr_in6 *)sa; + aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; + aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param)); + aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param); + memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr, + sizeof(struct in6_addr)); + break; + } +#endif +#ifdef INET + case AF_INET: + { + /* IPv4 address */ + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; + aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param)); + aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param); + memcpy(&aa->ap.addrp.addr, &sin->sin_addr, + sizeof(struct in_addr)); + break; + } +#endif + default: /* invalid family! */ SCTP_FREE(aa, SCTP_M_ASC_ADDR); if (ifa) @@ -1655,7 +1601,7 @@ sctp_asconf_process_param_ack(struct sctp_tcb *stcb, case SCTP_ADD_IP_ADDRESS: SCTPDBG(SCTP_DEBUG_ASCONF1, "process_param_ack: added IP address\n"); - sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, param_type, flag); + sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag); break; case SCTP_DEL_IP_ADDRESS: SCTPDBG(SCTP_DEBUG_ASCONF1, @@ -1733,8 +1679,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, */ if (serial_num == (asoc->asconf_seq_out + 1)) { SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n"); - sctp_abort_an_association(stcb->sctp_ep, stcb, - SCTP_CAUSE_ILLEGAL_ASCONF_ACK, NULL, SCTP_SO_NOT_LOCKED); + sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, SCTP_SO_NOT_LOCKED); *abort_no_unlock = 1; return; } @@ -1838,9 +1783,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, */ if (last_error_id == 0) last_error_id--;/* set to "max" value */ - for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL; - aa = aa_next) { - aa_next = TAILQ_NEXT(aa, next); + TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) { if (aa->sent == 1) { /* * implicitly successful or failed if correlation_id @@ -1921,8 +1864,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, { int status; - - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 && + if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 || sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) { /* subset bound, no ASCONF allowed case, so ignore */ return; @@ -1933,10 +1875,19 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, */ /* first, make sure it's a good address family */ - if (ifa->address.sa.sa_family != AF_INET6 && - ifa->address.sa.sa_family != AF_INET) { + switch (ifa->address.sa.sa_family) { +#ifdef INET6 + case AF_INET6: + break; +#endif +#ifdef INET + case AF_INET: + break; +#endif + default: return; } +#ifdef INET6 /* make sure we're "allowed" to add this type of addr */ if (ifa->address.sa.sa_family == AF_INET6) { /* invalid if we're not a v6 endpoint */ @@ -1947,6 +1898,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } } +#endif /* put this address on the "pending/do not use yet" list */ sctp_add_local_addr_restricted(stcb, ifa); /* @@ -1966,7 +1918,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (stcb->asoc.local_scope == 0) { + if (stcb->asoc.scope.local_scope == 0) { return; } /* is it the right link local scope? */ @@ -1974,13 +1926,14 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return; } } - if (stcb->asoc.site_scope == 0 && + if (stcb->asoc.scope.site_scope == 0 && IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { return; } break; } #endif +#ifdef INET case AF_INET: { struct sockaddr_in *sin; @@ -1997,12 +1950,13 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* we skip unspecifed addresses */ return; } - if (stcb->asoc.ipv4_local_scope == 0 && + if (stcb->asoc.scope.ipv4_local_scope == 0 && IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { return; } break; } +#endif default: /* else, not AF_INET or AF_INET6, so skip */ return; @@ -2026,8 +1980,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - addr_locked); + sctp_send_asconf(stcb, NULL, addr_locked); #endif } } @@ -2036,7 +1989,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int -sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val) +sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) { struct sctp_asconf_iterator *asc; struct sctp_ifa *ifa; @@ -2046,42 +1999,45 @@ sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val) asc = (struct sctp_asconf_iterator *)ptr; LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { ifa = l->ifa; - if (ifa->address.sa.sa_family == AF_INET6) { + switch (ifa->address.sa.sa_family) { +#ifdef INET6 + case AF_INET6: /* invalid if we're not a v6 endpoint */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { cnt_invalid++; if (asc->cnt == cnt_invalid) return (1); - else - continue; } - } else if (ifa->address.sa.sa_family == AF_INET) { - /* invalid if we are a v6 only endpoint */ - struct in6pcb *inp6; + break; +#endif +#ifdef INET + case AF_INET: + { + /* invalid if we are a v6 only endpoint */ + struct in6pcb *inp6; - inp6 = (struct in6pcb *)&inp->ip_inp.inp; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && - SCTP_IPV6_V6ONLY(inp6)) { - cnt_invalid++; - if (asc->cnt == cnt_invalid) - return (1); - else - continue; + inp6 = (struct in6pcb *)&inp->ip_inp.inp; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && + SCTP_IPV6_V6ONLY(inp6)) { + cnt_invalid++; + if (asc->cnt == cnt_invalid) + return (1); + } + break; } - } else { +#endif + default: /* invalid address family */ cnt_invalid++; if (asc->cnt == cnt_invalid) return (1); - else - continue; } } return (0); } static int -sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val) +sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED) { struct sctp_ifa *ifa; struct sctp_asconf_iterator *asc; @@ -2100,14 +2056,11 @@ sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val) } } } else if (l->action == SCTP_DEL_IP_ADDRESS) { - laddr = LIST_FIRST(&inp->sctp_addr_list); - while (laddr) { - nladdr = LIST_NEXT(laddr, sctp_nxt_addr); + LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { /* remove only after all guys are done */ if (laddr->ifa == ifa) { sctp_del_local_addr_ep(inp, ifa); } - laddr = nladdr; } } } @@ -2116,7 +2069,7 @@ sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val) void sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - void *ptr, uint32_t val) + void *ptr, uint32_t val SCTP_UNUSED) { struct sctp_asconf_iterator *asc; struct sctp_ifa *ifa; @@ -2155,7 +2108,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, continue; } if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (stcb->asoc.local_scope == 0) { + if (stcb->asoc.scope.local_scope == 0) { continue; } /* is it the right link local scope? */ @@ -2166,6 +2119,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; } #endif +#ifdef INET case AF_INET: { /* invalid if we are a v6 only endpoint */ @@ -2183,7 +2137,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* we skip unspecifed addresses */ continue; } - if (stcb->asoc.ipv4_local_scope == 0 && + if (stcb->asoc.scope.ipv4_local_scope == 0 && IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { continue; } @@ -2197,6 +2151,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } break; } +#endif default: /* invalid address family */ cnt_invalid++; @@ -2245,13 +2200,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } } else { /* Need to check scopes for this guy */ - if (sctp_is_address_in_scope(ifa, - stcb->asoc.ipv4_addr_legal, - stcb->asoc.ipv6_addr_legal, - stcb->asoc.loopback_scope, - stcb->asoc.ipv4_local_scope, - stcb->asoc.local_scope, - stcb->asoc.site_scope, 0) == 0) { + if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { continue; } } @@ -2277,22 +2226,19 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * If we have queued params in the open state, send out an ASCONF. */ if (num_queued > 0) { - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); } } void -sctp_asconf_iterator_end(void *ptr, uint32_t val) +sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED) { struct sctp_asconf_iterator *asc; struct sctp_ifa *ifa; - struct sctp_laddr *l, *l_next; + struct sctp_laddr *l, *nl; asc = (struct sctp_asconf_iterator *)ptr; - l = LIST_FIRST(&asc->list_of_work); - while (l != NULL) { - l_next = LIST_NEXT(l, sctp_nxt_addr); + LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) { ifa = l->ifa; if (l->action == SCTP_ADD_IP_ADDRESS) { /* Clear the defer use flag */ @@ -2301,7 +2247,6 @@ sctp_asconf_iterator_end(void *ptr, uint32_t val) sctp_free_ifa(ifa); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l); SCTP_DECR_LADDR_COUNT(); - l = l_next; } SCTP_FREE(asc, SCTP_M_ASC_IT); } @@ -2328,7 +2273,7 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) /* set primary queuing succeeded */ SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: queued on tcb=%p, ", - stcb); + (void *)stcb); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { #ifdef SCTP_TIMER_BASED_ASCONF @@ -2336,13 +2281,12 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } else { SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ", - stcb); + (void *)stcb); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); return (-1); } @@ -2365,7 +2309,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa) SCTP_SET_PRIM_ADDR)) { /* set primary queuing succeeded */ SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ", - stcb); + (void *)stcb); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa); if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { #ifdef SCTP_TIMER_BASED_ASCONF @@ -2373,8 +2317,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa) stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } @@ -2390,17 +2333,13 @@ sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) struct sctp_asconf_chunk *acp; struct sctp_asconf_paramhdr *aph; uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_ipv6addr_param *p_addr; + struct sctp_paramhdr *ph; int add_cnt, del_cnt; uint16_t last_param_type; add_cnt = del_cnt = 0; last_param_type = 0; - for (chk = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); chk != NULL; - chk = nchk) { - /* get next chk */ - nchk = TAILQ_NEXT(chk, sctp_next); - + TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) { if (chk->data == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n"); continue; @@ -2409,12 +2348,12 @@ sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) acp = mtod(chk->data, struct sctp_asconf_chunk *); offset += sizeof(struct sctp_asconf_chunk); asconf_limit = ntohs(acp->ch.chunk_length); - p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf); - if (p_addr == NULL) { + ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf); + if (ph == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n"); continue; } - offset += ntohs(p_addr->ph.param_length); + offset += ntohs(ph->param_length); aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf); if (aph == NULL) { @@ -2443,8 +2382,8 @@ sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n"); break; } - p_addr = (struct sctp_ipv6addr_param *)(aph + 1); - if (sctp_addr_match(p_addr, &sctp_ifa->address.sa) != 0) { + ph = (struct sctp_paramhdr *)(aph + 1); + if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) { switch (param_type) { case SCTP_ADD_IP_ADDRESS: add_cnt++; @@ -2473,9 +2412,9 @@ sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) */ if (add_cnt > del_cnt || (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) { - return 1; + return (1); } - return 0; + return (0); } static struct sockaddr * @@ -2494,58 +2433,78 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked) return (NULL); } LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { - if (stcb->asoc.loopback_scope == 0 && + if (stcb->asoc.scope.loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { /* Skip if loopback_scope not set */ continue; } LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { - if (sctp_ifa->address.sa.sa_family == AF_INET && - stcb->asoc.ipv4_addr_legal) { - struct sockaddr_in *sin; + switch (sctp_ifa->address.sa.sa_family) { +#ifdef INET + case AF_INET: + if (stcb->asoc.scope.ipv4_addr_legal) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)&sctp_ifa->address.sa; + if (sin->sin_addr.s_addr == 0) { + /* skip unspecifed addresses */ + continue; + } + if (stcb->asoc.scope.ipv4_local_scope == 0 && + IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) + continue; - sin = (struct sockaddr_in *)&sctp_ifa->address.sa; - if (sin->sin_addr.s_addr == 0) { - /* skip unspecifed addresses */ - continue; + if (sctp_is_addr_restricted(stcb, sctp_ifa) && + (!sctp_is_addr_pending(stcb, sctp_ifa))) + continue; + /* + * found a valid local v4 address to + * use + */ + if (addr_locked == SCTP_ADDR_NOT_LOCKED) + SCTP_IPI_ADDR_RUNLOCK(); + return (&sctp_ifa->address.sa); } - if (stcb->asoc.ipv4_local_scope == 0 && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) - continue; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (stcb->asoc.scope.ipv6_addr_legal) { + struct sockaddr_in6 *sin6; - if (sctp_is_addr_restricted(stcb, sctp_ifa) && - (!sctp_is_addr_pending(stcb, sctp_ifa))) - continue; - /* found a valid local v4 address to use */ - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (&sctp_ifa->address.sa); - } else if (sctp_ifa->address.sa.sa_family == AF_INET6 && - stcb->asoc.ipv6_addr_legal) { - struct sockaddr_in6 *sin6; + if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { + continue; + } + sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + /* + * we skip unspecifed + * addresses + */ + continue; + } + if (stcb->asoc.scope.local_scope == 0 && + IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + if (stcb->asoc.scope.site_scope == 0 && + IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) + continue; - if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { - continue; - } - sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* we skip unspecifed addresses */ - continue; + if (sctp_is_addr_restricted(stcb, sctp_ifa) && + (!sctp_is_addr_pending(stcb, sctp_ifa))) + continue; + /* + * found a valid local v6 address to + * use + */ + if (addr_locked == SCTP_ADDR_NOT_LOCKED) + SCTP_IPI_ADDR_RUNLOCK(); + return (&sctp_ifa->address.sa); } - if (stcb->asoc.local_scope == 0 && - IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - continue; - if (stcb->asoc.site_scope == 0 && - IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) - continue; - - if (sctp_is_addr_restricted(stcb, sctp_ifa) && - (!sctp_is_addr_pending(stcb, sctp_ifa))) - continue; - /* found a valid local v6 address to use */ - if (addr_locked == SCTP_ADDR_NOT_LOCKED) - SCTP_IPI_ADDR_RUNLOCK(); - return (&sctp_ifa->address.sa); + break; +#endif + default: + break; } } } @@ -2717,7 +2676,9 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) lookup = (struct sctp_ipv6addr_param *)lookup_ptr; if (found_addr != NULL) { - if (found_addr->sa_family == AF_INET6) { + switch (found_addr->sa_family) { +#ifdef INET6 + case AF_INET6: /* copy IPv6 address */ lookup->ph.param_type = htons(SCTP_IPV6_ADDRESS); @@ -2725,7 +2686,10 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) addr_size = sizeof(struct in6_addr); addr_ptr = (caddr_t)&((struct sockaddr_in6 *) found_addr)->sin6_addr; - } else { + break; +#endif +#ifdef INET + case AF_INET: /* copy IPv4 address */ lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS); @@ -2733,21 +2697,26 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked) addr_size = sizeof(struct in_addr); addr_ptr = (caddr_t)&((struct sockaddr_in *) found_addr)->sin_addr; + break; +#endif + default: + p_size = 0; + addr_size = 0; + addr_ptr = NULL; + break; } lookup->ph.param_length = htons(SCTP_SIZE32(p_size)); memcpy(lookup->addr, addr_ptr, addr_size); SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size); - lookup_used = 1; } else { /* uh oh... don't have any address?? */ SCTPDBG(SCTP_DEBUG_ASCONF1, "compose_asconf: no lookup addr!\n"); - /* for now, we send a IPv4 address of 0.0.0.0 */ + /* XXX for now, we send a IPv4 address of 0.0.0.0 */ lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS); lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param))); bzero(lookup->addr, sizeof(struct in_addr)); SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)); - lookup_used = 1; } } /* chain it all together */ @@ -2773,9 +2742,17 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, struct sctp_paramhdr tmp_param, *ph; uint16_t plen, ptype; struct sctp_ifa *sctp_ifa; - struct sctp_ipv6addr_param addr_store; + +#ifdef INET6 + struct sctp_ipv6addr_param addr6_store; struct sockaddr_in6 sin6; + +#endif +#ifdef INET + struct sctp_ipv4addr_param addr4_store; struct sockaddr_in sin; + +#endif struct sockaddr *sa; uint32_t vrf_id; @@ -2790,51 +2767,67 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, return; } /* init the addresses */ +#ifdef INET6 bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(sin6); sin6.sin6_port = stcb->rport; +#endif +#ifdef INET bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); sin.sin_port = stcb->rport; +#endif /* go through the addresses in the init-ack */ - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, - sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param); + 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); - if (ptype == SCTP_IPV6_ADDRESS) { - struct sctp_ipv6addr_param *a6p; - - /* get the entire IPv6 address param */ - a6p = (struct sctp_ipv6addr_param *) - sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv6addr_param), - (uint8_t *) & addr_store); - if (plen != sizeof(struct sctp_ipv6addr_param) || - a6p == NULL) { - return; + switch (ptype) { +#ifdef INET6 + case SCTP_IPV6_ADDRESS: + { + struct sctp_ipv6addr_param *a6p; + + /* get the entire IPv6 address param */ + 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; + } + memcpy(&sin6.sin6_addr, a6p->addr, + sizeof(struct in6_addr)); + sa = (struct sockaddr *)&sin6; + break; } - memcpy(&sin6.sin6_addr, a6p->addr, - sizeof(struct in6_addr)); - sa = (struct sockaddr *)&sin6; - } else if (ptype == SCTP_IPV4_ADDRESS) { - struct sctp_ipv4addr_param *a4p; - - /* get the entire IPv4 address param */ - a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv4addr_param), - (uint8_t *) & addr_store); - if (plen != sizeof(struct sctp_ipv4addr_param) || - a4p == NULL) { - return; +#endif +#ifdef INET + case SCTP_IPV4_ADDRESS: + { + struct sctp_ipv4addr_param *a4p; + + /* get the entire IPv4 address param */ + 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; + } + sin.sin_addr.s_addr = a4p->addr; + sa = (struct sockaddr *)&sin; + break; } - sin.sin_addr.s_addr = a4p->addr; - sa = (struct sockaddr *)&sin; - } else { +#endif + default: goto next_addr; } @@ -2868,8 +2861,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, stcb->sctp_ep, stcb, stcb->asoc.primary_destination); #else - sctp_send_asconf(stcb, stcb->asoc.primary_destination, - SCTP_ADDR_NOT_LOCKED); + sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); #endif } } @@ -2899,28 +2891,37 @@ next_addr: * 1 if found, 0 if not */ static uint32_t -sctp_addr_in_initack(struct sctp_tcb *stcb, struct mbuf *m, uint32_t offset, - uint32_t length, struct sockaddr *sa) +sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa) { struct sctp_paramhdr tmp_param, *ph; uint16_t plen, ptype; - struct sctp_ipv6addr_param addr_store; + +#ifdef INET struct sockaddr_in *sin; struct sctp_ipv4addr_param *a4p; + struct sctp_ipv6addr_param addr4_store; +#endif #ifdef INET6 struct sockaddr_in6 *sin6; struct sctp_ipv6addr_param *a6p; + struct sctp_ipv6addr_param addr6_store; struct sockaddr_in6 sin6_tmp; -#endif /* INET6 */ +#endif - if ( + switch (sa->sa_family) { +#ifdef INET + case AF_INET: + break; +#endif #ifdef INET6 - (sa->sa_family != AF_INET6) && -#endif /* INET6 */ - (sa->sa_family != AF_INET)) + case AF_INET6: + break; +#endif + default: return (0); + } SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa); @@ -2938,55 +2939,68 @@ sctp_addr_in_initack(struct sctp_tcb *stcb, struct mbuf *m, uint32_t offset, while (ph != NULL) { ptype = ntohs(ph->param_type); plen = ntohs(ph->param_length); + switch (ptype) { #ifdef INET6 - if (ptype == SCTP_IPV6_ADDRESS && sa->sa_family == AF_INET6) { - /* get the entire IPv6 address param */ - a6p = (struct sctp_ipv6addr_param *) - sctp_m_getptr(m, offset, - sizeof(struct sctp_ipv6addr_param), - (uint8_t *) & addr_store); - if (plen != sizeof(struct sctp_ipv6addr_param) || - (ph == NULL) || - (a6p == NULL)) { - return (0); - } - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { - /* create a copy and clear scope */ - memcpy(&sin6_tmp, sin6, - sizeof(struct sockaddr_in6)); - sin6 = &sin6_tmp; - in6_clearscope(&sin6->sin6_addr); - } - if (memcmp(&sin6->sin6_addr, a6p->addr, - sizeof(struct in6_addr)) == 0) { - /* found it */ - return (1); + case SCTP_IPV6_ADDRESS: + if (sa->sa_family == AF_INET6) { + /* get the entire IPv6 address param */ + if (plen != sizeof(struct sctp_ipv6addr_param)) { + break; + } + /* get the entire IPv6 address param */ + a6p = (struct sctp_ipv6addr_param *) + sctp_m_getptr(m, offset, + sizeof(struct sctp_ipv6addr_param), + (uint8_t *) & addr6_store); + if (a6p == NULL) { + return (0); + } + sin6 = (struct sockaddr_in6 *)sa; + if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { + /* create a copy and clear scope */ + memcpy(&sin6_tmp, sin6, + sizeof(struct sockaddr_in6)); + sin6 = &sin6_tmp; + in6_clearscope(&sin6->sin6_addr); + } + if (memcmp(&sin6->sin6_addr, a6p->addr, + sizeof(struct in6_addr)) == 0) { + /* found it */ + return (1); + } } - } else + break; #endif /* INET6 */ - - if (ptype == SCTP_IPV4_ADDRESS && - sa->sa_family == AF_INET) { - /* get the entire IPv4 address param */ - a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, - offset, sizeof(struct sctp_ipv4addr_param), - (uint8_t *) & addr_store); - if (plen != sizeof(struct sctp_ipv4addr_param) || - (ph == NULL) || - (a4p == NULL)) { - return (0); - } - sin = (struct sockaddr_in *)sa; - if (sin->sin_addr.s_addr == a4p->addr) { - /* found it */ - return (1); +#ifdef INET + case SCTP_IPV4_ADDRESS: + if (sa->sa_family == AF_INET) { + if (plen != sizeof(struct sctp_ipv4addr_param)) { + break; + } + /* get the entire IPv4 address param */ + a4p = (struct sctp_ipv4addr_param *) + sctp_m_getptr(m, offset, + sizeof(struct sctp_ipv4addr_param), + (uint8_t *) & addr4_store); + if (a4p == NULL) { + return (0); + } + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr == a4p->addr) { + /* found it */ + return (1); + } } + break; +#endif + default: + break; } /* get next parameter */ offset += SCTP_SIZE32(plen); - if (offset + sizeof(struct sctp_paramhdr) > length) + if (offset + sizeof(struct sctp_paramhdr) > length) { return (0); + } ph = (struct sctp_paramhdr *) sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param); @@ -3023,8 +3037,7 @@ sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset, continue; } /* check to see if in the init-ack */ - if (!sctp_addr_in_initack(stcb, m, offset, length, - &laddr->ifa->address.sa)) { + if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) { /* try to add it */ sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa, SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED); @@ -3047,6 +3060,15 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_ifa *sctp_ifa; uint32_t vrf_id; +#ifdef INET + struct sockaddr_in *sin; + +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6; + +#endif + if (stcb) { vrf_id = stcb->asoc.vrf_id; } else { @@ -3070,9 +3092,35 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) { continue; } + switch (sctp_ifa->address.sa.sa_family) { +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)&sctp_ifa->address.sin; + if ((ipv4_scope == 0) && + (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { + /* private address not in scope */ + continue; + } + break; +#endif +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sin6; + if ((local_scope == 0) && + (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { + continue; + } + if ((site_scope == 0) && + (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { + continue; + } + break; +#endif + default: + break; + } /* check to see if in the init-ack */ - if (!sctp_addr_in_initack(stcb, m, offset, length, - &sctp_ifa->address.sa)) { + if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) { /* try to add it */ sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, sctp_ifa, SCTP_ADD_IP_ADDRESS, @@ -3124,6 +3172,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap) { struct sctp_ifa *ifa; + struct sctp_laddr *laddr, *nladdr; if (sa->sa_len == 0) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); @@ -3144,8 +3193,6 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, if (type == SCTP_ADD_IP_ADDRESS) { sctp_add_local_addr_ep(inp, ifa, type); } else if (type == SCTP_DEL_IP_ADDRESS) { - struct sctp_laddr *laddr; - if (inp->laddr_count < 2) { /* can't delete the last local address */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); @@ -3159,11 +3206,19 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, } } } - if (!LIST_EMPTY(&inp->sctp_asoc_list)) { + if (LIST_EMPTY(&inp->sctp_asoc_list)) { /* * There is no need to start the iterator if the inp * has no associations. */ + if (type == SCTP_DEL_IP_ADDRESS) { + LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { + if (laddr->ifa == ifa) { + sctp_del_local_addr_ep(inp, ifa); + } + } + } + } else { struct sctp_asconf_iterator *asc; struct sctp_laddr *wi; @@ -3211,8 +3266,11 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, struct sctp_asconf_addr *aa; struct sctp_ifa *sctp_ifap; struct sctp_asconf_tag_param *vtag; + +#ifdef INET struct sockaddr_in *to; +#endif #ifdef INET6 struct sockaddr_in6 *to6; @@ -3260,24 +3318,28 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, memset(aa, 0, sizeof(struct sctp_asconf_addr)); /* fill in asconf address parameter fields */ /* ADD(0.0.0.0) */ - if (net->ro._l_addr.sa.sa_family == AF_INET) { + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param); /* No need to add an address, we are using 0.0.0.0 */ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); - } + break; +#endif #ifdef INET6 - else if (net->ro._l_addr.sa.sa_family == AF_INET6) { + case AF_INET6: aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param); /* No need to add an address, we are using 0.0.0.0 */ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); + break; +#endif } -#endif /* INET6 */ SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), SCTP_M_ASC_ADDR); if (aa == NULL) { @@ -3289,24 +3351,28 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, memset(aa, 0, sizeof(struct sctp_asconf_addr)); /* fill in asconf address parameter fields */ /* ADD(0.0.0.0) */ - if (net->ro._l_addr.sa.sa_family == AF_INET) { + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS; aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param); aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS; aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param); /* No need to add an address, we are using 0.0.0.0 */ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); - } + break; +#endif #ifdef INET6 - else if (net->ro._l_addr.sa.sa_family == AF_INET6) { + case AF_INET6: aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS; aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param); aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS; aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param); /* No need to add an address, we are using 0.0.0.0 */ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next); + break; +#endif } -#endif /* INET6 */ /* Now we must hunt the addresses and add all global addresses */ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { struct sctp_vrf *vrf = NULL; @@ -3321,18 +3387,20 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, SCTP_IPI_ADDR_RLOCK(); LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { - if (sctp_ifap->address.sa.sa_family == AF_INET) { + switch (sctp_ifap->address.sa.sa_family) { +#ifdef INET + case AF_INET: to = &sctp_ifap->address.sin; - if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { continue; } if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { continue; } - } + break; +#endif #ifdef INET6 - else if (sctp_ifap->address.sa.sa_family == AF_INET6) { + case AF_INET6: to6 = &sctp_ifap->address.sin6; if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { continue; @@ -3340,8 +3408,11 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { continue; } - } + break; #endif + default: + continue; + } sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); } } @@ -3367,18 +3438,20 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, continue; } sctp_ifap = laddr->ifa; - if (sctp_ifap->address.sa.sa_family == AF_INET) { + switch (sctp_ifap->address.sa.sa_family) { +#ifdef INET + case AF_INET: to = &sctp_ifap->address.sin; - if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) { continue; } if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { continue; } - } + break; +#endif #ifdef INET6 - else if (sctp_ifap->address.sa.sa_family == AF_INET6) { + case AF_INET6: to6 = &sctp_ifap->address.sin6; if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { continue; @@ -3386,12 +3459,15 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { continue; } - } + break; #endif + default: + continue; + } sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS); } } skip_rest: /* Now we must send the asconf into the queue */ - sctp_send_asconf(stcb, net, 0); + sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); } |