summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/sctp_pcb.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/sctp_pcb.c')
-rw-r--r--freebsd/sys/netinet/sctp_pcb.c2229
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);