diff options
Diffstat (limited to 'freebsd/sys/netinet/sctp_pcb.c')
-rw-r--r-- | freebsd/sys/netinet/sctp_pcb.c | 2229 |
1 files changed, 1191 insertions, 1038 deletions
diff --git a/freebsd/sys/netinet/sctp_pcb.c b/freebsd/sys/netinet/sctp_pcb.c index 98c5b707..8a0cdb42 100644 --- a/freebsd/sys/netinet/sctp_pcb.c +++ b/freebsd/sys/netinet/sctp_pcb.c @@ -2,16 +2,18 @@ /*- * Copyright (c) 2001-2008, 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,8 +32,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -/* $KAME: sctp_pcb.c,v 1.38 2005/03/06 16:04:18 itojun Exp $ */ - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -47,7 +47,14 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_output.h> #include <netinet/sctp_timer.h> #include <netinet/sctp_bsd_addr.h> +#include <netinet/sctp_dtrace_define.h> #include <netinet/udp.h> +#ifdef INET6 +#include <netinet6/ip6_var.h> +#endif +#include <sys/sched.h> +#include <sys/smp.h> +#include <rtems/bsd/sys/unistd.h> VNET_DEFINE(struct sctp_base_info, system_base_info); @@ -62,11 +69,11 @@ SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b) memcpy(&tmp_a, a, sizeof(struct sockaddr_in6)); if (sa6_embedscope(&tmp_a, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - return 0; + return (0); } memcpy(&tmp_b, b, sizeof(struct sockaddr_in6)); if (sa6_embedscope(&tmp_b, MODULE_GLOBAL(ip6_use_defzone)) != 0) { - return 0; + return (0); } return (IN6_ARE_ADDR_EQUAL(&tmp_a.sin6_addr, &tmp_b.sin6_addr)); } @@ -89,11 +96,10 @@ sctp_fill_pcbinfo(struct sctp_pcbinfo *spcb) spcb->readq_count = SCTP_BASE_INFO(ipi_count_readq); spcb->stream_oque = SCTP_BASE_INFO(ipi_count_strmoq); spcb->free_chunks = SCTP_BASE_INFO(ipi_free_chunks); - SCTP_INP_INFO_RUNLOCK(); } -/* +/*- * Addresses are added to VRF's (Virtual Router's). For BSD we * have only the default VRF 0. We maintain a hash list of * VRF's. Each VRF has its own list of sctp_ifn's. Each of @@ -209,7 +215,6 @@ sctp_find_ifn(void *ifn, uint32_t ifn_index) } - struct sctp_vrf * sctp_find_vrf(uint32_t vrf_id) { @@ -225,6 +230,7 @@ sctp_find_vrf(uint32_t vrf_id) return (NULL); } + void sctp_free_vrf(struct sctp_vrf *vrf) { @@ -240,6 +246,7 @@ sctp_free_vrf(struct sctp_vrf *vrf) } } + void sctp_free_ifn(struct sctp_ifn *sctp_ifnp) { @@ -253,6 +260,7 @@ sctp_free_ifn(struct sctp_ifn *sctp_ifnp) } } + void sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu) { @@ -278,6 +286,7 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap) } } + static void sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) { @@ -300,12 +309,13 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) sctp_free_ifn(sctp_ifnp); } + void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index) { struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap = NULL; + struct sctp_ifa *sctp_ifap; SCTP_IPI_ADDR_RLOCK(); vrf = sctp_find_vrf(vrf_id); @@ -324,19 +334,9 @@ sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, goto out; } if (if_name) { - int len1, len2; - - len1 = strlen(if_name); - len2 = strlen(sctp_ifap->ifn_p->ifn_name); - if (len1 != len2) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN of ifa names different length %d vs %d - ignored\n", - len1, len2); - goto out; - } - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) { + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, - if_name); + sctp_ifap->ifn_p->ifn_name, if_name); goto out; } } else { @@ -353,12 +353,13 @@ out: SCTP_IPI_ADDR_RUNLOCK(); } + void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index) { struct sctp_vrf *vrf; - struct sctp_ifa *sctp_ifap = NULL; + struct sctp_ifa *sctp_ifap; SCTP_IPI_ADDR_RLOCK(); vrf = sctp_find_vrf(vrf_id); @@ -377,19 +378,9 @@ sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, goto out; } if (if_name) { - int len1, len2; - - len1 = strlen(if_name); - len2 = strlen(sctp_ifap->ifn_p->ifn_name); - if (len1 != len2) { - SCTPDBG(SCTP_DEBUG_PCB4, "IFN of ifa names different length %d vs %d - ignored\n", - len1, len2); - goto out; - } - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) { + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) != 0) { SCTPDBG(SCTP_DEBUG_PCB4, "IFN %s of IFA not the same as %s\n", - sctp_ifap->ifn_p->ifn_name, - if_name); + sctp_ifap->ifn_p->ifn_name, if_name); goto out; } } else { @@ -406,6 +397,7 @@ out: SCTP_IPI_ADDR_RUNLOCK(); } + /*- * Add an ifa to an ifn. * Register the interface as necessary. @@ -422,10 +414,20 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) /* update address counts */ sctp_ifnp->ifa_count++; ifa_af = sctp_ifap->address.sa.sa_family; - if (ifa_af == AF_INET) + switch (ifa_af) { +#ifdef INET + case AF_INET: sctp_ifnp->num_v4++; - else + break; +#endif +#ifdef INET6 + case AF_INET6: sctp_ifnp->num_v6++; + break; +#endif + default: + break; + } if (sctp_ifnp->ifa_count == 1) { /* register the new interface */ SCTP_REGISTER_INTERFACE(sctp_ifnp->ifn_index, ifa_af); @@ -433,6 +435,7 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) } } + /*- * Remove an ifa from its ifn. * If no more addresses exist, remove the ifn too. Otherwise, re-register @@ -442,18 +445,25 @@ sctp_add_ifa_to_ifn(struct sctp_ifn *sctp_ifnp, struct sctp_ifa *sctp_ifap) static void sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) { - uint32_t ifn_index; - LIST_REMOVE(sctp_ifap, next_ifa); if (sctp_ifap->ifn_p) { /* update address counts */ sctp_ifap->ifn_p->ifa_count--; - if (sctp_ifap->address.sa.sa_family == AF_INET6) - sctp_ifap->ifn_p->num_v6--; - else if (sctp_ifap->address.sa.sa_family == AF_INET) + switch (sctp_ifap->address.sa.sa_family) { +#ifdef INET + case AF_INET: sctp_ifap->ifn_p->num_v4--; + break; +#endif +#ifdef INET6 + case AF_INET6: + sctp_ifap->ifn_p->num_v6--; + break; +#endif + default: + break; + } - ifn_index = sctp_ifap->ifn_p->ifn_index; if (LIST_EMPTY(&sctp_ifap->ifn_p->ifalist)) { /* remove the ifn, possibly freeing it */ sctp_delete_ifn(sctp_ifap->ifn_p, SCTP_ADDR_LOCKED); @@ -461,13 +471,13 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) /* re-register address family type, if needed */ if ((sctp_ifap->ifn_p->num_v6 == 0) && (sctp_ifap->ifn_p->registered_af == AF_INET6)) { - SCTP_DEREGISTER_INTERFACE(ifn_index, AF_INET6); - SCTP_REGISTER_INTERFACE(ifn_index, AF_INET); + SCTP_DEREGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET6); + SCTP_REGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET); sctp_ifap->ifn_p->registered_af = AF_INET; } else if ((sctp_ifap->ifn_p->num_v4 == 0) && (sctp_ifap->ifn_p->registered_af == AF_INET)) { - SCTP_DEREGISTER_INTERFACE(ifn_index, AF_INET); - SCTP_REGISTER_INTERFACE(ifn_index, AF_INET6); + SCTP_DEREGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET); + SCTP_REGISTER_INTERFACE(sctp_ifap->ifn_p->ifn_index, AF_INET6); sctp_ifap->ifn_p->registered_af = AF_INET6; } /* free the ifn refcount */ @@ -477,6 +487,7 @@ sctp_remove_ifa_from_ifn(struct sctp_ifa *sctp_ifap) } } + struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, uint32_t ifn_type, const char *if_name, void *ifa, @@ -532,9 +543,9 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, atomic_add_int(&vrf->refcount, 1); sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, addr->sa_family); if (if_name != NULL) { - memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ); + snprintf(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name); } else { - memcpy(sctp_ifnp->ifn_name, "unknown", min(7, SCTP_IFNAMSIZ)); + snprintf(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "unknown"); } hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; LIST_INIT(&sctp_ifnp->ifalist); @@ -551,7 +562,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, (sctp_ifap->ifn_p->ifn_index == ifn_index)) { SCTPDBG(SCTP_DEBUG_PCB4, "Using existing ifn %s (0x%x) for ifa %p\n", sctp_ifap->ifn_p->ifn_name, ifn_index, - sctp_ifap); + (void *)sctp_ifap); if (new_ifn_af) { /* Remove the created one that we don't want */ sctp_delete_ifn(sctp_ifnp, SCTP_ADDR_LOCKED); @@ -573,7 +584,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, * old one */ SCTPDBG(SCTP_DEBUG_PCB4, "Moving ifa %p from %s (0x%x) to %s (0x%x)\n", - sctp_ifap, sctp_ifap->ifn_p->ifn_name, + (void *)sctp_ifap, sctp_ifap->ifn_p->ifn_name, sctp_ifap->ifn_p->ifn_index, if_name, ifn_index); /* remove the address from the old ifn */ @@ -585,7 +596,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, /* repair ifnp which was NULL ? */ sctp_ifap->localifa_flags = SCTP_ADDR_VALID; SCTPDBG(SCTP_DEBUG_PCB4, "Repairing ifn %p for ifa %p\n", - sctp_ifnp, sctp_ifap); + (void *)sctp_ifnp, (void *)sctp_ifap); sctp_add_ifa_to_ifn(sctp_ifnp, sctp_ifap); } goto exit_stage_left; @@ -609,6 +620,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sctp_ifap->flags = ifa_flags; /* Set scope */ switch (sctp_ifap->address.sa.sa_family) { +#ifdef INET case AF_INET: { struct sockaddr_in *sin; @@ -626,6 +638,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, new_ifn_af = AF_INET; break; } +#endif #ifdef INET6 case AF_INET6: { @@ -739,19 +752,9 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, * panda who might recycle indexes fast. */ if (if_name) { - int len1, len2; - - len1 = min(SCTP_IFNAMSIZ, strlen(if_name)); - len2 = min(SCTP_IFNAMSIZ, strlen(sctp_ifap->ifn_p->ifn_name)); - if (len1 && len2 && (len1 == len2)) { - /* we can compare them */ - if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) == 0) { - /* - * They match its a correct - * delete - */ - valid = 1; - } + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, SCTP_IFNAMSIZ) == 0) { + /* They match its a correct delete */ + valid = 1; } } if (!valid) { @@ -769,7 +772,7 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, return; } } - SCTPDBG(SCTP_DEBUG_PCB4, "Deleting ifa %p\n", sctp_ifap); + SCTPDBG(SCTP_DEBUG_PCB4, "Deleting ifa %p\n", (void *)sctp_ifap); sctp_ifap->localifa_flags &= SCTP_ADDR_VALID; sctp_ifap->localifa_flags |= SCTP_BEING_DELETED; vrf->total_ifa_count--; @@ -823,6 +826,160 @@ out_now: } +static int +sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) +{ + 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; + + loopback_scope = stcb->asoc.scope.loopback_scope; + ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; + local_scope = stcb->asoc.scope.local_scope; + site_scope = stcb->asoc.scope.site_scope; + ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; + ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; + + SCTP_IPI_ADDR_RLOCK(); + vrf = sctp_find_vrf(stcb->asoc.vrf_id); + if (vrf == NULL) { + /* no vrf, no addresses */ + SCTP_IPI_ADDR_RUNLOCK(); + return (0); + } + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + 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) && + (!sctp_is_addr_pending(stcb, sctp_ifa))) { + /* + * We allow pending addresses, where + * we have sent an asconf-add to be + * considered valid. + */ + continue; + } + switch (sctp_ifa->address.sa.sa_family) { +#ifdef INET + case AF_INET: + if (ipv4_addr_legal) { + struct sockaddr_in *sin, + *rsin; + + sin = &sctp_ifa->address.sin; + rsin = (struct sockaddr_in *)to; + if ((ipv4_local_scope == 0) && + IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { + continue; + } + if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (ipv6_addr_legal) { + struct sockaddr_in6 *sin6, + *rsin6; + + sin6 = &sctp_ifa->address.sin6; + rsin6 = (struct sockaddr_in6 *)to; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + if (local_scope == 0) + continue; + if (sin6->sin6_scope_id == 0) { + if (sa6_recoverscope(sin6) != 0) + continue; + } + } + if ((site_scope == 0) && + (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { + continue; + } + if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + } + break; +#endif + default: + /* TSNH */ + break; + } + } + } + } else { + struct sctp_laddr *laddr; + + LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) { + if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { + SCTPDBG(SCTP_DEBUG_PCB1, "ifa being deleted\n"); + continue; + } + if (sctp_is_addr_restricted(stcb, laddr->ifa) && + (!sctp_is_addr_pending(stcb, laddr->ifa))) { + /* + * We allow pending addresses, where we have + * sent an asconf-add to be considered + * valid. + */ + continue; + } + if (laddr->ifa->address.sa.sa_family != to->sa_family) { + continue; + } + switch (to->sa_family) { +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin, *rsin; + + sin = (struct sockaddr_in *)&laddr->ifa->address.sin; + rsin = (struct sockaddr_in *)to; + if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + break; + } +#endif +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6, *rsin6; + + sin6 = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; + rsin6 = (struct sockaddr_in6 *)to; + if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { + SCTP_IPI_ADDR_RUNLOCK(); + return (1); + } + break; + } + +#endif + default: + /* TSNH */ + break; + } + + } + } + SCTP_IPI_ADDR_RUNLOCK(); + return (0); +} + + static struct sctp_tcb * sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id) @@ -842,14 +999,29 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, if ((to == NULL) || (from == NULL)) { return (NULL); } - if (to->sa_family == AF_INET && from->sa_family == AF_INET) { - lport = ((struct sockaddr_in *)to)->sin_port; - rport = ((struct sockaddr_in *)from)->sin_port; - } else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { - lport = ((struct sockaddr_in6 *)to)->sin6_port; - rport = ((struct sockaddr_in6 *)from)->sin6_port; - } else { - return NULL; + switch (to->sa_family) { +#ifdef INET + case AF_INET: + if (from->sa_family == AF_INET) { + lport = ((struct sockaddr_in *)to)->sin_port; + rport = ((struct sockaddr_in *)from)->sin_port; + } else { + return (NULL); + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (from->sa_family == AF_INET6) { + lport = ((struct sockaddr_in6 *)to)->sin6_port; + rport = ((struct sockaddr_in6 *)from)->sin6_port; + } else { + return (NULL); + } + break; +#endif + default: + return (NULL); } ephead = &SCTP_BASE_INFO(sctp_tcpephash)[SCTP_PCBHASH_ALLADDR((lport | rport), SCTP_BASE_INFO(hashtcpmark))]; /* @@ -890,17 +1062,20 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, if (laddr->ifa->address.sa.sa_family == to->sa_family) { /* see if it matches */ - struct sockaddr_in *intf_addr, *sin; - - intf_addr = &laddr->ifa->address.sin; - sin = (struct sockaddr_in *)to; +#ifdef INET if (from->sa_family == AF_INET) { + struct sockaddr_in *intf_addr, + *sin; + + intf_addr = &laddr->ifa->address.sin; + sin = (struct sockaddr_in *)to; if (sin->sin_addr.s_addr == intf_addr->sin_addr.s_addr) { match = 1; break; } } +#endif #ifdef INET6 if (from->sa_family == AF_INET6) { struct sockaddr_in6 *intf_addr6; @@ -929,13 +1104,18 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, * Ok if we hit here the ep has the address, does it hold * the tcb? */ - + /* XXX: Why don't we TAILQ_FOREACH through sctp_asoc_list? */ stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { SCTP_INP_RUNLOCK(inp); continue; } SCTP_TCB_LOCK(stcb); + if (!sctp_does_stcb_own_this_addr(stcb, to)) { + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_RUNLOCK(inp); + continue; + } if (stcb->rport != rport) { /* remote port does not match. */ SCTP_TCB_UNLOCK(stcb); @@ -947,6 +1127,11 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, SCTP_INP_RUNLOCK(inp); continue; } + if (!sctp_does_stcb_own_this_addr(stcb, to)) { + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_RUNLOCK(inp); + continue; + } /* Does this TCB have a matching address? */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { @@ -955,6 +1140,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, continue; } switch (from->sa_family) { +#ifdef INET case AF_INET: { struct sockaddr_in *sin, *rsin; @@ -977,6 +1163,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, } break; } +#endif #ifdef INET6 case AF_INET6: { @@ -1012,148 +1199,6 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, return (NULL); } -static int -sctp_does_stcb_own_this_addr(struct sctp_tcb *stcb, struct sockaddr *to) -{ - 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; - - 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; - } - - SCTP_IPI_ADDR_RLOCK(); - vrf = sctp_find_vrf(stcb->asoc.vrf_id); - if (vrf == NULL) { - /* no vrf, no addresses */ - SCTP_IPI_ADDR_RUNLOCK(); - return (0); - } - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - 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; - switch (sctp_ifa->address.sa.sa_family) { -#ifdef INET - case AF_INET: - if (ipv4_addr_legal) { - struct sockaddr_in *sin, - *rsin; - - sin = &sctp_ifa->address.sin; - rsin = (struct sockaddr_in *)to; - if ((ipv4_local_scope == 0) && - IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - continue; - } - if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if (ipv6_addr_legal) { - struct sockaddr_in6 *sin6, - *rsin6; - - sin6 = &sctp_ifa->address.sin6; - rsin6 = (struct sockaddr_in6 *)to; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - if (local_scope == 0) - continue; - if (sin6->sin6_scope_id == 0) { - if (sa6_recoverscope(sin6) != 0) - continue; - } - } - if ((site_scope == 0) && - (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { - continue; - } - if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - } - break; -#endif - default: - /* TSNH */ - break; - } - } - } - } else { - 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; - } - if (laddr->ifa->address.sa.sa_family != to->sa_family) { - continue; - } - switch (to->sa_family) { -#ifdef INET - case AF_INET: - { - struct sockaddr_in *sin, *rsin; - - sin = (struct sockaddr_in *)&laddr->ifa->address.sin; - rsin = (struct sockaddr_in *)to; - if (sin->sin_addr.s_addr == rsin->sin_addr.s_addr) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - break; - } -#endif -#ifdef INET6 - case AF_INET6: - { - struct sockaddr_in6 *sin6, *rsin6; - - sin6 = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; - rsin6 = (struct sockaddr_in6 *)to; - if (SCTP6_ARE_ADDR_EQUAL(sin6, rsin6)) { - SCTP_IPI_ADDR_RUNLOCK(); - return (1); - } - break; - } - -#endif - default: - /* TSNH */ - break; - } - - } - } - SCTP_IPI_ADDR_RUNLOCK(); - return (0); -} /* * rules for use @@ -1175,11 +1220,18 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, uint16_t rport; inp = *inp_p; - if (remote->sa_family == AF_INET) { + switch (remote->sa_family) { +#ifdef INET + case AF_INET: rport = (((struct sockaddr_in *)remote)->sin_port); - } else if (remote->sa_family == AF_INET6) { + break; +#endif +#ifdef INET6 + case AF_INET6: rport = (((struct sockaddr_in6 *)remote)->sin6_port); - } else { + break; +#endif + default: return (NULL); } if (locked_tcb) { @@ -1191,7 +1243,8 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, SCTP_TCB_UNLOCK(locked_tcb); } SCTP_INP_INFO_RLOCK(); - if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { /*- * Now either this guy is our listener or it's the * connector. If it is the one that issued the connect, then @@ -1252,6 +1305,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, continue; } switch (remote->sa_family) { +#ifdef INET case AF_INET: { struct sockaddr_in *sin, @@ -1280,6 +1334,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } break; } +#endif #ifdef INET6 case AF_INET6: { @@ -1353,6 +1408,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, continue; } switch (remote->sa_family) { +#ifdef INET case AF_INET: { struct sockaddr_in *sin, @@ -1381,6 +1437,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } break; } +#endif #ifdef INET6 case AF_INET6: { @@ -1431,11 +1488,11 @@ null_return: return (NULL); } + /* * Find an association for a specific endpoint using the association id given * out in the COMM_UP notification */ - struct sctp_tcb * sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock) { @@ -1496,37 +1553,39 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int } +/* + * Endpoint probe expects that the INP_INFO is locked. + */ static struct sctp_inpcb * sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, uint16_t lport, uint32_t vrf_id) { struct sctp_inpcb *inp; - struct sockaddr_in *sin; + struct sctp_laddr *laddr; -#ifdef INET6 - struct sockaddr_in6 *sin6; +#ifdef INET + struct sockaddr_in *sin; #endif - struct sctp_laddr *laddr; - #ifdef INET6 + struct sockaddr_in6 *sin6; struct sockaddr_in6 *intf_addr6; #endif - int fnd; - /* - * Endpoint probe expects that the INP_INFO is locked. - */ +#ifdef INET sin = NULL; +#endif #ifdef INET6 sin6 = NULL; #endif switch (nam->sa_family) { +#ifdef INET case AF_INET: sin = (struct sockaddr_in *)nam; break; +#endif #ifdef INET6 case AF_INET6: sin6 = (struct sockaddr_in6 *)nam; @@ -1549,6 +1608,7 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) && (inp->sctp_lport == lport)) { /* got it */ +#ifdef INET if ((nam->sa_family == AF_INET) && (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && SCTP_IPV6_V6ONLY(inp)) { @@ -1556,12 +1616,15 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, SCTP_INP_RUNLOCK(inp); continue; } +#endif +#ifdef INET6 /* A V6 address and the endpoint is NOT bound V6 */ if (nam->sa_family == AF_INET6 && (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { SCTP_INP_RUNLOCK(inp); continue; } +#endif /* does a VRF id match? */ fnd = 0; if (inp->def_vrf_id == vrf_id) @@ -1574,18 +1637,26 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, } SCTP_INP_RUNLOCK(inp); } - if ((nam->sa_family == AF_INET) && - (sin->sin_addr.s_addr == INADDR_ANY)) { - /* Can't hunt for one that has no address specified */ - return (NULL); - } + switch (nam->sa_family) { +#ifdef INET + case AF_INET: + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* Can't hunt for one that has no address specified */ + return (NULL); + } + break; +#endif #ifdef INET6 - if ((nam->sa_family == AF_INET6) && - (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) { - /* Can't hunt for one that has no address specified */ - return (NULL); - } + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + /* Can't hunt for one that has no address specified */ + return (NULL); + } + break; #endif + default: + break; + } /* * ok, not bound to all so see if we can find a EP bound to this * address. @@ -1624,24 +1695,23 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head, continue; } SCTPDBG(SCTP_DEBUG_PCB1, "Ok laddr->ifa:%p is possible, ", - laddr->ifa); + (void *)laddr->ifa); if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { SCTPDBG(SCTP_DEBUG_PCB1, "Huh IFA being deleted\n"); continue; } if (laddr->ifa->address.sa.sa_family == nam->sa_family) { /* possible, see if it matches */ - struct sockaddr_in *intf_addr; - - intf_addr = &laddr->ifa->address.sin; switch (nam->sa_family) { +#ifdef INET case AF_INET: if (sin->sin_addr.s_addr == - intf_addr->sin_addr.s_addr) { + laddr->ifa->address.sin.sin_addr.s_addr) { SCTP_INP_RUNLOCK(inp); return (inp); } break; +#endif #ifdef INET6 case AF_INET6: intf_addr6 = &laddr->ifa->address.sin6; @@ -1770,19 +1840,32 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock, */ struct sctp_inpcb *inp; struct sctppcbhead *head; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; int lport; unsigned int i; - if (nam->sa_family == AF_INET) { +#ifdef INET + struct sockaddr_in *sin; + +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6; + +#endif + + switch (nam->sa_family) { +#ifdef INET + case AF_INET: sin = (struct sockaddr_in *)nam; - lport = ((struct sockaddr_in *)nam)->sin_port; - } else if (nam->sa_family == AF_INET6) { + lport = sin->sin_port; + break; +#endif +#ifdef INET6 + case AF_INET6: sin6 = (struct sockaddr_in6 *)nam; - lport = ((struct sockaddr_in6 *)nam)->sin6_port; - } else { - /* unsupported family */ + lport = sin6->sin6_port; + break; +#endif + default: return (NULL); } /* @@ -1826,31 +1909,32 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock, return (inp); } + /* * Find an association for an endpoint with the pointer to whom you want to * send to and the endpoint pointer. The address can be IPv4 or IPv6. We may * need to change the *to to some other struct like a mbuf... */ struct sctp_tcb * -sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from, +sctp_findassociation_addr_sa(struct sockaddr *from, struct sockaddr *to, struct sctp_inpcb **inp_p, struct sctp_nets **netp, int find_tcp_pool, uint32_t vrf_id) { struct sctp_inpcb *inp = NULL; - struct sctp_tcb *retval; + struct sctp_tcb *stcb; SCTP_INP_INFO_RLOCK(); if (find_tcp_pool) { if (inp_p != NULL) { - retval = sctp_tcb_special_locate(inp_p, from, to, netp, + stcb = sctp_tcb_special_locate(inp_p, from, to, netp, vrf_id); } else { - retval = sctp_tcb_special_locate(&inp, from, to, netp, + stcb = sctp_tcb_special_locate(&inp, from, to, netp, vrf_id); } - if (retval != NULL) { + if (stcb != NULL) { SCTP_INP_INFO_RUNLOCK(); - return (retval); + return (stcb); } } inp = sctp_pcb_findep(to, 0, 1, vrf_id); @@ -1858,7 +1942,6 @@ sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from, *inp_p = inp; } SCTP_INP_INFO_RUNLOCK(); - if (inp == NULL) { return (NULL); } @@ -1869,13 +1952,13 @@ sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from, * inbound packet side. */ if (inp_p != NULL) { - retval = sctp_findassociation_ep_addr(inp_p, from, netp, to, + stcb = sctp_findassociation_ep_addr(inp_p, from, netp, to, NULL); } else { - retval = sctp_findassociation_ep_addr(&inp, from, netp, to, + stcb = sctp_findassociation_ep_addr(&inp, from, netp, to, NULL); } - return retval; + return (stcb); } @@ -1885,26 +1968,37 @@ sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from, * address will be used to lookup the TCB and see if one exits. */ static struct sctp_tcb * -sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, +sctp_findassociation_special_addr(struct mbuf *m, int offset, struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp, - struct sockaddr *dest) + struct sockaddr *dst) { - struct sockaddr_in sin4; - struct sockaddr_in6 sin6; struct sctp_paramhdr *phdr, parm_buf; - struct sctp_tcb *retval; + struct sctp_tcb *stcb; uint32_t ptype, plen; +#ifdef INET + struct sockaddr_in sin4; + +#endif +#ifdef INET6 + struct sockaddr_in6 sin6; + +#endif + +#ifdef INET memset(&sin4, 0, sizeof(sin4)); - memset(&sin6, 0, sizeof(sin6)); sin4.sin_len = sizeof(sin4); sin4.sin_family = AF_INET; sin4.sin_port = sh->src_port; +#endif +#ifdef INET6 + memset(&sin6, 0, sizeof(sin6)); sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; sin6.sin6_port = sh->src_port; +#endif - retval = NULL; + stcb = NULL; offset += sizeof(struct sctp_init_chunk); phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf)); @@ -1915,6 +2009,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, if (plen == 0) { break; } +#ifdef INET if (ptype == SCTP_IPV4_ADDRESS && plen == sizeof(struct sctp_ipv4addr_param)) { /* Get the rest of the address */ @@ -1928,12 +2023,15 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, p4 = (struct sctp_ipv4addr_param *)phdr; memcpy(&sin4.sin_addr, &p4->addr, sizeof(p4->addr)); /* look it up */ - retval = sctp_findassociation_ep_addr(inp_p, - (struct sockaddr *)&sin4, netp, dest, NULL); - if (retval != NULL) { - return (retval); + stcb = sctp_findassociation_ep_addr(inp_p, + (struct sockaddr *)&sin4, netp, dst, NULL); + if (stcb != NULL) { + return (stcb); } - } else if (ptype == SCTP_IPV6_ADDRESS && + } +#endif +#ifdef INET6 + if (ptype == SCTP_IPV6_ADDRESS && plen == sizeof(struct sctp_ipv6addr_param)) { /* Get the rest of the address */ struct sctp_ipv6addr_param ip6_parm, *p6; @@ -1946,12 +2044,13 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, p6 = (struct sctp_ipv6addr_param *)phdr; memcpy(&sin6.sin6_addr, &p6->addr, sizeof(p6->addr)); /* look it up */ - retval = sctp_findassociation_ep_addr(inp_p, - (struct sockaddr *)&sin6, netp, dest, NULL); - if (retval != NULL) { - return (retval); + stcb = sctp_findassociation_ep_addr(inp_p, + (struct sockaddr *)&sin6, netp, dst, NULL); + if (stcb != NULL) { + return (stcb); } } +#endif offset += SCTP_SIZE32(plen); phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf)); @@ -1973,8 +2072,6 @@ sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag struct sctp_nets *net; struct sctp_tcb *stcb; - *netp = NULL; - *inp_p = NULL; SCTP_INP_INFO_RLOCK(); head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(vtag, SCTP_BASE_INFO(hashasocmark))]; @@ -1989,6 +2086,10 @@ sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag SCTP_INP_RUNLOCK(stcb->sctp_ep); continue; } + if (stcb->sctp_ep->def_vrf_id != vrf_id) { + SCTP_INP_RUNLOCK(stcb->sctp_ep); + continue; + } SCTP_TCB_LOCK(stcb); SCTP_INP_RUNLOCK(stcb->sctp_ep); if (stcb->asoc.my_vtag == vtag) { @@ -2028,7 +2129,7 @@ sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag if (skip_src_check) { conclusive: if (from) { - net = sctp_findnet(stcb, from); + *netp = sctp_findnet(stcb, from); } else { *netp = NULL; /* unknown */ } @@ -2059,110 +2160,27 @@ sctp_findassoc_by_vtag(struct sockaddr *from, struct sockaddr *to, uint32_t vtag return (NULL); } + /* * Find an association with the pointer to the inbound IP packet. This can be * a IPv4 or IPv6 packet. */ struct sctp_tcb * -sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, +sctp_findassociation_addr(struct mbuf *m, int offset, + struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) { int find_tcp_pool; - struct ip *iph; - struct sctp_tcb *retval; - struct sockaddr_storage to_store, from_store; - struct sockaddr *to = (struct sockaddr *)&to_store; - struct sockaddr *from = (struct sockaddr *)&from_store; + struct sctp_tcb *stcb; struct sctp_inpcb *inp; - iph = mtod(m, struct ip *); - switch (iph->ip_v) { - case IPVERSION: - { - /* its IPv4 */ - 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: - { - /* its IPv6 */ - 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: - /* Currently not supported. */ - return (NULL); - } - - - switch (iph->ip_v) { - case IPVERSION: - { - /* its IPv4 */ - struct sockaddr_in *to4; - - to4 = (struct sockaddr_in *)&to_store; - bzero(to4, sizeof(*to4)); - to4->sin_family = AF_INET; - to4->sin_len = sizeof(struct sockaddr_in); - to4->sin_addr.s_addr = iph->ip_dst.s_addr; - to4->sin_port = sh->dest_port; - break; - } -#ifdef INET6 - case IPV6_VERSION >> 4: - { - /* its IPv6 */ - struct ip6_hdr *ip6; - struct sockaddr_in6 *to6; - - ip6 = mtod(m, struct ip6_hdr *); - to6 = (struct sockaddr_in6 *)&to_store; - bzero(to6, sizeof(*to6)); - to6->sin6_family = AF_INET6; - to6->sin6_len = sizeof(struct sockaddr_in6); - to6->sin6_addr = ip6->ip6_dst; - to6->sin6_port = sh->dest_port; - /* Get the scopes in properly to the sin6 addr's */ - /* we probably don't need these operations */ - (void)sa6_recoverscope(to6); - sa6_embedscope(to6, MODULE_GLOBAL(ip6_use_defzone)); - break; - } -#endif - default: - /* TSNH */ - break; - } if (sh->v_tag) { /* we only go down this path if vtag is non-zero */ - retval = sctp_findassoc_by_vtag(from, to, ntohl(sh->v_tag), + stcb = sctp_findassoc_by_vtag(src, dst, ntohl(sh->v_tag), inp_p, netp, sh->src_port, sh->dest_port, 0, vrf_id, 0); - if (retval) { - return (retval); + if (stcb) { + return (stcb); } } find_tcp_pool = 0; @@ -2174,15 +2192,15 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, find_tcp_pool = 1; } if (inp_p) { - retval = sctp_findassociation_addr_sa(to, from, inp_p, netp, + stcb = sctp_findassociation_addr_sa(src, dst, inp_p, netp, find_tcp_pool, vrf_id); inp = *inp_p; } else { - retval = sctp_findassociation_addr_sa(to, from, &inp, netp, + stcb = sctp_findassociation_addr_sa(src, dst, &inp, netp, find_tcp_pool, vrf_id); } - SCTPDBG(SCTP_DEBUG_PCB1, "retval:%p inp:%p\n", retval, inp); - if (retval == NULL && inp) { + SCTPDBG(SCTP_DEBUG_PCB1, "stcb:%p inp:%p\n", (void *)stcb, (void *)inp); + if (stcb == NULL && inp) { /* Found a EP but not this address */ if ((ch->chunk_type == SCTP_INITIATION) || (ch->chunk_type == SCTP_INITIATION_ACK)) { @@ -2200,15 +2218,15 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, } return (NULL); } - retval = sctp_findassociation_special_addr(m, iphlen, - offset, sh, &inp, netp, to); + stcb = sctp_findassociation_special_addr(m, + offset, sh, &inp, netp, dst); if (inp_p != NULL) { *inp_p = inp; } } } - SCTPDBG(SCTP_DEBUG_PCB1, "retval is %p\n", retval); - return (retval); + SCTPDBG(SCTP_DEBUG_PCB1, "stcb is %p\n", (void *)stcb); + return (stcb); } /* @@ -2216,58 +2234,26 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, * if the lookup address is 0.0.0.0 or ::0, use the vtag to do the lookup */ struct sctp_tcb * -sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset, - struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) +sctp_findassociation_ep_asconf(struct mbuf *m, int offset, + struct sockaddr *dst, struct sctphdr *sh, + struct sctp_inpcb **inp_p, struct sctp_nets **netp, uint32_t vrf_id) { struct sctp_tcb *stcb; - struct sockaddr_in *sin; - -#ifdef INET6 - struct sockaddr_in6 *sin6; - -#endif - struct sockaddr_storage local_store, remote_store; - struct sockaddr *to; - struct ip *iph; - -#ifdef INET6 - struct ip6_hdr *ip6; - -#endif + struct sockaddr_storage remote_store; struct sctp_paramhdr parm_buf, *phdr; int ptype; int zero_address = 0; +#ifdef INET + struct sockaddr_in *sin; - memset(&local_store, 0, sizeof(local_store)); - memset(&remote_store, 0, sizeof(remote_store)); - to = (struct sockaddr *)&local_store; - /* First get the destination address setup too. */ - iph = mtod(m, struct ip *); - switch (iph->ip_v) { - case IPVERSION: - /* its IPv4 */ - sin = (struct sockaddr_in *)&local_store; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_port = sh->dest_port; - sin->sin_addr.s_addr = iph->ip_dst.s_addr; - break; +#endif #ifdef INET6 - case IPV6_VERSION >> 4: - /* its IPv6 */ - ip6 = mtod(m, struct ip6_hdr *); - sin6 = (struct sockaddr_in6 *)&local_store; - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_port = sh->dest_port; - sin6->sin6_addr = ip6->ip6_dst; - break; + struct sockaddr_in6 *sin6; + #endif - default: - return NULL; - } + memset(&remote_store, 0, sizeof(remote_store)); phdr = sctp_get_next_param(m, offset + sizeof(struct sctp_asconf_chunk), &parm_buf, sizeof(struct sctp_paramhdr)); if (phdr == NULL) { @@ -2305,6 +2291,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset, break; } #endif +#ifdef INET case SCTP_IPV4_ADDRESS: { /* ipv4 address param */ @@ -2330,22 +2317,22 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int iphlen, int offset, zero_address = 1; break; } +#endif default: /* invalid address param type */ return NULL; } if (zero_address) { - stcb = sctp_findassoc_by_vtag(NULL, to, ntohl(sh->v_tag), inp_p, + stcb = sctp_findassoc_by_vtag(NULL, dst, ntohl(sh->v_tag), inp_p, netp, sh->src_port, sh->dest_port, 1, vrf_id, 0); - /* - * printf("findassociation_ep_asconf: zero lookup address - * finds stcb 0x%x\n", (uint32_t)stcb); - */ + if (stcb != NULL) { + SCTP_INP_DECR_REF(*inp_p); + } } else { stcb = sctp_findassociation_ep_addr(inp_p, (struct sockaddr *)&remote_store, netp, - to, NULL); + dst, NULL); } return (stcb); } @@ -2390,10 +2377,16 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) /* setup socket pointers */ inp->sctp_socket = so; inp->ip_inp.inp.inp_socket = so; +#ifdef INET6 + if (MODULE_GLOBAL(ip6_auto_flowlabel)) { + inp->ip_inp.inp.inp_flags |= IN6P_AUTOFLOWLABEL; + } +#endif inp->sctp_associd_counter = 1; inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); + inp->sctp_ecn_enable = SCTP_BASE_SYSCTL(sctp_ecn_enable); /* init the small hash table we use to track asocid <-> tcb */ inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark); if (inp->sctp_asocidhash == NULL) { @@ -2422,8 +2415,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) so->so_pcb = (caddr_t)inp; - if ((SCTP_SO_TYPE(so) == SOCK_DGRAM) || - (SCTP_SO_TYPE(so) == SOCK_SEQPACKET)) { + if (SCTP_SO_TYPE(so) == SOCK_SEQPACKET) { /* UDP style socket */ inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE | SCTP_PCB_FLAGS_UNBOUND); @@ -2514,21 +2506,20 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) m->max_init_times = SCTP_BASE_SYSCTL(sctp_init_rtx_max_default); m->max_send_times = SCTP_BASE_SYSCTL(sctp_assoc_rtx_max_default); m->def_net_failure = SCTP_BASE_SYSCTL(sctp_path_rtx_max_default); + m->def_net_pf_threshold = SCTP_BASE_SYSCTL(sctp_path_pf_threshold); m->sctp_sws_sender = SCTP_SWS_SENDER_DEF; m->sctp_sws_receiver = SCTP_SWS_RECEIVER_DEF; m->max_burst = SCTP_BASE_SYSCTL(sctp_max_burst_default); - if ((SCTP_BASE_SYSCTL(sctp_default_cc_module) >= SCTP_CC_RFC2581) && - (SCTP_BASE_SYSCTL(sctp_default_cc_module) <= SCTP_CC_HTCP)) { - m->sctp_default_cc_module = SCTP_BASE_SYSCTL(sctp_default_cc_module); - } else { - /* sysctl done with invalid value, set to 2581 */ - m->sctp_default_cc_module = SCTP_CC_RFC2581; - } + m->fr_max_burst = SCTP_BASE_SYSCTL(sctp_fr_max_burst_default); + + m->sctp_default_cc_module = SCTP_BASE_SYSCTL(sctp_default_cc_module); + m->sctp_default_ss_module = SCTP_BASE_SYSCTL(sctp_default_ss_module); /* number of streams to pre-open on a association */ m->pre_open_stream_count = SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default); /* Add adaptation cookie */ - m->adaptation_layer_indicator = 0x504C5253; + m->adaptation_layer_indicator = 0; + m->adaptation_layer_indicator_provided = 0; /* seed random number generator */ m->random_counter = 1; @@ -2557,6 +2548,11 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) */ m->local_hmacs = sctp_default_supported_hmaclist(); m->local_auth_chunks = sctp_alloc_chunklist(); + m->default_dscp = 0; +#ifdef INET6 + m->default_flowlabel = 0; +#endif + m->port = 0; /* encapsulation disabled by default */ sctp_auth_set_default_chunks(m->local_auth_chunks); LIST_INIT(&m->shared_keys); /* add default NULL key as key id 0 */ @@ -2663,6 +2659,9 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, LIST_INSERT_HEAD(&new_inp->sctp_addr_list, laddr, sctp_nxt_addr); new_inp->laddr_count++; + if (oladdr == stcb->asoc.last_used_address) { + stcb->asoc.last_used_address = laddr; + } } } /* @@ -2671,7 +2670,6 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, * all of them. */ - stcb->asoc.hb_timer.ep = (void *)new_inp; stcb->asoc.dack_timer.ep = (void *)new_inp; stcb->asoc.asconf_timer.ep = (void *)new_inp; stcb->asoc.strreset_timer.ep = (void *)new_inp; @@ -2682,8 +2680,8 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, /* now what about the nets? */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { net->pmtu_timer.ep = (void *)new_inp; + net->hb_timer.ep = (void *)new_inp; net->rxt_timer.ep = (void *)new_inp; - net->fr_timer.ep = (void *)new_inp; } SCTP_INP_WUNLOCK(new_inp); SCTP_INP_WUNLOCK(old_inp); @@ -2714,9 +2712,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, ip_inp = (struct inpcb *)so->so_pcb; #ifdef SCTP_DEBUG if (addr) { - SCTPDBG(SCTP_DEBUG_PCB1, "Bind called port:%d\n", + SCTPDBG(SCTP_DEBUG_PCB1, "Bind called port: %d\n", ntohs(((struct sockaddr_in *)addr)->sin_port)); - SCTPDBG(SCTP_DEBUG_PCB1, "Addr :"); + SCTPDBG(SCTP_DEBUG_PCB1, "Addr: "); SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr); } #endif @@ -2731,6 +2729,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, #endif if (addr != NULL) { switch (addr->sa_family) { +#ifdef INET case AF_INET: { struct sockaddr_in *sin; @@ -2760,6 +2759,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, } break; } +#endif #ifdef INET6 case AF_INET6: { @@ -2776,7 +2776,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, return (EINVAL); } lport = sin6->sin6_port; - /* * For LOOPBACK the prison_local_ip6() call * will transmute the ipv6 address to the @@ -2814,7 +2813,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_INCR_REF(inp); if (lport) { /* - * Did the caller specify a port? if so we must see if a ep + * Did the caller specify a port? if so we must see if an ep * already has this one bound. */ /* got to be root to get at low ports */ @@ -2895,8 +2894,7 @@ continue_anyway: if (bindall) { /* verify that no lport is not used by a singleton */ if ((port_reuse_active == 0) && - (inp_tmp = sctp_isport_inuse(inp, lport, vrf_id)) - ) { + (inp_tmp = sctp_isport_inuse(inp, lport, vrf_id))) { /* Sorry someone already has this one bound */ if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && (sctp_is_feature_on(inp_tmp, SCTP_PCB_FLAGS_PORTREUSE))) { @@ -3031,27 +3029,40 @@ continue_anyway: struct sockaddr_storage store_sa; memset(&store_sa, 0, sizeof(store_sa)); - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; + switch (addr->sa_family) { +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin; - sin = (struct sockaddr_in *)&store_sa; - memcpy(sin, addr, sizeof(struct sockaddr_in)); - sin->sin_port = 0; - } else if (addr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; + sin = (struct sockaddr_in *)&store_sa; + memcpy(sin, addr, sizeof(struct sockaddr_in)); + sin->sin_port = 0; + break; + } +#endif +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)&store_sa; - memcpy(sin6, addr, sizeof(struct sockaddr_in6)); - sin6->sin6_port = 0; + sin6 = (struct sockaddr_in6 *)&store_sa; + memcpy(sin6, addr, sizeof(struct sockaddr_in6)); + sin6->sin6_port = 0; + break; + } +#endif + default: + break; } /* * first find the interface with the bound address need to * zero out the port to find the address! yuck! can't do * this earlier since need port for sctp_pcb_findep() */ - if (sctp_ifap != NULL) + if (sctp_ifap != NULL) { ifa = sctp_ifap; - else { + } else { /* * Note for BSD we hit here always other O/S's will * pass things in via the sctp_ifap argument @@ -3067,6 +3078,7 @@ continue_anyway: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRNOTAVAIL); return (EADDRNOTAVAIL); } +#ifdef INET6 if (addr->sa_family == AF_INET6) { /* GAK, more FIXME IFA lock? */ if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { @@ -3077,6 +3089,7 @@ continue_anyway: return (EINVAL); } } +#endif /* we're not bound all */ inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL; /* allow bindx() to send ASCONF's for binding changes */ @@ -3104,7 +3117,7 @@ continue_anyway: /* put it in the bucket */ LIST_INSERT_HEAD(head, inp, sctp_hash); SCTPDBG(SCTP_DEBUG_PCB1, "Main hash to bind at head:%p, bound port:%d - in tcp_pool=%d\n", - head, ntohs(lport), port_reuse_active); + (void *)head, ntohs(lport), port_reuse_active); /* set in the port */ inp->sctp_lport = lport; @@ -3155,11 +3168,8 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp) * may be still pending on the list */ SCTP_IPI_ITERATOR_WQ_LOCK(); - it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead); - while (it) { - nit = TAILQ_NEXT(it, sctp_nxt_itr); + TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { if (it->vn != curvnet) { - it = nit; continue; } if (it->inp == inp) { @@ -3184,7 +3194,6 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp) */ SCTP_INP_DECR_REF(inp); } - it = nit; } SCTP_IPI_ITERATOR_WQ_UNLOCK(); } @@ -3201,17 +3210,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * freeing. a) Any local lists. b) Any associations. c) The hash of * all associations. d) finally the ep itself. */ - struct sctp_pcb *m; struct sctp_tcb *asoc, *nasoc; struct sctp_laddr *laddr, *nladdr; struct inpcb *ip_pcb; struct socket *so; int being_refed = 0; - struct sctp_queued_to_read *sq; - - + struct sctp_queued_to_read *sq, *nsq; int cnt; - sctp_sharedkey_t *shared_key; + sctp_sharedkey_t *shared_key, *nshared_key; #ifdef SCTP_LOG_CLOSING @@ -3254,7 +3260,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) sctp_m_freem(inp->pkt); inp->pkt = NULL; } - m = &inp->sctp_ep; ip_pcb = &inp->ip_inp.inp; /* we could just cast the main pointer * here but I will be nice :> (i.e. * ip_pcb = ep;) */ @@ -3262,10 +3267,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) int cnt_in_sd; cnt_in_sd = 0; - for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL; - asoc = nasoc) { + LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) { SCTP_TCB_LOCK(asoc); - nasoc = LIST_NEXT(asoc, sctp_tcblist); if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { /* Skip guys being freed */ cnt_in_sd++; @@ -3304,32 +3307,22 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) if ((asoc->asoc.size_on_reasm_queue > 0) || (asoc->asoc.control_pdapi) || (asoc->asoc.size_on_all_streams > 0) || - (so && (so->so_rcv.sb_cc > 0)) - ) { + (so && (so->so_rcv.sb_cc > 0))) { /* Left with Data unread */ struct mbuf *op_err; - op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), + op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); if (op_err) { /* Fill in the user initiated abort */ struct sctp_paramhdr *ph; - uint32_t *ippp; - - SCTP_BUF_LEN(op_err) = - sizeof(struct sctp_paramhdr) + sizeof(uint32_t); - ph = mtod(op_err, - struct sctp_paramhdr *); - ph->param_type = htons( - SCTP_CAUSE_USER_INITIATED_ABT); + + SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); + ph = mtod(op_err, struct sctp_paramhdr *); + ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(SCTP_BUF_LEN(op_err)); - ippp = (uint32_t *) (ph + 1); - *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_3); } asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3; -#if defined(SCTP_PANIC_ON_ABORT) - panic("inpcb_free does an abort"); -#endif sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || @@ -3343,26 +3336,33 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) continue; } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && - (asoc->asoc.stream_queue_cnt == 0) - ) { + (asoc->asoc.stream_queue_cnt == 0)) { if (asoc->asoc.locked_on_sending) { goto abort_anyway; } if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { + struct sctp_nets *netp; + /* * there is nothing queued to send, * so I send shutdown */ - sctp_send_shutdown(asoc, asoc->asoc.primary_destination); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_PENDING); + sctp_stop_timers_for_shutdown(asoc); + if (asoc->asoc.alternate) { + netp = asoc->asoc.alternate; + } else { + netp = asoc->asoc.primary_destination; + } + sctp_send_shutdown(asoc, netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc, - asoc->asoc.primary_destination); + netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, asoc->asoc.primary_destination); sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED); @@ -3379,7 +3379,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) sctp_streamhead); if (sp == NULL) { SCTP_PRINTF("Error, sp is NULL, locked on sending is %p strm:%d\n", - asoc->asoc.locked_on_sending, + (void *)asoc->asoc.locked_on_sending, asoc->asoc.locked_on_sending->stream_no); } else { if ((sp->length == 0) && (sp->msg_is_complete == 0)) @@ -3392,7 +3392,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) struct mbuf *op_err; abort_anyway: - op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), + op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); if (op_err) { /* @@ -3400,24 +3400,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * initiated abort */ struct sctp_paramhdr *ph; - uint32_t *ippp; - - SCTP_BUF_LEN(op_err) = - (sizeof(struct sctp_paramhdr) + - sizeof(uint32_t)); - ph = mtod(op_err, - struct sctp_paramhdr *); - ph->param_type = htons( - SCTP_CAUSE_USER_INITIATED_ABT); + + SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); + ph = mtod(op_err, struct sctp_paramhdr *); + ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(SCTP_BUF_LEN(op_err)); - ippp = (uint32_t *) (ph + 1); - *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_5); } asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5; -#if defined(SCTP_PANIC_ON_ABORT) - panic("inpcb_free does an abort"); -#endif - sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) || @@ -3464,10 +3453,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * have a contest on the INP lock.. which would cause us to die ... */ cnt = 0; - for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL; - asoc = nasoc) { + LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_list, sctp_tcblist, nasoc) { SCTP_TCB_LOCK(asoc); - nasoc = LIST_NEXT(asoc, sctp_tcblist); if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { asoc->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; @@ -3481,28 +3468,19 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_COOKIE_WAIT) && ((asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) { struct mbuf *op_err; - uint32_t *ippp; - op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), + op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); if (op_err) { /* Fill in the user initiated abort */ struct sctp_paramhdr *ph; - SCTP_BUF_LEN(op_err) = (sizeof(struct sctp_paramhdr) + - sizeof(uint32_t)); + SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); ph = mtod(op_err, struct sctp_paramhdr *); - ph->param_type = htons( - SCTP_CAUSE_USER_INITIATED_ABT); + ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(SCTP_BUF_LEN(op_err)); - ippp = (uint32_t *) (ph + 1); - *ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_7); - } asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7; -#if defined(SCTP_PANIC_ON_ABORT) - panic("inpcb_free does an abort"); -#endif sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); } else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { @@ -3584,7 +3562,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) inp->sctp_asocidhash = NULL; } /* sa_ignore FREED_MEMORY */ - while ((sq = TAILQ_FIRST(&inp->read_queue)) != NULL) { + TAILQ_FOREACH_SAFE(sq, &inp->read_queue, next, nsq) { /* Its only abandoned if it had data left */ if (sq->length) SCTP_STAT_INCR(sctps_left_abandon); @@ -3610,7 +3588,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * macro here since le_next will get freed as part of the * sctp_free_assoc() call. */ - cnt = 0; if (so) { #ifdef IPSEC ipsec_delete_pcbpolicy(ip_pcb); @@ -3622,10 +3599,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (void)sctp_m_free(ip_pcb->inp_options); ip_pcb->inp_options = 0; } - if (ip_pcb->inp_moptions) { - inp_freemoptions(ip_pcb->inp_moptions); - ip_pcb->inp_moptions = 0; - } #ifdef INET6 if (ip_pcb->inp_vflag & INP_IPV6) { struct in6pcb *in6p; @@ -3641,12 +3614,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) if (inp->sctp_ep.local_hmacs != NULL) sctp_free_hmaclist(inp->sctp_ep.local_hmacs); - shared_key = LIST_FIRST(&inp->sctp_ep.shared_keys); - while (shared_key) { + LIST_FOREACH_SAFE(shared_key, &inp->sctp_ep.shared_keys, next, nshared_key) { LIST_REMOVE(shared_key, next); sctp_free_sharedkey(shared_key); /* sa_ignore FREED_MEMORY */ - shared_key = LIST_FIRST(&inp->sctp_ep.shared_keys); } /* @@ -3654,17 +3625,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * ifaddr's that are set into this ep. Again macro limitations here, * since the LIST_FOREACH could be a bad idea. */ - for ((laddr = LIST_FIRST(&inp->sctp_addr_list)); laddr != NULL; - laddr = nladdr) { - nladdr = LIST_NEXT(laddr, sctp_nxt_addr); + LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) { sctp_remove_laddr(laddr); } #ifdef SCTP_TRACK_FREED_ASOCS /* TEMP CODE */ - for ((asoc = LIST_FIRST(&inp->sctp_asoc_free_list)); asoc != NULL; - asoc = nasoc) { - nasoc = LIST_NEXT(asoc, sctp_tcblist); + LIST_FOREACH_SAFE(asoc, &inp->sctp_asoc_free_list, sctp_tcblist, nasoc) { LIST_REMOVE(asoc, sctp_tcblist); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), asoc); SCTP_DECR_ASOC_COUNT(); @@ -3720,7 +3687,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id) */ int sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, - int set_scope, int from) + struct sctp_nets **netp, int set_scope, int from) { /* * The following is redundant to the same lines in the @@ -3756,84 +3723,96 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, return (0); } addr_inscope = 1; - if (newaddr->sa_family == AF_INET) { - struct sockaddr_in *sin; + switch (newaddr->sa_family) { +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin; - sin = (struct sockaddr_in *)newaddr; - if (sin->sin_addr.s_addr == 0) { - /* Invalid address */ - return (-1); - } - /* zero out the bzero area */ - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); + sin = (struct sockaddr_in *)newaddr; + if (sin->sin_addr.s_addr == 0) { + /* Invalid address */ + return (-1); + } + /* zero out the bzero area */ + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - /* assure len is set */ - sin->sin_len = sizeof(struct sockaddr_in); - if (set_scope) { + /* assure len is set */ + sin->sin_len = sizeof(struct sockaddr_in); + if (set_scope) { #ifdef SCTP_DONT_DO_PRIVADDR_SCOPE - stcb->ipv4_local_scope = 1; + stcb->ipv4_local_scope = 1; #else - if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { - stcb->asoc.ipv4_local_scope = 1; - } + if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { + stcb->asoc.scope.ipv4_local_scope = 1; + } #endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */ - } else { - /* Validate the address is in scope */ - if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) && - (stcb->asoc.ipv4_local_scope == 0)) { - addr_inscope = 0; + } else { + /* Validate the address is in scope */ + if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) && + (stcb->asoc.scope.ipv4_local_scope == 0)) { + addr_inscope = 0; + } } + break; } +#endif #ifdef INET6 - } else if (newaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; + case AF_INET6: + { + struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)newaddr; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* Invalid address */ - return (-1); - } - /* assure len is set */ - sin6->sin6_len = sizeof(struct sockaddr_in6); - if (set_scope) { - if (sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id)) { - stcb->asoc.loopback_scope = 1; - stcb->asoc.local_scope = 0; - stcb->asoc.ipv4_local_scope = 1; - stcb->asoc.site_scope = 1; - } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - /* - * If the new destination is a LINK_LOCAL we - * must have common site scope. Don't set - * the local scope since we may not share - * all links, only loopback can do this. - * Links on the local network would also be - * on our private network for v4 too. - */ - stcb->asoc.ipv4_local_scope = 1; - stcb->asoc.site_scope = 1; - } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { - /* - * If the new destination is SITE_LOCAL then - * we must have site scope in common. - */ - stcb->asoc.site_scope = 1; + sin6 = (struct sockaddr_in6 *)newaddr; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + /* Invalid address */ + return (-1); } - } else { - /* Validate the address is in scope */ - if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && - (stcb->asoc.loopback_scope == 0)) { - addr_inscope = 0; - } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && - (stcb->asoc.local_scope == 0)) { - addr_inscope = 0; - } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && - (stcb->asoc.site_scope == 0)) { - addr_inscope = 0; + /* assure len is set */ + sin6->sin6_len = sizeof(struct sockaddr_in6); + if (set_scope) { + if (sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id)) { + stcb->asoc.scope.loopback_scope = 1; + stcb->asoc.scope.local_scope = 0; + stcb->asoc.scope.ipv4_local_scope = 1; + stcb->asoc.scope.site_scope = 1; + } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + /* + * If the new destination is a + * LINK_LOCAL we must have common + * site scope. Don't set the local + * scope since we may not share all + * links, only loopback can do this. + * Links on the local network would + * also be on our private network + * for v4 too. + */ + stcb->asoc.scope.ipv4_local_scope = 1; + stcb->asoc.scope.site_scope = 1; + } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { + /* + * If the new destination is + * SITE_LOCAL then we must have site + * scope in common. + */ + stcb->asoc.scope.site_scope = 1; + } + } else { + /* Validate the address is in scope */ + if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && + (stcb->asoc.scope.loopback_scope == 0)) { + addr_inscope = 0; + } else if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && + (stcb->asoc.scope.local_scope == 0)) { + addr_inscope = 0; + } else if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && + (stcb->asoc.scope.site_scope == 0)) { + addr_inscope = 0; + } } + break; } #endif - } else { + default: /* not supported family type */ return (-1); } @@ -3842,23 +3821,33 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, return (-1); } SCTP_INCR_RADDR_COUNT(); - bzero(net, sizeof(*net)); + bzero(net, sizeof(struct sctp_nets)); (void)SCTP_GETTIME_TIMEVAL(&net->start_time); memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len); - if (newaddr->sa_family == AF_INET) { + switch (newaddr->sa_family) { +#ifdef INET + case AF_INET: ((struct sockaddr_in *)&net->ro._l_addr)->sin_port = stcb->rport; - } else if (newaddr->sa_family == AF_INET6) { + break; +#endif +#ifdef INET6 + case AF_INET6: ((struct sockaddr_in6 *)&net->ro._l_addr)->sin6_port = stcb->rport; + break; +#endif + default: + break; } net->addr_is_local = sctp_is_address_on_local_host(newaddr, stcb->asoc.vrf_id); if (net->addr_is_local && ((set_scope || (from == SCTP_ADDR_IS_CONFIRMED)))) { - stcb->asoc.loopback_scope = 1; - stcb->asoc.ipv4_local_scope = 1; - stcb->asoc.local_scope = 0; - stcb->asoc.site_scope = 1; + stcb->asoc.scope.loopback_scope = 1; + stcb->asoc.scope.ipv4_local_scope = 1; + stcb->asoc.scope.local_scope = 0; + stcb->asoc.scope.site_scope = 1; addr_inscope = 1; } net->failure_threshold = stcb->asoc.def_net_failure; + net->pf_threshold = stcb->asoc.def_net_pf_threshold; if (addr_inscope == 0) { net->dest_state = (SCTP_ADDR_REACHABLE | SCTP_ADDR_OUT_OF_SCOPE); @@ -3874,28 +3863,32 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, * We set this to 0, the timer code knows that this means its an * initial value */ + net->rto_needed = 1; net->RTO = 0; net->RTO_measured = 0; stcb->asoc.numnets++; - *(&net->ref_count) = 1; - net->tos_flowlabel = 0; - if (SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable)) { - net->port = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); - } else { - net->port = 0; - } -#ifdef INET - if (newaddr->sa_family == AF_INET) - net->tos_flowlabel = stcb->asoc.default_tos; -#endif + net->ref_count = 1; + net->cwr_window_tsn = net->last_cwr_tsn = stcb->asoc.sending_seq - 1; + net->port = stcb->asoc.port; + net->dscp = stcb->asoc.default_dscp; #ifdef INET6 - if (newaddr->sa_family == AF_INET6) - net->tos_flowlabel = stcb->asoc.default_flowlabel; + net->flowlabel = stcb->asoc.default_flowlabel; #endif + if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { + net->dest_state |= SCTP_ADDR_NOHB; + } else { + net->dest_state &= ~SCTP_ADDR_NOHB; + } + if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { + net->dest_state |= SCTP_ADDR_NO_PMTUD; + } else { + net->dest_state &= ~SCTP_ADDR_NO_PMTUD; + } + net->heart_beat_delay = stcb->asoc.heart_beat_delay; /* Init the timer structure */ SCTP_OS_TIMER_INIT(&net->rxt_timer.timer); - SCTP_OS_TIMER_INIT(&net->fr_timer.timer); SCTP_OS_TIMER_INIT(&net->pmtu_timer.timer); + SCTP_OS_TIMER_INIT(&net->hb_timer.timer); /* Now generate a route for this guy */ #ifdef INET6 @@ -3921,13 +3914,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, /* Now get the interface MTU */ if (net->ro._s_addr && net->ro._s_addr->ifn_p) { net->mtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p); - } else { - net->mtu = 0; } - if (net->mtu == 0) { - /* Huh ?? */ - net->mtu = SCTP_DEFAULT_MTU; - } else { + if (net->mtu > 0) { uint32_t rmtu; rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt); @@ -3947,11 +3935,31 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->mtu = rmtu; } } - if (from == SCTP_ALLOC_ASOC) { - stcb->asoc.smallest_mtu = net->mtu; + } + if (net->mtu == 0) { + switch (newaddr->sa_family) { +#ifdef INET + case AF_INET: + net->mtu = SCTP_DEFAULT_MTU; + break; +#endif +#ifdef INET6 + case AF_INET6: + net->mtu = 1280; + break; +#endif + default: + break; } - } else { - net->mtu = stcb->asoc.smallest_mtu; + } + if (net->port) { + net->mtu -= (uint32_t) sizeof(struct udphdr); + } + if (from == SCTP_ALLOC_ASOC) { + stcb->asoc.smallest_mtu = net->mtu; + } + if (stcb->asoc.smallest_mtu > net->mtu) { + stcb->asoc.smallest_mtu = net->mtu; } #ifdef INET6 if (newaddr->sa_family == AF_INET6) { @@ -3961,14 +3969,10 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, (void)sa6_recoverscope(sin6); } #endif - if (net->port) { - net->mtu -= sizeof(struct udphdr); - } - if (stcb->asoc.smallest_mtu > net->mtu) { - stcb->asoc.smallest_mtu = net->mtu; - } + /* JRS - Use the congestion control given in the CC module */ - stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); + if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) + (*stcb->asoc.cc_functions.sctp_set_initial_cc_param) (stcb, net); /* * CMT: CUC algo - set find_pseudo_cumack to TRUE (1) at beginning @@ -3977,6 +3981,16 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->find_pseudo_cumack = 1; net->find_rtx_pseudo_cumack = 1; net->src_addr_selected = 0; + /* Choose an initial flowid. */ + net->flowid = stcb->asoc.my_vtag ^ + ntohs(stcb->rport) ^ + ntohs(stcb->sctp_ep->sctp_lport); +#ifdef INVARIANTS + net->flowidset = 1; +#endif + if (netp) { + *netp = net; + } netfirst = TAILQ_FIRST(&stcb->asoc.nets); if (net->ro.ro_rt == NULL) { /* Since we have no route put it at the back */ @@ -4034,8 +4048,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, /* No route to current primary adopt new primary */ stcb->asoc.primary_destination = net; } - sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, - net); /* Validate primary is first */ net = TAILQ_FIRST(&stcb->asoc.nets); if ((net != stcb->asoc.primary_destination) && @@ -4069,11 +4081,11 @@ try_again: return (0); } /* - * We don't allow assoc id to be 0, this is needed otherwise if the - * id were to wrap we would have issues with some socket options. + * We don't allow assoc id to be one of SCTP_FUTURE_ASSOC, + * SCTP_CURRENT_ASSOC and SCTP_ALL_ASSOC. */ - if (inp->sctp_associd_counter == 0) { - inp->sctp_associd_counter++; + if (inp->sctp_associd_counter <= SCTP_ALL_ASSOC) { + inp->sctp_associd_counter = SCTP_ALL_ASSOC + 1; } id = inp->sctp_associd_counter; inp->sctp_associd_counter++; @@ -4138,42 +4150,81 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, *error = EINVAL; return (NULL); } + if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || + (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { + SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + *error = EINVAL; + return (NULL); + } + } SCTPDBG(SCTP_DEBUG_PCB3, "Allocate an association for peer:"); #ifdef SCTP_DEBUG if (firstaddr) { SCTPDBG_ADDR(SCTP_DEBUG_PCB3, firstaddr); - SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", - ntohs(((struct sockaddr_in *)firstaddr)->sin_port)); + switch (firstaddr->sa_family) { +#ifdef INET + case AF_INET: + SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", + ntohs(((struct sockaddr_in *)firstaddr)->sin_port)); + break; +#endif +#ifdef INET6 + case AF_INET6: + SCTPDBG(SCTP_DEBUG_PCB3, "Port:%d\n", + ntohs(((struct sockaddr_in6 *)firstaddr)->sin6_port)); + break; +#endif + default: + break; + } } else { SCTPDBG(SCTP_DEBUG_PCB3, "None\n"); } #endif /* SCTP_DEBUG */ - if (firstaddr->sa_family == AF_INET) { - struct sockaddr_in *sin; + switch (firstaddr->sa_family) { +#ifdef INET + case AF_INET: + { + struct sockaddr_in *sin; - sin = (struct sockaddr_in *)firstaddr; - if ((sin->sin_port == 0) || (sin->sin_addr.s_addr == 0)) { - /* Invalid address */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); + sin = (struct sockaddr_in *)firstaddr; + if ((ntohs(sin->sin_port) == 0) || + (sin->sin_addr.s_addr == INADDR_ANY) || + (sin->sin_addr.s_addr == INADDR_BROADCAST) || + IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { + /* Invalid address */ + SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + *error = EINVAL; + return (NULL); + } + rport = sin->sin_port; + break; } - rport = sin->sin_port; - } else if (firstaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; +#endif +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)firstaddr; - if ((sin6->sin6_port == 0) || - (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) { - /* Invalid address */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); - *error = EINVAL; - return (NULL); + sin6 = (struct sockaddr_in6 *)firstaddr; + if ((ntohs(sin6->sin6_port) == 0) || + IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + /* Invalid address */ + SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); + *error = EINVAL; + return (NULL); + } + rport = sin6->sin6_port; + break; } - rport = sin6->sin6_port; - } else { +#endif + default: /* not supported family type */ SCTP_INP_RUNLOCK(inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); @@ -4249,7 +4300,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, LIST_INSERT_HEAD(head, stcb, sctp_asocs); SCTP_INP_INFO_WUNLOCK(); - if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { + if ((err = sctp_add_remote_addr(stcb, firstaddr, NULL, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { /* failure.. memory error? */ if (asoc->strmout) { SCTP_FREE(asoc->strmout, SCTP_M_STRMO); @@ -4274,7 +4325,6 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, return (NULL); } /* Init all the timers */ - SCTP_OS_TIMER_INIT(&asoc->hb_timer.timer); SCTP_OS_TIMER_INIT(&asoc->dack_timer.timer); SCTP_OS_TIMER_INIT(&asoc->strreset_timer.timer); SCTP_OS_TIMER_INIT(&asoc->asconf_timer.timer); @@ -4291,7 +4341,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, LIST_INSERT_HEAD(head, stcb, sctp_tcbhash); } SCTP_INP_WUNLOCK(inp); - SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", stcb); + SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", (void *)stcb); return (stcb); } @@ -4344,6 +4394,10 @@ out: /* Clear net */ asoc->last_control_chunk_from = NULL; } + if (net == stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } sctp_free_remote_addr(net); } @@ -4362,13 +4416,12 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr) * no other addresses. */ struct sctp_association *asoc; - struct sctp_nets *net, *net_tmp; + struct sctp_nets *net, *nnet; asoc = &stcb->asoc; /* locate the address */ - for (net = TAILQ_FIRST(&asoc->nets); net != NULL; net = net_tmp) { - net_tmp = TAILQ_NEXT(net, sctp_next); + TAILQ_FOREACH_SAFE(net, &asoc->nets, sctp_next, nnet) { if (net->ro._l_addr.sa.sa_family != remaddr->sa_family) { continue; } @@ -4533,18 +4586,16 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre { int i; struct sctp_association *asoc; - struct sctp_nets *net, *prev; - struct sctp_laddr *laddr; - struct sctp_tmit_chunk *chk; - struct sctp_asconf_addr *aparam; - struct sctp_asconf_ack *aack; - struct sctp_stream_reset_list *liste; - struct sctp_queued_to_read *sq; - struct sctp_stream_queue_pending *sp; - sctp_sharedkey_t *shared_key; + struct sctp_nets *net, *nnet; + struct sctp_laddr *laddr, *naddr; + struct sctp_tmit_chunk *chk, *nchk; + struct sctp_asconf_addr *aparam, *naparam; + struct sctp_asconf_ack *aack, *naack; + struct sctp_stream_reset_list *strrst, *nstrrst; + struct sctp_queued_to_read *sq, *nsq; + struct sctp_stream_queue_pending *sp, *nsp; + sctp_sharedkey_t *shared_key, *nshared_key; struct socket *so; - int ccnt = 0; - int cnt = 0; /* first, lets purge the entry from the hash table. */ @@ -4558,6 +4609,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* there is no asoc, really TSNH :-0 */ return (1); } + if (stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } /* TEMP CODE */ if (stcb->freed_from_where == 0) { /* Only record the first place free happened from */ @@ -4596,8 +4651,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } } /* now clean up any other timers */ - (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer); - asoc->hb_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); asoc->dack_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); @@ -4621,15 +4674,14 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer); asoc->delete_prim_timer.self = NULL; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); - net->fr_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer); net->rxt_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); net->pmtu_timer.self = NULL; + (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); + net->hb_timer.self = NULL; } /* Now the read queue needs to be cleaned up (only once) */ - cnt = 0; if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED; SCTP_INP_READ_LOCK(inp); @@ -4645,7 +4697,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Held for PD-API clear that. */ sq->pdapi_aborted = 1; sq->held_length = 0; - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) { + if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) { /* * Need to add a PD-API * aborted indication. @@ -4668,12 +4720,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* Add an end to wake them */ sq->end_added = 1; - cnt++; } } SCTP_INP_READ_UNLOCK(inp); if (stcb->block_entry) { - cnt++; SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PCB, ECONNRESET); stcb->block_entry->error = ECONNRESET; stcb->block_entry = NULL; @@ -4797,7 +4847,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre * Now restop the timers to be sure this is paranoia at is finest! */ (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); - (void)SCTP_OS_TIMER_STOP(&asoc->hb_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); @@ -4805,13 +4854,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->rxt_timer.timer); (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); + (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); } asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE; - prev = NULL; /* * The chunk lists and such SHOULD be empty but we check them just * in case. @@ -4822,45 +4870,35 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre outs = &asoc->strmout[i]; /* now clean up any chunks here */ - sp = TAILQ_FIRST(&outs->outqueue); - while (sp) { + TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { TAILQ_REMOVE(&outs->outqueue, sp, next); + sctp_free_spbufspace(stcb, asoc, sp); if (sp->data) { if (so) { /* Still an open socket - report */ sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, - SCTP_NOTIFY_DATAGRAM_UNSENT, - (void *)sp, SCTP_SO_LOCKED); + 0, (void *)sp, SCTP_SO_LOCKED); } if (sp->data) { sctp_m_freem(sp->data); sp->data = NULL; sp->tail_mbuf = NULL; + sp->length = 0; } } if (sp->net) { sctp_free_remote_addr(sp->net); sp->net = NULL; } - sctp_free_spbufspace(stcb, asoc, sp); - if (sp->holds_key_ref) - sctp_auth_key_release(stcb, sp->auth_keyid); - /* Free the zone stuff */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_strmoq), sp); - SCTP_DECR_STRMOQ_COUNT(); - /* sa_ignore FREED_MEMORY */ - sp = TAILQ_FIRST(&outs->outqueue); + sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); } } - /* sa_ignore FREED_MEMORY */ - while ((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) { - TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); - SCTP_FREE(liste, SCTP_M_STRESET); + TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) { + TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp); + SCTP_FREE(strrst, SCTP_M_STRESET); } - - sq = TAILQ_FIRST(&asoc->pending_reply_queue); - while (sq) { + TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) { TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next); if (sq->data) { sctp_m_freem(sq->data); @@ -4873,168 +4911,131 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), sq); SCTP_DECR_READQ_COUNT(); /* sa_ignore FREED_MEMORY */ - sq = TAILQ_FIRST(&asoc->pending_reply_queue); } - - chk = TAILQ_FIRST(&asoc->free_chunks); - while (chk) { + TAILQ_FOREACH_SAFE(chk, &asoc->free_chunks, sctp_next, nchk) { TAILQ_REMOVE(&asoc->free_chunks, chk, sctp_next); if (chk->data) { sctp_m_freem(chk->data); chk->data = NULL; } if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - ccnt++; + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); SCTP_DECR_CHK_COUNT(); atomic_subtract_int(&SCTP_BASE_INFO(ipi_free_chunks), 1); asoc->free_chunk_cnt--; /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->free_chunks); } /* pending send queue SHOULD be empty */ - if (!TAILQ_EMPTY(&asoc->send_queue)) { - chk = TAILQ_FIRST(&asoc->send_queue); - while (chk) { - TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); - if (chk->data) { - if (so) { - /* Still a socket? */ - sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, - SCTP_NOTIFY_DATAGRAM_UNSENT, chk, SCTP_SO_LOCKED); - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } + TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { + if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { + asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; +#ifdef INVARIANTS + } else { + panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number); +#endif + } + TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); + if (chk->data) { + if (so) { + /* Still a socket? */ + sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, + 0, chk, SCTP_SO_LOCKED); } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - ccnt++; - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; } - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->send_queue); } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + if (chk->whoTo) { + sctp_free_remote_addr(chk->whoTo); + chk->whoTo = NULL; + } + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ } -/* - if (ccnt) { - printf("Freed %d from send_queue\n", ccnt); - ccnt = 0; - } -*/ /* sent queue SHOULD be empty */ - if (!TAILQ_EMPTY(&asoc->sent_queue)) { - chk = TAILQ_FIRST(&asoc->sent_queue); - while (chk) { - TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); - if (chk->data) { - if (so) { - /* Still a socket? */ - sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, - SCTP_NOTIFY_DATAGRAM_SENT, chk, SCTP_SO_LOCKED); - } - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } + TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { + if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { + if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { + asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; +#ifdef INVARIANTS + } else { + panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number); +#endif } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - ccnt++; - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->sent_queue); } - } -/* - if (ccnt) { - printf("Freed %d from sent_queue\n", ccnt); - ccnt = 0; - } -*/ - /* control queue MAY not be empty */ - if (!TAILQ_EMPTY(&asoc->control_send_queue)) { - chk = TAILQ_FIRST(&asoc->control_send_queue); - while (chk) { - TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); + TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); + if (chk->data) { + if (so) { + /* Still a socket? */ + sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, + 0, chk, SCTP_SO_LOCKED); + } if (chk->data) { sctp_m_freem(chk->data); chk->data = NULL; } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - ccnt++; - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->control_send_queue); } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + sctp_free_remote_addr(chk->whoTo); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ + } +#ifdef INVARIANTS + for (i = 0; i < stcb->asoc.streamoutcnt; i++) { + if (stcb->asoc.strmout[i].chunks_on_queues > 0) { + panic("%u chunks left for stream %u.", stcb->asoc.strmout[i].chunks_on_queues, i); + } + } +#endif + /* control queue MAY not be empty */ + TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { + TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + sctp_free_remote_addr(chk->whoTo); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ } -/* - if (ccnt) { - printf("Freed %d from ctrl_queue\n", ccnt); - ccnt = 0; - } -*/ - /* ASCONF queue MAY not be empty */ - if (!TAILQ_EMPTY(&asoc->asconf_send_queue)) { - chk = TAILQ_FIRST(&asoc->asconf_send_queue); - while (chk) { - TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - ccnt++; - sctp_free_remote_addr(chk->whoTo); - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->asconf_send_queue); + TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { + TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + sctp_free_remote_addr(chk->whoTo); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ } -/* - if (ccnt) { - printf("Freed %d from asconf_queue\n", ccnt); - ccnt = 0; - } -*/ - if (!TAILQ_EMPTY(&asoc->reasmqueue)) { - chk = TAILQ_FIRST(&asoc->reasmqueue); - while (chk) { - TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - if (chk->holds_key_ref) - sctp_auth_key_release(stcb, chk->auth_keyid); - sctp_free_remote_addr(chk->whoTo); - ccnt++; - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); - SCTP_DECR_CHK_COUNT(); - /* sa_ignore FREED_MEMORY */ - chk = TAILQ_FIRST(&asoc->reasmqueue); + TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { + TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; } + if (chk->holds_key_ref) + sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); + sctp_free_remote_addr(chk->whoTo); + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ } -/* - if (ccnt) { - printf("Freed %d from reasm_queue\n", ccnt); - ccnt = 0; - } -*/ + if (asoc->mapping_array) { SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); asoc->mapping_array = NULL; @@ -5050,66 +5051,50 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } asoc->strm_realoutsize = asoc->streamoutcnt = 0; if (asoc->strmin) { - struct sctp_queued_to_read *ctl; + struct sctp_queued_to_read *ctl, *nctl; for (i = 0; i < asoc->streamincnt; i++) { - if (!TAILQ_EMPTY(&asoc->strmin[i].inqueue)) { - /* We have somethings on the streamin queue */ - ctl = TAILQ_FIRST(&asoc->strmin[i].inqueue); - while (ctl) { - TAILQ_REMOVE(&asoc->strmin[i].inqueue, - ctl, next); - sctp_free_remote_addr(ctl->whoFrom); - if (ctl->data) { - sctp_m_freem(ctl->data); - ctl->data = NULL; - } - /* - * We don't free the address here - * since all the net's were freed - * above. - */ - SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl); - SCTP_DECR_READQ_COUNT(); - ctl = TAILQ_FIRST(&asoc->strmin[i].inqueue); + TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[i].inqueue, next, nctl) { + TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next); + sctp_free_remote_addr(ctl->whoFrom); + if (ctl->data) { + sctp_m_freem(ctl->data); + ctl->data = NULL; } + /* + * We don't free the address here since all + * the net's were freed above. + */ + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl); + SCTP_DECR_READQ_COUNT(); } } SCTP_FREE(asoc->strmin, SCTP_M_STRMI); asoc->strmin = NULL; } asoc->streamincnt = 0; - while (!TAILQ_EMPTY(&asoc->nets)) { - /* sa_ignore FREED_MEMORY */ - net = TAILQ_FIRST(&asoc->nets); - /* pull from list */ - if ((SCTP_BASE_INFO(ipi_count_raddr) == 0) || (prev == net)) { + TAILQ_FOREACH_SAFE(net, &asoc->nets, sctp_next, nnet) { #ifdef INVARIANTS + if (SCTP_BASE_INFO(ipi_count_raddr) == 0) { panic("no net's left alloc'ed, or list points to itself"); -#endif - break; } - prev = net; +#endif TAILQ_REMOVE(&asoc->nets, net, sctp_next); sctp_free_remote_addr(net); } - - while (!LIST_EMPTY(&asoc->sctp_restricted_addrs)) { + LIST_FOREACH_SAFE(laddr, &asoc->sctp_restricted_addrs, sctp_nxt_addr, naddr) { /* sa_ignore FREED_MEMORY */ - laddr = LIST_FIRST(&asoc->sctp_restricted_addrs); sctp_remove_laddr(laddr); } /* pending asconf (address) parameters */ - while (!TAILQ_EMPTY(&asoc->asconf_queue)) { + TAILQ_FOREACH_SAFE(aparam, &asoc->asconf_queue, next, naparam) { /* sa_ignore FREED_MEMORY */ - aparam = TAILQ_FIRST(&asoc->asconf_queue); TAILQ_REMOVE(&asoc->asconf_queue, aparam, next); SCTP_FREE(aparam, SCTP_M_ASC_ADDR); } - while (!TAILQ_EMPTY(&asoc->asconf_ack_sent)) { + TAILQ_FOREACH_SAFE(aack, &asoc->asconf_ack_sent, next, naack) { /* sa_ignore FREED_MEMORY */ - aack = TAILQ_FIRST(&asoc->asconf_ack_sent); TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next); if (aack->data != NULL) { sctp_m_freem(aack->data); @@ -5129,12 +5114,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_free_authinfo(&asoc->authinfo); - shared_key = LIST_FIRST(&asoc->shared_keys); - while (shared_key) { + LIST_FOREACH_SAFE(shared_key, &asoc->shared_keys, next, nshared_key) { LIST_REMOVE(shared_key, next); sctp_free_sharedkey(shared_key); /* sa_ignore FREED_MEMORY */ - shared_key = LIST_FIRST(&asoc->shared_keys); } /* Insert new items here :> */ @@ -5231,13 +5214,21 @@ sctp_destination_is_reachable(struct sctp_tcb *stcb, struct sockaddr *destaddr) return (1); } /* NOTE: all "scope" checks are done when local addresses are added */ - if (destaddr->sa_family == AF_INET6) { + switch (destaddr->sa_family) { +#ifdef INET6 + case AF_INET6: answer = inp->ip_inp.inp.inp_vflag & INP_IPV6; - } else if (destaddr->sa_family == AF_INET) { + break; +#endif +#ifdef INET + case AF_INET: answer = inp->ip_inp.inp.inp_vflag & INP_IPV4; - } else { + break; +#endif + default: /* invalid family, so it's unreachable */ answer = 0; + break; } return (answer); } @@ -5262,10 +5253,19 @@ sctp_update_ep_vflag(struct sctp_inpcb *inp) if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { continue; } - if (laddr->ifa->address.sa.sa_family == AF_INET6) { + switch (laddr->ifa->address.sa.sa_family) { +#ifdef INET6 + case AF_INET6: inp->ip_inp.inp.inp_vflag |= INP_IPV6; - } else if (laddr->ifa->address.sa.sa_family == AF_INET) { + break; +#endif +#ifdef INET + case AF_INET: inp->ip_inp.inp.inp_vflag |= INP_IPV4; + break; +#endif + default: + break; } } } @@ -5286,12 +5286,14 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac /* You are already bound to all. You have it already */ return; } +#ifdef INET6 if (ifa->address.sa.sa_family == AF_INET6) { if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { /* Can't bind a non-useable addr. */ return; } } +#endif /* first, is it already present? */ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { if (laddr->ifa == ifa) { @@ -5307,10 +5309,19 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac return; inp->laddr_count++; /* update inp_vflag flags */ - if (ifa->address.sa.sa_family == AF_INET6) { + switch (ifa->address.sa.sa_family) { +#ifdef INET6 + case AF_INET6: inp->ip_inp.inp.inp_vflag |= INP_IPV6; - } else if (ifa->address.sa.sa_family == AF_INET) { + break; +#endif +#ifdef INET + case AF_INET: inp->ip_inp.inp.inp_vflag |= INP_IPV4; + break; +#endif + default: + break; } } return; @@ -5428,7 +5439,6 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa) void sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) { - struct sctp_inpcb *inp; struct sctp_laddr *laddr; struct sctpladdr *list; @@ -5438,13 +5448,14 @@ sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) */ list = &stcb->asoc.sctp_restricted_addrs; - inp = stcb->sctp_ep; +#ifdef INET6 if (ifa->address.sa.sa_family == AF_INET6) { if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { /* Can't bind a non-existent addr. */ return; } } +#endif /* does the address already exist? */ LIST_FOREACH(laddr, list, sctp_nxt_addr) { if (laddr->ifa == ifa) { @@ -5546,6 +5557,163 @@ sctp_del_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) static int sctp_max_number_of_assoc = SCTP_MAX_NUM_OF_ASOC; static int sctp_scale_up_for_address = SCTP_SCALE_FOR_ADDR; + + +#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP) +struct sctp_mcore_ctrl *sctp_mcore_workers = NULL; +int *sctp_cpuarry = NULL; +void +sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use) +{ + /* Queue a packet to a processor for the specified core */ + struct sctp_mcore_queue *qent; + struct sctp_mcore_ctrl *wkq; + int need_wake = 0; + + if (sctp_mcore_workers == NULL) { + /* Something went way bad during setup */ + sctp_input_with_port(m, off, 0); + return; + } + SCTP_MALLOC(qent, struct sctp_mcore_queue *, + (sizeof(struct sctp_mcore_queue)), + SCTP_M_MCORE); + if (qent == NULL) { + /* This is trouble */ + sctp_input_with_port(m, off, 0); + return; + } + qent->vn = curvnet; + qent->m = m; + qent->off = off; + qent->v6 = 0; + wkq = &sctp_mcore_workers[cpu_to_use]; + SCTP_MCORE_QLOCK(wkq); + + TAILQ_INSERT_TAIL(&wkq->que, qent, next); + if (wkq->running == 0) { + need_wake = 1; + } + SCTP_MCORE_QUNLOCK(wkq); + if (need_wake) { + wakeup(&wkq->running); + } +} + +static void +sctp_mcore_thread(void *arg) +{ + + struct sctp_mcore_ctrl *wkq; + struct sctp_mcore_queue *qent; + + wkq = (struct sctp_mcore_ctrl *)arg; + struct mbuf *m; + int off, v6; + + /* Wait for first tickle */ + SCTP_MCORE_LOCK(wkq); + wkq->running = 0; + msleep(&wkq->running, + &wkq->core_mtx, + 0, "wait for pkt", 0); + SCTP_MCORE_UNLOCK(wkq); + + /* Bind to our cpu */ + thread_lock(curthread); + sched_bind(curthread, wkq->cpuid); + thread_unlock(curthread); + + /* Now lets start working */ + SCTP_MCORE_LOCK(wkq); + /* Now grab lock and go */ + for (;;) { + SCTP_MCORE_QLOCK(wkq); +skip_sleep: + wkq->running = 1; + qent = TAILQ_FIRST(&wkq->que); + if (qent) { + TAILQ_REMOVE(&wkq->que, qent, next); + SCTP_MCORE_QUNLOCK(wkq); + CURVNET_SET(qent->vn); + m = qent->m; + off = qent->off; + v6 = qent->v6; + SCTP_FREE(qent, SCTP_M_MCORE); + if (v6 == 0) { + sctp_input_with_port(m, off, 0); + } else { + SCTP_PRINTF("V6 not yet supported\n"); + sctp_m_freem(m); + } + CURVNET_RESTORE(); + SCTP_MCORE_QLOCK(wkq); + } + wkq->running = 0; + if (!TAILQ_EMPTY(&wkq->que)) { + goto skip_sleep; + } + SCTP_MCORE_QUNLOCK(wkq); + msleep(&wkq->running, + &wkq->core_mtx, + 0, "wait for pkt", 0); + } +} + +static void +sctp_startup_mcore_threads(void) +{ + int i, cpu; + + if (mp_ncpus == 1) + return; + + if (sctp_mcore_workers != NULL) { + /* + * Already been here in some previous vnet? + */ + return; + } + SCTP_MALLOC(sctp_mcore_workers, struct sctp_mcore_ctrl *, + ((mp_maxid + 1) * sizeof(struct sctp_mcore_ctrl)), + SCTP_M_MCORE); + if (sctp_mcore_workers == NULL) { + /* TSNH I hope */ + return; + } + memset(sctp_mcore_workers, 0, ((mp_maxid + 1) * + sizeof(struct sctp_mcore_ctrl))); + /* Init the structures */ + for (i = 0; i <= mp_maxid; i++) { + TAILQ_INIT(&sctp_mcore_workers[i].que); + SCTP_MCORE_LOCK_INIT(&sctp_mcore_workers[i]); + SCTP_MCORE_QLOCK_INIT(&sctp_mcore_workers[i]); + sctp_mcore_workers[i].cpuid = i; + } + if (sctp_cpuarry == NULL) { + SCTP_MALLOC(sctp_cpuarry, int *, + (mp_ncpus * sizeof(int)), + SCTP_M_MCORE); + i = 0; + CPU_FOREACH(cpu) { + sctp_cpuarry[i] = cpu; + i++; + } + } + /* Now start them all */ + CPU_FOREACH(cpu) { + (void)kproc_create(sctp_mcore_thread, + (void *)&sctp_mcore_workers[cpu], + &sctp_mcore_workers[cpu].thread_proc, + RFPROC, + SCTP_KTHREAD_PAGES, + SCTP_MCORE_NAME); + + } +} + +#endif + void sctp_pcb_init() { @@ -5565,11 +5733,18 @@ sctp_pcb_init() #if defined(SCTP_LOCAL_TRACE_BUF) bzero(&SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log)); #endif +#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) + SCTP_MALLOC(SCTP_BASE_STATS, struct sctpstat *, + ((mp_maxid + 1) * sizeof(struct sctpstat)), + SCTP_M_MCORE); +#endif (void)SCTP_GETTIME_TIMEVAL(&tv); #if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) + bzero(SCTP_BASE_STATS, (sizeof(struct sctpstat) * (mp_maxid + 1))); SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_sec = (uint32_t) tv.tv_sec; SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_usec = (uint32_t) tv.tv_usec; #else + bzero(&SCTP_BASE_STATS, sizeof(struct sctpstat)); SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t) tv.tv_sec; SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t) tv.tv_usec; #endif @@ -5676,13 +5851,16 @@ sctp_pcb_init() sctp_startup_iterator(); +#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP) + sctp_startup_mcore_threads(); +#endif + /* * INIT the default VRF which for BSD is the only one, other O/S's * may have more. But initially they must start with one and then * add the VRF's as addresses are added. */ sctp_init_vrf_list(SCTP_DEFAULT_VRF); - } /* @@ -5692,12 +5870,12 @@ void sctp_pcb_finish(void) { struct sctp_vrflist *vrf_bucket; - struct sctp_vrf *vrf; - struct sctp_ifn *ifn; - struct sctp_ifa *ifa; + struct sctp_vrf *vrf, *nvrf; + struct sctp_ifn *ifn, *nifn; + struct sctp_ifa *ifa, *nifa; struct sctpvtaghead *chain; struct sctp_tagblock *twait_block, *prev_twait_block; - struct sctp_laddr *wi; + struct sctp_laddr *wi, *nwi; int i; /* @@ -5709,20 +5887,15 @@ sctp_pcb_finish(void) struct sctp_iterator *it, *nit; SCTP_IPI_ITERATOR_WQ_LOCK(); - it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead); - while (it) { - nit = TAILQ_NEXT(it, sctp_nxt_itr); + TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { if (it->vn != curvnet) { - it = nit; continue; } - TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, - it, sctp_nxt_itr); + TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); if (it->function_atend != NULL) { (*it->function_atend) (it->pointer, it->val); } SCTP_FREE(it, SCTP_M_ITER); - it = nit; } SCTP_IPI_ITERATOR_WQ_UNLOCK(); SCTP_ITERATOR_LOCK(); @@ -5735,7 +5908,7 @@ sctp_pcb_finish(void) SCTP_OS_TIMER_STOP(&SCTP_BASE_INFO(addr_wq_timer.timer)); SCTP_WQ_ADDR_LOCK(); - while ((wi = LIST_FIRST(&SCTP_BASE_INFO(addr_wq))) != NULL) { + LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { LIST_REMOVE(wi, sctp_nxt_addr); SCTP_DECR_LADDR_COUNT(); SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), wi); @@ -5747,9 +5920,9 @@ sctp_pcb_finish(void) * destroyed first). */ vrf_bucket = &SCTP_BASE_INFO(sctp_vrfhash)[(SCTP_DEFAULT_VRFID & SCTP_BASE_INFO(hashvrfmark))]; - while ((vrf = LIST_FIRST(vrf_bucket)) != NULL) { - while ((ifn = LIST_FIRST(&vrf->ifnlist)) != NULL) { - while ((ifa = LIST_FIRST(&ifn->ifalist)) != NULL) { + LIST_FOREACH_SAFE(vrf, vrf_bucket, next_vrf, nvrf) { + LIST_FOREACH_SAFE(ifn, &vrf->ifnlist, next_ifn, nifn) { + LIST_FOREACH_SAFE(ifa, &ifn->ifalist, next_ifa, nifa) { /* free the ifa */ LIST_REMOVE(ifa, next_bucket); LIST_REMOVE(ifa, next_ifa); @@ -5813,13 +5986,16 @@ sctp_pcb_finish(void) SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_ephash), SCTP_BASE_INFO(hashmark)); if (SCTP_BASE_INFO(sctp_tcpephash) != NULL) SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_tcpephash), SCTP_BASE_INFO(hashtcpmark)); - +#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) + SCTP_FREE(SCTP_BASE_STATS, SCTP_M_MCORE); +#endif } int sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, - int iphlen, int offset, int limit, struct sctphdr *sh, + int offset, int limit, + struct sockaddr *src, struct sockaddr *dst, struct sockaddr *altsa) { /* @@ -5829,17 +6005,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * with either INIT or INIT-ACK's as long as the m points to the IP * packet and the offset points to the beginning of the parameters. */ - struct sctp_inpcb *inp, *l_inp; - struct sctp_nets *net, *net_tmp; - struct ip *iph; + struct sctp_inpcb *inp; + struct sctp_nets *net, *nnet, *net_tmp; struct sctp_paramhdr *phdr, parm_buf; struct sctp_tcb *stcb_tmp; uint16_t ptype, plen; struct sockaddr *sa; - struct sockaddr_storage dest_store; - struct sockaddr *local_sa = (struct sockaddr *)&dest_store; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; struct sctp_auth_random *p_random = NULL; uint16_t random_len = 0; @@ -5854,91 +6025,71 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sctp_key_t *new_key; uint32_t keylen; int got_random = 0, got_hmacs = 0, got_chklist = 0; + uint8_t ecn_allowed; + +#ifdef INET + struct sockaddr_in sin; + +#endif +#ifdef INET6 + struct sockaddr_in6 sin6; + +#endif /* First get the destination address setup too. */ +#ifdef INET memset(&sin, 0, sizeof(sin)); - memset(&sin6, 0, sizeof(sin6)); - sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); sin.sin_port = stcb->rport; - +#endif +#ifdef INET6 + memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_port = stcb->rport; - if (altsa == NULL) { - iph = mtod(m, struct ip *); - switch (iph->ip_v) { - case IPVERSION: - { - /* its IPv4 */ - struct sockaddr_in *sin_2; - - sin_2 = (struct sockaddr_in *)(local_sa); - memset(sin_2, 0, sizeof(sin)); - sin_2->sin_family = AF_INET; - sin_2->sin_len = sizeof(sin); - sin_2->sin_port = sh->dest_port; - sin_2->sin_addr.s_addr = iph->ip_dst.s_addr; - sin.sin_addr = iph->ip_src; - sa = (struct sockaddr *)&sin; - break; - } -#ifdef INET6 - case IPV6_VERSION >> 4: - { - /* its IPv6 */ - struct ip6_hdr *ip6; - struct sockaddr_in6 *sin6_2; - - ip6 = mtod(m, struct ip6_hdr *); - sin6_2 = (struct sockaddr_in6 *)(local_sa); - memset(sin6_2, 0, sizeof(sin6)); - sin6_2->sin6_family = AF_INET6; - sin6_2->sin6_len = sizeof(struct sockaddr_in6); - sin6_2->sin6_port = sh->dest_port; - sin6.sin6_addr = ip6->ip6_src; - sa = (struct sockaddr *)&sin6; - break; - } #endif - default: - return (-1); - break; - } - } else { - /* - * For cookies we use the src address NOT from the packet - * but from the original INIT - */ + if (altsa) { sa = altsa; + } else { + sa = src; } /* Turn off ECN until we get through all params */ - stcb->asoc.ecn_allowed = 0; + ecn_allowed = 0; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { /* mark all addresses that we have currently on the list */ net->dest_state |= SCTP_ADDR_NOT_IN_ASSOC; } /* does the source address already exist? if so skip it */ - l_inp = inp = stcb->sctp_ep; - + inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); - stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net_tmp, local_sa, stcb); + stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net_tmp, dst, stcb); atomic_add_int(&stcb->asoc.refcnt, -1); if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || inp == NULL) { /* we must add the source address */ /* no scope set here since we have a tcb already. */ - if ((sa->sa_family == AF_INET) && - (stcb->asoc.ipv4_addr_legal)) { - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { - return (-1); + switch (sa->sa_family) { +#ifdef INET + case AF_INET: + if (stcb->asoc.scope.ipv4_addr_legal) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_2)) { + return (-1); + } } - } else if ((sa->sa_family == AF_INET6) && - (stcb->asoc.ipv6_addr_legal)) { - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { - return (-2); + break; +#endif +#ifdef INET6 + case AF_INET6: + if (stcb->asoc.scope.ipv6_addr_legal) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_3)) { + return (-2); + } } + break; +#endif + default: + break; } } else { if (net_tmp != NULL && stcb_tmp == stcb) { @@ -5966,8 +6117,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, ptype = ntohs(phdr->param_type); plen = ntohs(phdr->param_length); /* - * printf("ptype => %0x, plen => %d\n", (uint32_t)ptype, - * (int)plen); + * SCTP_PRINTF("ptype => %0x, plen => %d\n", + * (uint32_t)ptype, (int)plen); */ if (offset + plen > limit) { break; @@ -5975,8 +6126,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, if (plen == 0) { break; } +#ifdef INET if (ptype == SCTP_IPV4_ADDRESS) { - if (stcb->asoc.ipv4_addr_legal) { + if (stcb->asoc.scope.ipv4_addr_legal) { struct sctp_ipv4addr_param *p4, p4_buf; /* ok get the v4 address and check/add */ @@ -6001,7 +6153,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, - local_sa, stcb); + dst, stcb); atomic_add_int(&stcb->asoc.refcnt, -1); if ((stcb_tmp == NULL && inp == stcb->sctp_ep) || @@ -6021,7 +6173,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* the assoc was freed? */ return (-7); } - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_4)) { return (-8); } } else if (stcb_tmp == stcb) { @@ -6046,7 +6198,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * abort this guy */ sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, 1, NULL, 0); + stcb_tmp, NULL, SCTP_SO_NOT_LOCKED); goto add_it_now; } SCTP_TCB_UNLOCK(stcb_tmp); @@ -6058,8 +6210,11 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, return (-13); } } - } else if (ptype == SCTP_IPV6_ADDRESS) { - if (stcb->asoc.ipv6_addr_legal) { + } else +#endif +#ifdef INET6 + if (ptype == SCTP_IPV6_ADDRESS) { + if (stcb->asoc.scope.ipv6_addr_legal) { /* ok get the v6 address and check/add */ struct sctp_ipv6addr_param *p6, p6_buf; @@ -6088,7 +6243,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); stcb_tmp = sctp_findassociation_ep_addr(&inp, sa, &net, - local_sa, stcb); + dst, stcb); atomic_add_int(&stcb->asoc.refcnt, -1); if (stcb_tmp == NULL && (inp == stcb->sctp_ep || inp == NULL)) { @@ -6105,7 +6260,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * we must add the address, no scope * set */ - if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { + if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_LOAD_ADDR_5)) { return (-17); } } else if (stcb_tmp == stcb) { @@ -6134,7 +6289,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, * abort this guy */ sctp_abort_an_association(stcb_tmp->sctp_ep, - stcb_tmp, 1, NULL, 0); + stcb_tmp, NULL, SCTP_SO_NOT_LOCKED); goto add_it_now6; } SCTP_TCB_UNLOCK(stcb_tmp); @@ -6146,8 +6301,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, return (-22); } } - } else if (ptype == SCTP_ECN_CAPABLE) { - stcb->asoc.ecn_allowed = 1; + } else +#endif + if (ptype == SCTP_ECN_CAPABLE) { + ecn_allowed = 1; } else if (ptype == SCTP_ULP_ADAPTATION) { if (stcb->asoc.state != SCTP_STATE_OPEN) { struct sctp_adaptation_layer_indication ai, @@ -6163,10 +6320,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } } else if (ptype == SCTP_SET_PRIM_ADDR) { struct sctp_asconf_addr_param lstore, *fee; - struct sctp_asconf_addrv4_param *fii; int lptype; struct sockaddr *lsa = NULL; +#ifdef INET + struct sctp_asconf_addrv4_param *fii; + +#endif + stcb->asoc.peer_supports_asconf = 1; if (plen > sizeof(lstore)) { return (-23); @@ -6179,7 +6340,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } fee = (struct sctp_asconf_addr_param *)phdr; lptype = ntohs(fee->addrp.ph.param_type); - if (lptype == SCTP_IPV4_ADDRESS) { + switch (lptype) { +#ifdef INET + case SCTP_IPV4_ADDRESS: if (plen != sizeof(struct sctp_asconf_addrv4_param)) { SCTP_PRINTF("Sizeof setprim in init/init ack not %d but %d - ignored\n", @@ -6190,7 +6353,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sin.sin_addr.s_addr = fii->addrp.addr; lsa = (struct sockaddr *)&sin; } - } else if (lptype == SCTP_IPV6_ADDRESS) { + break; +#endif +#ifdef INET6 + case SCTP_IPV6_ADDRESS: if (plen != sizeof(struct sctp_asconf_addr_param)) { SCTP_PRINTF("Sizeof setprim (v6) in init/init ack not %d but %d - ignored\n", @@ -6202,6 +6368,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sizeof(fee->addrp.addr)); lsa = (struct sockaddr *)&sin6; } + break; +#endif + default: + break; } if (lsa) { (void)sctp_set_primary_addr(stcb, sa, NULL); @@ -6257,10 +6427,6 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } } - } else if (ptype == SCTP_ECN_NONCE_SUPPORTED) { - /* Peer supports ECN-nonce */ - stcb->asoc.peer_supports_ecn_nonce = 1; - stcb->asoc.ecn_nonce_allowed = 1; } else if (ptype == SCTP_RANDOM) { if (plen > sizeof(random_store)) break; @@ -6376,8 +6542,7 @@ next_param: sizeof(parm_buf)); } /* Now check to see if we need to purge any addresses */ - for (net = TAILQ_FIRST(&stcb->asoc.nets); net != NULL; net = net_tmp) { - net_tmp = TAILQ_NEXT(net, sctp_next); + TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) { if ((net->dest_state & SCTP_ADDR_NOT_IN_ASSOC) == SCTP_ADDR_NOT_IN_ASSOC) { /* This address has been removed from the asoc */ @@ -6391,6 +6556,9 @@ next_param: } } } + if (ecn_allowed == 0) { + stcb->asoc.ecn_allowed = 0; + } /* validate authentication required parameters */ if (got_random && got_hmacs) { stcb->asoc.peer_supports_auth = 1; @@ -6464,7 +6632,10 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, return (0); } stcb->asoc.primary_destination = net; - net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY; + if (!(net->dest_state & SCTP_ADDR_PF) && (stcb->asoc.alternate)) { + sctp_free_remote_addr(stcb->asoc.alternate); + stcb->asoc.alternate = NULL; + } net = TAILQ_FIRST(&stcb->asoc.nets); if (net != stcb->asoc.primary_destination) { /* @@ -6480,7 +6651,7 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa, } int -sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now, int save_in_twait) +sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now) { /* * This function serves two purposes. It will see if a TAG can be @@ -6559,13 +6730,8 @@ skip_vtag_check: return (1); } - -static sctp_assoc_t reneged_asoc_ids[256]; -static uint8_t reneged_at = 0; - - static void -sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) +sctp_drain_mbufs(struct sctp_tcb *stcb) { /* * We must hunt this association for MBUF's past the cumack (i.e. @@ -6590,12 +6756,8 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) cumulative_tsn_p1 = asoc->cumulative_tsn + 1; cnt = 0; /* First look in the re-assembly queue */ - chk = TAILQ_FIRST(&asoc->reasmqueue); - while (chk) { - /* Get the next one */ - nchk = TAILQ_NEXT(chk, sctp_next); - if (compare_with_wrap(chk->rec.data.TSN_seq, - cumulative_tsn_p1, MAX_TSN)) { + TAILQ_FOREACH_SAFE(chk, &asoc->reasmqueue, sctp_next, nchk) { + if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumulative_tsn_p1)) { /* Yep it is above cum-ack */ cnt++; SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.TSN_seq, asoc->mapping_array_base_tsn); @@ -6607,17 +6769,13 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) sctp_m_freem(chk->data); chk->data = NULL; } - sctp_free_a_chunk(stcb, chk); + sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); } - chk = nchk; } /* Ok that was fun, now we will drain all the inbound streams? */ for (strmat = 0; strmat < asoc->streamincnt; strmat++) { - ctl = TAILQ_FIRST(&asoc->strmin[strmat].inqueue); - while (ctl) { - nctl = TAILQ_NEXT(ctl, next); - if (compare_with_wrap(ctl->sinfo_tsn, - cumulative_tsn_p1, MAX_TSN)) { + TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next, nctl) { + if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) { /* Yep it is above cum-ack */ cnt++; SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn); @@ -6633,14 +6791,11 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), ctl); SCTP_DECR_READQ_COUNT(); } - ctl = nctl; } } if (cnt) { /* We must back down to see what the new highest is */ - for (i = asoc->highest_tsn_inside_map; - (compare_with_wrap(i, asoc->mapping_array_base_tsn, MAX_TSN) || (i == asoc->mapping_array_base_tsn)); - i--) { + for (i = asoc->highest_tsn_inside_map; SCTP_TSN_GE(i, asoc->mapping_array_base_tsn); i--) { SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn); if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { asoc->highest_tsn_inside_map = i; @@ -6677,10 +6832,8 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb) asoc->last_revoke_count = cnt; (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer); /* sa_ignore NO_NULL_CHK */ - sctp_send_sack(stcb); + sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED); - reneged_asoc_ids[reneged_at] = sctp_get_associd(stcb); - reneged_at++; } /* * Another issue, in un-setting the TSN's in the mapping array we @@ -6723,7 +6876,7 @@ sctp_drain() LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { /* For each association */ SCTP_TCB_LOCK(stcb); - sctp_drain_mbufs(inp, stcb); + sctp_drain_mbufs(stcb); SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); |