diff options
author | rrs <rrs@FreeBSD.org> | 2007-07-24 20:06:02 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-07-24 20:06:02 +0000 |
commit | 1db8ba247453b3da31775f1a39199179ca75bfb7 (patch) | |
tree | d2ea0fd9ef19605e959e0ed17a4723e94186c995 /sys/netinet/sctputil.c | |
parent | 4177278d87cbfa0b06b72d4b526e3a39dbd7838b (diff) | |
download | FreeBSD-src-1db8ba247453b3da31775f1a39199179ca75bfb7.zip FreeBSD-src-1db8ba247453b3da31775f1a39199179ca75bfb7.tar.gz |
- take out a needless panic under invariants for sctp_output.c
- Fix addrs's error checking of sctp_sendx(3) when addrcnt is less than
SCTP_SMALL_IOVEC_SIZE
- re-add back inpcb_bind local address check bypass capability
- Fix it so sctp_opt_info is independant of assoc_id postion.
- Fix cookie life set to use MSEC_TO_TICKS() macro.
- asconf changes
o More comment changes/clarifications related to the old local address
"not" list which is now an explicit restricted list.
o Rename some functions for clarity:
- sctp_add/del_local_addr_assoc to xxx_local_addr_restricted()
- asconf related iterator functions to sctp_asconf_iterator_xxx()
o Fix bug when the same address is deleted and added (and removed from
the asconf queue) where the ifa is "freed" twice refcount wise,
possibly freeing it completely.
o Fix bug in output where the first ASCONF would not go out after the
last address is changed (e.g. only goes out when retransmitted).
o Fix bug where multiple ASCONFs can be bundled in the same packet with
the and with the same serial numbers.
o Fix asconf stcb iterator to not send ASCONF until after all work
queue entries have been processed.
o Change behavior so that when the last address is deleted (auto asconf
on a bound all endpoint) no action is taken until an address is
added; at that time, an ASCONF add+delete is sent (if the assoc
is still up).
o Fix local address counting so that address scoping is taken into
account.
o #ifdef SCTP_TIMER_BASED_ASCONF the old timer triggered sending
of ASCONF (after an RTO). The default now is to send
ASCONF immediately (except for the case of changing/deleting the
last usable address).
Approved by: re(ken smith)@freebsd.org
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 130 |
1 files changed, 120 insertions, 10 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index b70a1e7..bf0eb29 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1373,15 +1373,15 @@ sctp_handle_addr_wq(void) if (asc->cnt == 0) { SCTP_FREE(asc, SCTP_M_ASC_IT); } else { - (void)sctp_initiate_iterator(sctp_iterator_ep, - sctp_iterator_stcb, + (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, + sctp_asconf_iterator_stcb, NULL, /* No ep end for boundall */ SCTP_PCB_FLAGS_BOUNDALL, SCTP_PCB_ANY_FEATURES, - SCTP_ASOC_ANY_STATE, (void *)asc, 0, - sctp_iterator_end, NULL, 0); + SCTP_ASOC_ANY_STATE, + (void *)asc, 0, + sctp_asconf_iterator_end, NULL, 0); } - } int retcode = 0; @@ -2078,8 +2078,8 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_STRRESET: /* - * Here the timer comes from the inp but its value is from - * the RTO. + * Here the timer comes from the stcb but its value is from + * the net's RTO. */ if ((stcb == NULL) || (net == NULL)) { return; @@ -2122,8 +2122,8 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, break; case SCTP_TIMER_TYPE_ASCONF: /* - * Here the timer comes from the inp but its value is from - * the RTO. + * Here the timer comes from the stcb but its value is from + * the net's RTO. */ if ((stcb == NULL) || (net == NULL)) { return; @@ -5932,7 +5932,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, *error = EINVAL; return; } - *error = sctp_inpcb_bind(so, addr_touse, p); + *error = sctp_inpcb_bind(so, addr_touse, NULL, p); return; } /* @@ -6056,3 +6056,113 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp, */ } } + +/* + * returns the valid local address count for an assoc, taking into account + * all scoping rules + */ +int +sctp_local_addr_count(struct sctp_tcb *stcb) +{ + int loopback_scope, ipv4_local_scope, local_scope, site_scope; + int ipv4_addr_legal, ipv6_addr_legal; + struct sctp_vrf *vrf; + struct sctp_ifn *sctp_ifn; + struct sctp_ifa *sctp_ifa; + int count = 0; + + /* Turn on all the appropriate scopes */ + loopback_scope = stcb->asoc.loopback_scope; + ipv4_local_scope = stcb->asoc.ipv4_local_scope; + local_scope = stcb->asoc.local_scope; + site_scope = stcb->asoc.site_scope; + ipv4_addr_legal = ipv6_addr_legal = 0; + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { + ipv6_addr_legal = 1; + if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) { + ipv4_addr_legal = 1; + } + } else { + ipv4_addr_legal = 1; + } + + vrf = sctp_find_vrf(stcb->asoc.vrf_id); + if (vrf == NULL) { + /* no vrf, no addresses */ + return (0); + } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + /* + * bound all case: go through all ifns on the vrf + */ + LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { + if ((loopback_scope == 0) && + SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { + continue; + } + LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { + if (sctp_is_addr_restricted(stcb, sctp_ifa)) + continue; + + if ((sctp_ifa->address.sa.sa_family == AF_INET) && + (ipv4_addr_legal)) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)&sctp_ifa->address.sa; + if (sin->sin_addr.s_addr == 0) { + /* skip unspecified addrs */ + continue; + } + if ((ipv4_local_scope == 0) && + (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { + continue; + } + /* count this one */ + count++; + } else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && + (ipv6_addr_legal)) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + continue; + } + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + if (local_scope == 0) + continue; + if (sin6->sin6_scope_id == 0) { + if (sa6_recoverscope(sin6) != 0) + /* + * bad link + * local + * address + */ + continue; + } + } + if ((site_scope == 0) && + (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { + continue; + } + /* count this one */ + count++; + } + } + } + } else { + /* + * subset bound case + */ + struct sctp_laddr *laddr; + + LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, + sctp_nxt_addr) { + if (sctp_is_addr_restricted(stcb, laddr->ifa)) { + continue; + } + /* count this one */ + count++; + } + } + return (count); +} |