summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_asconf.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-03-15 11:27:14 +0000
committerrrs <rrs@FreeBSD.org>2007-03-15 11:27:14 +0000
commitbd8786ed778eb3e2e64f4bc1078d8653aa1a6d54 (patch)
tree3a099c736ba497f25dc6fd964a7995f33f2282ad /sys/netinet/sctp_asconf.c
parent7f1d3da162e9e7e9561d1b1ab3e88b00622c7b5e (diff)
downloadFreeBSD-src-bd8786ed778eb3e2e64f4bc1078d8653aa1a6d54.zip
FreeBSD-src-bd8786ed778eb3e2e64f4bc1078d8653aa1a6d54.tar.gz
- Sysctl's move to seperate file
- moved away from ifn/ifa access to sctp_ifa/sctp_ifn built and managed by the add-ip code. - cleaned up add-ip code to use the iterator - made iterator be a thread, which enables auto-asconf now. - rewrote and cleaned up source address selection (also made it use new structures). - Fixed a couple of memory leaks. - DACK now settable as to how many packets to delay as well as time. - connectx() to latest socket API, new associd arg. - Fixed issue with revoking and loosing potential to send when we inflate the flight size. We now inflate the cwnd too and deflate it later when the revoked chunk is sent or acked. - Got rid of some temp debug code - src addr selection moved to a common file (sctp_output.c) - Support for simple VRF's (we have support for multi-vfr via compile switch that is scrubbed from BSD but we won't need multi-vrf until we first get VRF :-D) - Rest of mib work for address information now done - Limit number of addresses in INIT/INIT-ACK to a #def (30). Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctp_asconf.c')
-rw-r--r--sys/netinet/sctp_asconf.c760
1 files changed, 354 insertions, 406 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 8abab9d..d4f088b 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -34,6 +34,7 @@
__FBSDID("$FreeBSD$");
#include <netinet/sctp_os.h>
#include <netinet/sctp_var.h>
+#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_pcb.h>
#include <netinet/sctp_header.h>
#include <netinet/sctputil.h>
@@ -47,8 +48,6 @@ __FBSDID("$FreeBSD$");
* SCTP_DEBUG_ASCONF2: detailed info
*/
#ifdef SCTP_DEBUG
-extern uint32_t sctp_debug_on;
-
#endif /* SCTP_DEBUG */
@@ -316,7 +315,6 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
}
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL);
-
}
return m_reply;
@@ -990,12 +988,12 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
/*
* process an ADD/DELETE IP ack from peer.
- * addr corresponding ifaddr to the address being added/deleted.
+ * addr corresponding sctp_ifa to the address being added/deleted.
* type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
* flag: 1=success, 0=failure.
*/
static void
-sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct ifaddr *addr,
+sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
uint16_t type, uint32_t flag)
{
/*
@@ -1023,7 +1021,7 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct ifaddr *addr,
* for add. If a duplicate operation is found, ignore the new one.
*/
static uint32_t
-sctp_asconf_queue_add(struct sctp_tcb *stcb, struct ifaddr *ifa, uint16_t type)
+sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa, uint16_t type)
{
struct sctp_asconf_addr *aa, *aa_next;
struct sockaddr *sa;
@@ -1037,7 +1035,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct ifaddr *ifa, uint16_t type)
aa = aa_next) {
aa_next = TAILQ_NEXT(aa, next);
/* address match? */
- if (sctp_asconf_addr_match(aa, ifa->ifa_addr) == 0)
+ if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
continue;
/* is the request already in queue (sent or not) */
if (aa->ap.aph.ph.param_type == type) {
@@ -1077,11 +1075,11 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct ifaddr *ifa, uint16_t type)
aa->ap.aph.ph.param_type = type;
aa->ifa = ifa;
/* correlation_id filled in during send routine later... */
- if (ifa->ifa_addr->sa_family == AF_INET6) {
+ if (ifa->address.sa.sa_family == AF_INET6) {
/* IPv6 address */
struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sin6 = (struct sockaddr_in6 *)&ifa->address.sa;
sa = (struct sockaddr *)sin6;
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
@@ -1090,9 +1088,9 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct ifaddr *ifa, uint16_t type)
sizeof(struct sctp_ipv6addr_param);
memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
sizeof(struct in6_addr));
- } else if (ifa->ifa_addr->sa_family == AF_INET) {
+ } else if (ifa->address.sa.sa_family == AF_INET) {
/* IPv4 address */
- struct sockaddr_in *sin = (struct sockaddr_in *)ifa->ifa_addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifa->address.sa;
sa = (struct sockaddr *)sin;
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
@@ -1153,6 +1151,7 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
uint16_t type)
{
struct sctp_asconf_addr *aa, *aa_next;
+ uint32_t vrf_id;
/* see if peer supports ASCONF */
if (stcb->asoc.peer_supports_asconf == 0) {
@@ -1208,8 +1207,9 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
}
/* fill in asconf address parameter fields */
/* top level elements are "networked" during send */
+ vrf_id = SCTP_DEFAULT_VRFID;
aa->ap.aph.ph.param_type = type;
- aa->ifa = sctp_find_ifa_by_addr(sa);
+ aa->ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
/* correlation_id filled in during send routine later... */
if (sa->sa_family == AF_INET6) {
/* IPv6 address */
@@ -1590,35 +1590,6 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
}
}
-/* is this an interface that we care about at all? */
-static uint32_t
-sctp_is_desired_interface_type(struct ifaddr *ifa)
-{
- int result;
-
- /* check the interface type to see if it's one we care about */
- switch (ifa->ifa_ifp->if_type) {
- case IFT_ETHER:
- case IFT_ISO88023:
- case IFT_ISO88025:
- case IFT_STARLAN:
- case IFT_P10:
- case IFT_P80:
- case IFT_HY:
- case IFT_FDDI:
- case IFT_PPP:
- case IFT_XETHER:
- case IFT_SLIP:
- case IFT_GIF:
- result = 1;
- break;
- default:
- result = 0;
- }
-
- return (result);
-}
-
static uint32_t
sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
{
@@ -1656,7 +1627,7 @@ sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
*/
static void
sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct ifaddr *ifa, uint16_t type)
+ struct sctp_ifa *ifa, uint16_t type)
{
int status;
@@ -1672,23 +1643,17 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
/* first, make sure it's a good address family */
- if (ifa->ifa_addr->sa_family != AF_INET6 &&
- ifa->ifa_addr->sa_family != AF_INET) {
+ if (ifa->address.sa.sa_family != AF_INET6 &&
+ ifa->address.sa.sa_family != AF_INET) {
return;
}
/* make sure we're "allowed" to add this type of addr */
- if (ifa->ifa_addr->sa_family == AF_INET6) {
- struct in6_ifaddr *ifa6;
-
+ if (ifa->address.sa.sa_family == AF_INET6) {
/* invalid if we're not a v6 endpoint */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
return;
/* is the v6 addr really valid ? */
- ifa6 = (struct in6_ifaddr *)ifa;
- if (IFA6_IS_DEPRECATED(ifa6) ||
- (ifa6->ia6_flags &
- (IN6_IFF_DETACHED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
- /* can't use an invalid address */
+ if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
return;
}
}
@@ -1700,27 +1665,16 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* Recall that this routine is only called for the subset bound
* w/ASCONF allowed case.
*/
-
- /*
- * do a scope_id check against any link local addresses in the
- * destination nets list to see if we should put this local address
- * on the pending list or not eg. don't put on the list if we have a
- * link local destination with the same scope_id
- */
- if (type == SCTP_ADD_IP_ADDRESS) {
- if (sctp_is_scopeid_in_nets(stcb, ifa->ifa_addr) == 0) {
- sctp_add_local_addr_assoc(stcb, ifa);
- }
- }
+ sctp_add_local_addr_assoc(stcb, ifa, 1);
/*
* check address scope if address is out of scope, don't queue
* anything... note: this would leave the address on both inp and
* asoc lists
*/
- if (ifa->ifa_addr->sa_family == AF_INET6) {
+ if (ifa->address.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/* we skip unspecifed addresses */
return;
@@ -1730,7 +1684,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
return;
}
/* is it the right link local scope? */
- if (sctp_is_scopeid_in_nets(stcb, ifa->ifa_addr) == 0) {
+ if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
return;
}
}
@@ -1738,7 +1692,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
return;
}
- } else if (ifa->ifa_addr->sa_family == AF_INET) {
+ } else if (ifa->address.sa.sa_family == AF_INET) {
struct sockaddr_in *sin;
struct in6pcb *inp6;
@@ -1748,7 +1702,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
SCTP_IPV6_V6ONLY(inp6))
return;
- sin = (struct sockaddr_in *)ifa->ifa_addr;
+ sin = (struct sockaddr_in *)&ifa->address.sa;
if (sin->sin_addr.s_addr == 0) {
/* we skip unspecifed addresses */
return;
@@ -1759,16 +1713,10 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
} else {
/* else, not AF_INET or AF_INET6, so skip */
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
- printf("addr_mgmt_assoc: not AF_INET or AF_INET6\n");
- }
-#endif /* SCTP_DEBUG */
return;
}
/* queue an asconf for this address add/delete */
-
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
/* does the peer do asconf? */
if (stcb->asoc.peer_supports_asconf) {
@@ -1786,247 +1734,266 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stcb, stcb->asoc.primary_destination);
}
}
- } else {
- /* this is the boundall, no ASCONF case */
-#if 0
- /* Peter: Fixe me? why the if 0? */
- /*
- * assume kernel will delete this very shortly; add done
- * above
- */
- if (type == SCTP_DEL_IP_ADDRESS) {
- /* if deleting, add this addr to the do not use list */
- sctp_add_local_addr_assoc(stcb, ifa);
- }
-#endif
}
}
-static void
-sctp_addr_mgmt_ep(struct sctp_inpcb *inp, struct ifaddr *ifa, uint16_t type)
-{
- struct sctp_tcb *stcb;
-
-
- SCTP_INP_WLOCK(inp);
- /* make sure we're "allowed" to add this type of addr */
- if (ifa->ifa_addr->sa_family == AF_INET6) {
- struct in6_ifaddr *ifa6;
- /* invalid if we're not a v6 endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
- SCTP_INP_WUNLOCK(inp);
- return;
- }
- /* is the v6 addr really valid ? */
- ifa6 = (struct in6_ifaddr *)ifa;
- if (IFA6_IS_DEPRECATED(ifa6) ||
- (ifa6->ia6_flags &
- (IN6_IFF_DETACHED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
- /* can't use an invalid address */
- SCTP_INP_WUNLOCK(inp);
- return;
- }
- } else if (ifa->ifa_addr->sa_family == AF_INET) {
- /* invalid if we are a v6 only endpoint */
- struct in6pcb *inp6;
-
- inp6 = (struct in6pcb *)&inp->ip_inp.inp;
-
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp6)) {
- SCTP_INP_WUNLOCK(inp);
- return;
- }
- } else {
- /* invalid address family */
- SCTP_INP_WUNLOCK(inp);
- return;
- }
- /* is this endpoint subset bound ? */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
- /* subset bound endpoint */
- if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
- /*
- * subset bound, but ASCONFs not allowed... if
- * adding, nothing to do, since not allowed if
- * deleting, remove address from endpoint peer will
- * have to "timeout" this addr
- */
- if (type == SCTP_DEL_IP_ADDRESS) {
- sctp_del_local_addr_ep(inp, ifa);
+int
+sctp_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val)
+{
+ struct sctp_asconf_iterator *asc;
+ struct sctp_ifa *ifa;
+ struct sctp_laddr *l;
+ int type;
+ int cnt_invalid = 0;
+
+ asc = (struct sctp_asconf_iterator *)ptr;
+ LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
+ ifa = l->ifa;
+ type = l->action;
+ if (ifa->address.sa.sa_family == AF_INET6) {
+ /* invalid if we're not a v6 endpoint */
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
+ return (1);
+ else
+ continue;
}
- /* no asconfs to queue for this inp... */
- SCTP_INP_WUNLOCK(inp);
- return;
- } else {
- /*
- * subset bound, ASCONFs allowed... if adding, add
- * address to endpoint list if deleting, remove
- * address from endpoint
- */
- if (type == SCTP_ADD_IP_ADDRESS) {
- sctp_add_local_addr_ep(inp, ifa);
- } else {
- sctp_del_local_addr_ep(inp, ifa);
+ } else if (ifa->address.sa.sa_family == AF_INET) {
+ /* invalid if we are a v6 only endpoint */
+ struct in6pcb *inp6;
+
+ inp6 = (struct in6pcb *)&inp->ip_inp.inp;
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
+ SCTP_IPV6_V6ONLY(inp6)) {
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
+ return (1);
+ else
+ continue;
}
- /* drop through and notify all asocs */
+ } else {
+ /* invalid address family */
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
+ return (1);
+ else
+ continue;
}
}
- /* process for all associations for this endpoint */
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- sctp_addr_mgmt_assoc(inp, stcb, ifa, type);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_WUNLOCK(inp);
+ return (0);
}
-/*
- * restrict the use of this address
- */
-static void
-sctp_addr_mgmt_restrict_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
+int
+sctp_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val)
{
- struct sctp_tcb *stcb;
-
- /* is this endpoint bound to all? */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
- /*
- * Nothing to do for subset bound case. Allow sctp_bindx()
- * to manage the address lists
- */
- return;
- }
- SCTP_INP_RLOCK(inp);
- /* process for all associations for this endpoint */
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- /* put this address on the "pending/do not use yet" list */
- SCTP_TCB_LOCK(stcb);
- sctp_add_local_addr_assoc(stcb, ifa);
- SCTP_TCB_UNLOCK(stcb);
+ struct sctp_ifa *ifa;
+ struct sctp_asconf_iterator *asc;
+ struct sctp_laddr *laddr, *nladdr, *l;
+
+ /* Only for specific case not bound all */
+ asc = (struct sctp_asconf_iterator *)ptr;
+ LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
+ ifa = l->ifa;
+ if (l->action == SCTP_ADD_IP_ADDRESS) {
+ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
+ if (laddr->ifa == ifa) {
+ laddr->action = 0;
+ break;
+ }
+ }
+ } else if (l->action == SCTP_DEL_IP_ADDRESS) {
+ laddr = LIST_FIRST(&inp->sctp_addr_list);
+ while (laddr) {
+ nladdr = LIST_NEXT(laddr, sctp_nxt_addr);
+ /* remove only after all guys are done */
+ if (laddr->ifa == ifa) {
+ sctp_del_local_addr_ep(inp, ifa);
+ }
+ laddr = nladdr;
+ }
+ }
}
- SCTP_INP_RUNLOCK(inp);
+ return (0);
}
-/*
- * this is only called for kernel initiated address changes eg. it will check
- * the PCB_FLAGS_AUTO_ASCONF flag
- */
-static void
-sctp_addr_mgmt(struct ifaddr *ifa, uint16_t type)
+void
+sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
+ uint32_t val)
{
- struct sockaddr *sa;
- struct sctp_inpcb *inp;
-
- /* make sure we care about this interface... */
- if (!sctp_is_desired_interface_type(ifa)) {
- return;
- }
- sa = ifa->ifa_addr;
- if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
- return;
-
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
- if (type == SCTP_ADD_IP_ADDRESS)
- printf("sctp_addr_mgmt: kernel adds ");
- else
- printf("sctp_addr_mgmt: kernel deletes ");
- sctp_print_address(sa);
- }
-#endif /* SCTP_DEBUG */
+ struct sctp_asconf_iterator *asc;
+ struct sctp_ifa *ifa;
+ struct sctp_laddr *l;
+ int cnt_invalid = 0;
+ int type, status;
+
+ asc = (struct sctp_asconf_iterator *)ptr;
+ LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
+ ifa = l->ifa;
+ type = l->action;
+ /* Same checks again for assoc */
+ if (ifa->address.sa.sa_family == AF_INET6) {
+ /* invalid if we're not a v6 endpoint */
+ struct sockaddr_in6 *sin6;
+
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
+ return;
+ else
+ continue;
+ }
+ sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ /* we skip unspecifed addresses */
+ continue;
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ if (stcb->asoc.local_scope == 0) {
+ continue;
+ }
+ /* is it the right link local scope? */
+ if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
+ continue;
+ }
+ }
+ } else if (ifa->address.sa.sa_family == AF_INET) {
+ /* invalid if we are a v6 only endpoint */
+ struct in6pcb *inp6;
+ struct sockaddr_in *sin;
+
+ inp6 = (struct in6pcb *)&inp->ip_inp.inp;
+ /* invalid if we are a v6 only endpoint */
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
+ SCTP_IPV6_V6ONLY(inp6))
+ continue;
- /* go through all our PCB's */
- LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF)) {
- sctp_addr_mgmt_ep(inp, ifa, type);
+ sin = (struct sockaddr_in *)&ifa->address.sa;
+ if (sin->sin_addr.s_addr == 0) {
+ /* we skip unspecifed addresses */
+ continue;
+ }
+ if (stcb->asoc.ipv4_local_scope == 0 &&
+ IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
+ continue;;
+ }
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
+ SCTP_IPV6_V6ONLY(inp6)) {
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
+ return;
+ else
+ continue;
+ }
} else {
- /* this address is going away anyways... */
- if (type == SCTP_DEL_IP_ADDRESS)
+ /* invalid address family */
+ cnt_invalid++;
+ if (asc->cnt == cnt_invalid)
return;
- /* (temporarily) restrict this address */
- sctp_addr_mgmt_restrict_ep(inp, ifa);
+ else
+ continue;
}
- /* else, not allowing automatic asconf's, so ignore */
- }
-}
-
-/*
- * add/delete IP address requests from kernel (via routing change) assumed
- * that the address is non-broadcast, non-multicast all addresses are passed
- * from any type of interface-- need to filter duplicate addresses may get
- * requested
- */
-
-void
-sctp_add_ip_address(struct ifaddr *ifa)
-{
- sctp_addr_mgmt(ifa, SCTP_ADD_IP_ADDRESS);
-}
-
-void
-sctp_delete_ip_address(struct ifaddr *ifa)
-{
- struct sctp_inpcb *inp;
-
- /* process the delete */
- sctp_addr_mgmt(ifa, SCTP_DEL_IP_ADDRESS);
- /*
- * need to remove this ifaddr from any cached routes and also any
- * from any assoc "restricted/pending" lists
- */
- /* make sure we care about this interface... */
- if (!sctp_is_desired_interface_type(ifa)) {
- return;
- }
- /* go through all our PCB's */
- SCTP_INP_INFO_RLOCK();
- LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
- struct sctp_tcb *stcb;
- struct sctp_laddr *laddr, *laddr_next;
-
- /* process for all associations for this endpoint */
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ /* put this address on the "pending/do not use yet" list */
+ if (type == SCTP_ADD_IP_ADDRESS) {
+ sctp_add_local_addr_assoc(stcb, ifa, 1);
+ } else if (type == SCTP_DEL_IP_ADDRESS) {
struct sctp_nets *net;
- /* process through the nets list */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
struct rtentry *rt;
/* delete this address if cached */
- rt = net->ro.ro_rt;
- if (rt != NULL && rt->rt_ifa == ifa) {
- /* RTFREE(rt); */
- net->ro.ro_rt = NULL;
+ if (net->ro._s_addr &&
+ (net->ro._s_addr->ifa == ifa)) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ net->src_addr_selected = 0;
+ rt = net->ro.ro_rt;
+ if (rt) {
+ RTFREE(rt);
+ net->ro.ro_rt = NULL;
+ }
+ /*
+ * Now we deleted our src address,
+ * should we not also now reset the
+ * cwnd/rto to start as if its a new
+ * address?
+ */
+ sctp_set_initial_cc_param(stcb, net);
+ net->RTO = stcb->asoc.initial_rto;
+
}
- } /* for each net */
- /* process through the asoc "pending" list */
- laddr = LIST_FIRST(&stcb->asoc.sctp_local_addr_list);
- while (laddr != NULL) {
- laddr_next = LIST_NEXT(laddr, sctp_nxt_addr);
- /* remove if in use */
- if (laddr->ifa == ifa) {
- sctp_remove_laddr(laddr);
+ }
+ } else if (type == SCTP_SET_PRIM_ADDR) {
+ if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
+ /*
+ * must validate the ifa in question is in
+ * the ep
+ */
+ if (sctp_is_addr_in_ep(stcb->sctp_ep, ifa) == 0) {
+ continue;
+ }
+ } else {
+ /* Need to check scopes for this guy */
+ if (sctp_is_address_in_scope(ifa,
+ stcb->asoc.ipv4_addr_legal,
+ stcb->asoc.ipv6_addr_legal,
+ stcb->asoc.loopback_scope,
+ stcb->asoc.ipv4_local_scope,
+ stcb->asoc.local_scope,
+ stcb->asoc.site_scope, 0) == 0) {
+ continue;
+ }
+ }
+
+ }
+ /* queue an asconf for this address add/delete */
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
+ /* does the peer do asconf? */
+ if (stcb->asoc.peer_supports_asconf) {
+ /* queue an asconf for this addr */
+
+ status = sctp_asconf_queue_add(stcb, ifa, type);
+ /*
+ * if queued ok, and in correct state, set
+ * the ASCONF timer if in non-open state, we
+ * will set this timer when the state does
+ * go open and do all the asconf's
+ */
+ if (status == 0 &&
+ SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+ sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
+ stcb, stcb->asoc.primary_destination);
}
- laddr = laddr_next;
- } /* while */
- } /* for each stcb */
- /* process through the inp bound addr list */
- laddr = LIST_FIRST(&inp->sctp_addr_list);
- while (laddr != NULL) {
- laddr_next = LIST_NEXT(laddr, sctp_nxt_addr);
- /* remove if in use */
- if (laddr->ifa == ifa) {
- sctp_remove_laddr(laddr);
}
- laddr = laddr_next;
}
- SCTP_INP_RUNLOCK(inp);
}
- SCTP_INP_INFO_RUNLOCK();
+}
+
+void
+sctp_iterator_end(void *ptr, uint32_t val)
+{
+ struct sctp_asconf_iterator *asc;
+ struct sctp_ifa *ifa;
+ struct sctp_laddr *l, *l_next;
+
+ asc = (struct sctp_asconf_iterator *)ptr;
+ l = LIST_FIRST(&asc->list_of_work);
+ while (l != NULL) {
+ l_next = LIST_NEXT(l, sctp_nxt_addr);
+ ifa = l->ifa;
+ if (l->action == SCTP_ADD_IP_ADDRESS) {
+ /* Clear the defer use flag */
+ ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
+ }
+ sctp_free_ifa(ifa);
+ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, l);
+ SCTP_DECR_LADDR_COUNT();
+ l = l_next;
+ }
+ SCTP_FREE(asc);
}
/*
@@ -2067,14 +2034,10 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
}
void
-sctp_set_primary_ip_address(struct ifaddr *ifa)
+sctp_set_primary_ip_address(struct sctp_ifa *ifa)
{
struct sctp_inpcb *inp;
- /* make sure we care about this interface... */
- if (!sctp_is_desired_interface_type(ifa)) {
- return;
- }
/* go through all our PCB's */
LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
struct sctp_tcb *stcb;
@@ -2095,7 +2058,7 @@ sctp_set_primary_ip_address(struct ifaddr *ifa)
if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
printf("set_primary_ip_address: queued on stcb=%p, ",
stcb);
- sctp_print_address(ifa->ifa_addr);
+ sctp_print_address(&ifa->address.sa);
}
#endif /* SCTP_DEBUG */
}
@@ -2106,21 +2069,23 @@ sctp_set_primary_ip_address(struct ifaddr *ifa)
static struct sockaddr *
sctp_find_valid_localaddr(struct sctp_tcb *stcb)
{
- struct ifnet *ifn;
- struct ifaddr *ifa;
-
-
- TAILQ_FOREACH(ifn, &ifnet, if_list) {
- if (stcb->asoc.loopback_scope == 0 && ifn->if_type == IFT_LOOP) {
+ struct sctp_vrf *vrf = NULL;
+ struct sctp_ifn *sctp_ifn;
+ struct sctp_ifa *sctp_ifa;
+
+ vrf = sctp_find_vrf(stcb->asoc.vrf_id);
+ LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
+ if (stcb->asoc.loopback_scope == 0 &&
+ SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* Skip if loopback_scope not set */
continue;
}
- TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
- if (ifa->ifa_addr->sa_family == AF_INET &&
+ LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
+ if (sctp_ifa->address.sa.sa_family == AF_INET &&
stcb->asoc.ipv4_addr_legal) {
struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)ifa->ifa_addr;
+ sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
if (sin->sin_addr.s_addr == 0) {
/* skip unspecifed addresses */
continue;
@@ -2129,23 +2094,18 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
continue;
- if (sctp_is_addr_restricted(stcb,
- ifa->ifa_addr))
+ if (sctp_is_addr_restricted(stcb, sctp_ifa))
continue;
/* found a valid local v4 address to use */
- return (ifa->ifa_addr);
- } else if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ return (&sctp_ifa->address.sa);
+ } else if (sctp_ifa->address.sa.sa_family == AF_INET6 &&
stcb->asoc.ipv6_addr_legal) {
struct sockaddr_in6 *sin6;
- struct in6_ifaddr *ifa6;
- ifa6 = (struct in6_ifaddr *)ifa;
- if (IFA6_IS_DEPRECATED(ifa6) ||
- (ifa6->ia6_flags & (IN6_IFF_DETACHED |
- IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)))
+ if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
continue;
-
- sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ }
+ sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
/* we skip unspecifed addresses */
continue;
@@ -2158,7 +2118,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
continue;
/* found a valid local v6 address to use */
- return (ifa->ifa_addr);
+ return (&sctp_ifa->address.sa);
}
}
}
@@ -2175,15 +2135,15 @@ sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
if (laddr->ifa == NULL) {
continue;
}
- if (laddr->ifa->ifa_addr == NULL) {
+ if (laddr->ifa == NULL) {
continue;
}
/* is the address restricted ? */
- if (sctp_is_addr_restricted(stcb, laddr->ifa->ifa_addr))
+ if (sctp_is_addr_restricted(stcb, laddr->ifa))
continue;
/* found a valid local address to use */
- return (laddr->ifa->ifa_addr);
+ return (&laddr->ifa->address.sa);
}
/* no valid addresses found */
return (NULL);
@@ -2384,11 +2344,12 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
{
struct sctp_paramhdr tmp_param, *ph;
uint16_t plen, ptype;
+ struct sctp_ifa *sctp_ifa;
struct sctp_ipv6addr_param addr_store;
struct sockaddr_in6 sin6;
struct sockaddr_in sin;
struct sockaddr *sa;
- struct ifaddr *ifa;
+ uint32_t vrf_id;
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
@@ -2438,7 +2399,9 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
struct sctp_ipv4addr_param *a4p;
/* get the entire IPv4 address param */
- a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_ipv4addr_param), (uint8_t *) & addr_store);
+ a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
+ sizeof(struct sctp_ipv4addr_param),
+ (uint8_t *) & addr_store);
if (plen != sizeof(struct sctp_ipv4addr_param) ||
a4p == NULL) {
return;
@@ -2450,8 +2413,9 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
}
/* see if this address really (still) exists */
- ifa = sctp_find_ifa_by_addr(sa);
- if (ifa == NULL) {
+ vrf_id = SCTP_DEFAULT_VRFID;
+ sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ if (sctp_ifa == NULL) {
/* address doesn't exist anymore */
int status;
@@ -2474,25 +2438,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
stcb->asoc.primary_destination);
}
}
- } else {
- /* address still exists */
- /*
- * if subset bound, ep addr's managed by default if
- * not doing ASCONF, add the address to the assoc
- */
- if ((stcb->sctp_ep->sctp_flags &
- SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
- (sctp_is_feature_off(stcb->sctp_ep,
- SCTP_PCB_FLAGS_DO_ASCONF))) {
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
- printf("process_initack_addrs: adding local addr to asoc\n");
- }
-#endif /* SCTP_DEBUG */
- sctp_add_local_addr_assoc(stcb, ifa);
- }
}
-
next_addr:
/*
* Sanity check: Make sure the length isn't 0, otherwise
@@ -2530,8 +2476,9 @@ sctp_addr_in_initack(struct sctp_tcb *stcb, struct mbuf *m, uint32_t offset,
struct sctp_ipv4addr_param *a4p;
#ifdef INET6
- struct sockaddr_in6 *sin6, sin6_tmp;
+ struct sockaddr_in6 *sin6;
struct sctp_ipv6addr_param *a6p;
+ struct sockaddr_in6 sin6_tmp;
#endif /* INET6 */
@@ -2642,7 +2589,7 @@ sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
#endif /* SCTP_DEBUG */
continue;
}
- if (laddr->ifa->ifa_addr == NULL) {
+ if (laddr->ifa == NULL) {
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
printf("check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
@@ -2651,12 +2598,12 @@ sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
continue;
}
/* do i have it implicitly? */
- if (sctp_cmpaddr(laddr->ifa->ifa_addr, init_addr)) {
+ if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
continue;
}
/* check to see if in the init-ack */
if (!sctp_addr_in_initack(stcb, m, offset, length,
- laddr->ifa->ifa_addr)) {
+ &laddr->ifa->address.sa)) {
/* try to add it */
sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
SCTP_ADD_IP_ADDRESS);
@@ -2674,27 +2621,34 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
uint16_t local_scope, uint16_t site_scope,
uint16_t ipv4_scope, uint16_t loopback_scope)
{
- struct ifnet *ifn;
- struct ifaddr *ifa;
-
+ struct sctp_vrf *vrf = NULL;
+ struct sctp_ifn *sctp_ifn;
+ struct sctp_ifa *sctp_ifa;
+ uint32_t vrf_id;
+
+ vrf_id = SCTP_DEFAULT_VRFID;
+ vrf = sctp_find_vrf(vrf_id);
+ if (vrf == NULL) {
+ return;
+ }
/* go through all our known interfaces */
- TAILQ_FOREACH(ifn, &ifnet, if_list) {
- if (loopback_scope == 0 && ifn->if_type == IFT_LOOP) {
+ LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
+ if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
/* skip loopback interface */
continue;
}
/* go through each interface address */
- TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
+ LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
/* do i have it implicitly? */
- if (sctp_cmpaddr(ifa->ifa_addr, init_addr)) {
+ if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) {
continue;
}
/* check to see if in the init-ack */
if (!sctp_addr_in_initack(stcb, m, offset, length,
- ifa->ifa_addr)) {
+ &sctp_ifa->address.sa)) {
/* try to add it */
sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
- ifa, SCTP_ADD_IP_ADDRESS);
+ sctp_ifa, SCTP_ADD_IP_ADDRESS);
}
} /* end foreach ifa */
} /* end foreach ifn */
@@ -2737,71 +2691,65 @@ sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
* sctp_bindx() support
*/
uint32_t
-sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint16_t type)
+sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, uint32_t vrf_id)
{
- struct ifaddr *ifa;
+ struct sctp_ifa *ifa;
-
- if (sa->sa_len == 0)
+ if (sa->sa_len == 0) {
return (EINVAL);
-
- ifa = sctp_find_ifa_by_addr(sa);
+ }
+ if (type == SCTP_ADD_IP_ADDRESS) {
+ /* For an add the address MUST be on the system */
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ } else if (type == SCTP_DEL_IP_ADDRESS) {
+ /* For a delete we need to find it in the inp */
+ ifa = sctp_find_ifa_in_ep(inp, sa, 0);
+ } else {
+ ifa = NULL;
+ }
if (ifa != NULL) {
-#ifdef INET6
- if (ifa->ifa_addr->sa_family == AF_INET6) {
- struct in6_ifaddr *ifa6;
-
- ifa6 = (struct in6_ifaddr *)ifa;
- if (IFA6_IS_DEPRECATED(ifa6) ||
- (ifa6->ia6_flags & (IN6_IFF_DETACHED |
- IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
- /* Can't bind a non-existent addr. */
- return (EINVAL);
+ /* add this address */
+ struct sctp_asconf_iterator *asc;
+ struct sctp_laddr *wi;
+
+ SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
+ sizeof(struct sctp_asconf_iterator), "SCTP_ASCONF_ITERATOR");
+ if (asc == NULL) {
+ return (ENOMEM);
+ }
+ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
+ if (wi == NULL) {
+ SCTP_FREE(asc);
+ return (ENOMEM);
+ }
+ if (type == SCTP_ADD_IP_ADDRESS) {
+ sctp_add_local_addr_ep(inp, ifa, type);
+ } else if (type == SCTP_DEL_IP_ADDRESS) {
+ struct sctp_laddr *laddr;
+
+ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
+ if (ifa == laddr->ifa) {
+ /* Mark in the delete */
+ laddr->action = type;
+ }
}
}
-#endif /* INET6 */
- /* add this address */
- sctp_addr_mgmt_ep(inp, ifa, type);
+ LIST_INIT(&asc->list_of_work);
+ asc->cnt = 1;
+ SCTP_INCR_LADDR_COUNT();
+ wi->ifa = ifa;
+ wi->action = type;
+ atomic_add_int(&ifa->refcount, 1);
+ LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
+ sctp_initiate_iterator(sctp_iterator_ep,
+ sctp_iterator_stcb,
+ sctp_iterator_ep_end,
+ SCTP_PCB_ANY_FLAGS,
+ SCTP_PCB_ANY_FEATURES, SCTP_ASOC_ANY_STATE, (void *)asc, 0,
+ sctp_iterator_end, inp, 0);
} else {
/* invalid address! */
return (EADDRNOTAVAIL);
}
return (0);
}
-
-void
-sctp_addr_change(struct ifaddr *ifa, int cmd)
-{
- struct sctp_laddr *wi;
-
- wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
- if (wi == NULL) {
- /*
- * Gak, what can we do? We have lost an address change can
- * you say HOSED?
- */
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_PCB1) {
- printf("Lost and address change ???\n");
- }
-#endif /* SCTP_DEBUG */
- return;
- }
- SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
- wi->ifa = ifa;
- IFAREF(ifa);
-
- wi->action = cmd;
- SCTP_IPI_ADDR_LOCK();
- /*
- * Should this really be a tailq? As it is we will process the
- * newest first :-0
- */
- LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
- sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
- (struct sctp_inpcb *)NULL,
- (struct sctp_tcb *)NULL,
- (struct sctp_nets *)NULL);
- SCTP_IPI_ADDR_UNLOCK();
-}
OpenPOWER on IntegriCloud