summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_asconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_asconf.c')
-rw-r--r--sys/netinet/sctp_asconf.c149
1 files changed, 76 insertions, 73 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 1c56ad8..937c3c7 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1204,14 +1204,12 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
/* success case, so remove from the restricted list */
sctp_del_local_addr_restricted(stcb, addr);
- if (sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) {
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_BASE)) {
sctp_path_check_and_react(stcb, addr);
return;
}
- /*
- * clear any cached, topologically incorrect source
- * addresses
- */
+ /* clear any cached/topologically incorrect source addresses */
sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
}
/* else, leave it on the list */
@@ -1310,6 +1308,7 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
} else {
/* invalid family! */
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
+ sctp_free_ifa(ifa);
return (-1);
}
aa->sent = 0; /* clear sent flag */
@@ -1428,17 +1427,17 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
return (status);
}
-/*
- * add an asconf add/delete IP address parameter to the queue by addr.
- * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
+/*-
+ * add an asconf delete IP address parameter to the queue by sockaddr and
+ * possibly with no sctp_ifa available. This is only called by the routine
+ * that checks the addresses in an INIT-ACK against the current address list.
* returns 0 if completed, non-zero if not completed.
- * NOTE: if adding, but delete already scheduled (and not yet sent out),
- * simply remove from queue. Same for deleting an address already scheduled
- * for add. If a duplicate operation is found, ignore the new one.
+ * NOTE: if an add is already scheduled (and not yet sent out), simply
+ * remove it from queue. If a duplicate operation is found, ignore the
+ * new one.
*/
static int
-sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
- uint16_t type)
+sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
{
struct sctp_ifa *ifa;
struct sctp_asconf_addr *aa, *aa_next;
@@ -1459,27 +1458,14 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
if (sctp_asconf_addr_match(aa, sa) == 0)
continue;
/* is the request already in queue (sent or not) */
- if (aa->ap.aph.ph.param_type == type) {
+ if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
return (-1);
}
/* is the negative request already in queue, and not sent */
if (aa->sent == 1)
continue;
- if (type == SCTP_ADD_IP_ADDRESS &&
- aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
- /* add requested, delete already queued */
-
- /* delete the existing entry in the queue */
- TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
- sctp_free_ifa(aa->ifa);
- /* free the entry */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- return (-1);
- } else if (type == SCTP_DEL_IP_ADDRESS &&
- aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
- /* delete requested, add already queued */
-
- /* delete the existing entry in the queue */
+ if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
+ /* add already queued, so remove existing entry */
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
sctp_del_local_addr_restricted(stcb, aa->ifa);
/* free the entry */
@@ -1487,31 +1473,30 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
return (-1);
}
} /* for each aa */
+
+ /* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */
if (stcb) {
vrf_id = stcb->asoc.vrf_id;
} else {
vrf_id = SCTP_DEFAULT_VRFID;
}
-
ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
- if (ifa == NULL) {
- /* Invalid address */
- return (-1);
- }
+
/* adding new request to the queue */
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
SCTP_M_ASC_ADDR);
if (aa == NULL) {
/* didn't get memory */
SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_queue_add_sa: failed to get memory!\n");
+ "sctp_asconf_queue_sa_delete: failed to get memory!\n");
return (-1);
}
/* fill in asconf address parameter fields */
/* top level elements are "networked" during send */
- aa->ap.aph.ph.param_type = type;
+ aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
aa->ifa = ifa;
- atomic_add_int(&ifa->refcount, 1);
+ if (ifa)
+ atomic_add_int(&ifa->refcount, 1);
/* correlation_id filled in during send routine later... */
if (sa->sa_family == AF_INET6) {
/* IPv6 address */
@@ -1535,21 +1520,14 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
} else {
/* invalid family! */
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
+ if (ifa)
+ sctp_free_ifa(ifa);
return (-1);
}
aa->sent = 0; /* clear sent flag */
- /*
- * if we are deleting an address it should go out last otherwise,
- * add it to front of the pending queue
- */
- if (type == SCTP_ADD_IP_ADDRESS) {
- /* add goes to the front of the queue */
- TAILQ_INSERT_HEAD(&stcb->asoc.asconf_queue, aa, next);
- } else {
- /* delete and set primary goes to the back of the queue */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- }
+ /* delete goes to the back of the queue */
+ TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
return (0);
}
@@ -1663,7 +1641,8 @@ sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
/* remove the param and free it */
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
- sctp_free_ifa(aparam->ifa);
+ if (aparam->ifa)
+ sctp_free_ifa(aparam->ifa);
SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
}
@@ -1681,7 +1660,7 @@ sctp_asconf_ack_clear(struct sctp_tcb *stcb)
void
sctp_handle_asconf_ack(struct mbuf *m, int offset,
struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
- struct sctp_nets *net)
+ struct sctp_nets *net, int *abort_no_unlock)
{
struct sctp_association *asoc;
uint32_t serial_num;
@@ -1721,6 +1700,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_CAUSE_ILLEGAL_ASCONF_ACK, NULL, SCTP_SO_NOT_LOCKED);
+ *abort_no_unlock = 1;
return;
}
if (serial_num != asoc->asconf_seq_out) {
@@ -1865,7 +1845,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
stcb, net);
#else
/* we have more params, so send out more */
- sctp_send_asconf(stcb, net);
+ sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
#endif
}
}
@@ -1907,7 +1887,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 sctp_ifa *ifa, uint16_t type)
+ struct sctp_ifa *ifa, uint16_t type, int addr_locked)
{
int status;
@@ -2007,7 +1987,8 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
stcb, stcb->asoc.primary_destination);
#else
- sctp_send_asconf(stcb, stcb->asoc.primary_destination);
+ sctp_send_asconf(stcb, stcb->asoc.primary_destination,
+ addr_locked);
#endif
}
}
@@ -2249,7 +2230,8 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* If we have queued params in the open state, send out an ASCONF.
*/
if (num_queued > 0) {
- sctp_send_asconf(stcb, stcb->asoc.primary_destination);
+ sctp_send_asconf(stcb, stcb->asoc.primary_destination,
+ SCTP_ADDR_NOT_LOCKED);
}
}
@@ -2284,10 +2266,22 @@ sctp_asconf_iterator_end(void *ptr, uint32_t val)
int32_t
sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
{
- /* NOTE: we currently don't check the validity of the address! */
+ uint32_t vrf_id;
+ struct sctp_ifa *ifa;
+ /* find the ifa for the desired set primary */
+ if (stcb) {
+ vrf_id = stcb->asoc.vrf_id;
+ } else {
+ vrf_id = SCTP_DEFAULT_VRFID;
+ }
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
+ if (ifa == NULL) {
+ /* Invalid address */
+ return (-1);
+ }
/* queue an ASCONF:SET_PRIM_ADDR to be sent */
- if (!sctp_asconf_queue_add_sa(stcb, sa, SCTP_SET_PRIM_ADDR)) {
+ if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) {
/* set primary queuing succeeded */
SCTPDBG(SCTP_DEBUG_ASCONF1,
"set_primary_ip_address_sa: queued on tcb=%p, ",
@@ -2299,7 +2293,8 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
- sctp_send_asconf(stcb, stcb->asoc.primary_destination);
+ sctp_send_asconf(stcb, stcb->asoc.primary_destination,
+ SCTP_ADDR_NOT_LOCKED);
#endif
}
} else {
@@ -2335,7 +2330,8 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
- sctp_send_asconf(stcb, stcb->asoc.primary_destination);
+ sctp_send_asconf(stcb, stcb->asoc.primary_destination,
+ SCTP_ADDR_NOT_LOCKED);
#endif
}
}
@@ -2344,16 +2340,18 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
}
static struct sockaddr *
-sctp_find_valid_localaddr(struct sctp_tcb *stcb)
+sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
{
struct sctp_vrf *vrf = NULL;
struct sctp_ifn *sctp_ifn;
struct sctp_ifa *sctp_ifa;
- SCTP_IPI_ADDR_LOCK();
+ if (addr_locked == SCTP_ADDR_NOT_LOCKED)
+ SCTP_IPI_ADDR_LOCK();
vrf = sctp_find_vrf(stcb->asoc.vrf_id);
if (vrf == NULL) {
- SCTP_IPI_ADDR_UNLOCK();
+ if (addr_locked == SCTP_ADDR_NOT_LOCKED)
+ SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
@@ -2379,7 +2377,8 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
if (sctp_is_addr_restricted(stcb, sctp_ifa))
continue;
/* found a valid local v4 address to use */
- SCTP_IPI_ADDR_UNLOCK();
+ if (addr_locked == SCTP_ADDR_NOT_LOCKED)
+ SCTP_IPI_ADDR_UNLOCK();
return (&sctp_ifa->address.sa);
} else if (sctp_ifa->address.sa.sa_family == AF_INET6 &&
stcb->asoc.ipv6_addr_legal) {
@@ -2401,13 +2400,15 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
continue;
/* found a valid local v6 address to use */
- SCTP_IPI_ADDR_UNLOCK();
+ if (addr_locked == SCTP_ADDR_NOT_LOCKED)
+ SCTP_IPI_ADDR_UNLOCK();
return (&sctp_ifa->address.sa);
}
}
}
/* no valid addresses found */
- SCTP_IPI_ADDR_UNLOCK();
+ if (addr_locked == SCTP_ADDR_NOT_LOCKED)
+ SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
@@ -2436,7 +2437,7 @@ sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
* returns NULL on error (no mbuf, no ASCONF params queued, etc).
*/
struct mbuf *
-sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen)
+sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
{
struct mbuf *m_asconf, *m_asconf_chk;
struct sctp_asconf_addr *aa;
@@ -2561,7 +2562,8 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen)
caddr_t addr_ptr;
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
- found_addr = sctp_find_valid_localaddr(stcb);
+ found_addr = sctp_find_valid_localaddr(stcb,
+ addr_locked);
else
found_addr = sctp_find_valid_localaddr_ep(stcb);
@@ -2697,8 +2699,8 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
} else {
vrf_id = SCTP_DEFAULT_VRFID;
}
-
- sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
+ sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id,
+ SCTP_ADDR_NOT_LOCKED);
if (sctp_ifa == NULL) {
/* address doesn't exist anymore */
int status;
@@ -2708,8 +2710,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
SCTP_PCB_FLAGS_DO_ASCONF)) &&
stcb->asoc.peer_supports_asconf) {
/* queue an ASCONF DEL_IP_ADDRESS */
- status = sctp_asconf_queue_add_sa(stcb, sa,
- SCTP_DEL_IP_ADDRESS);
+ status = sctp_asconf_queue_sa_delete(stcb, sa);
/*
* if queued ok, and in correct state, send
* out the ASCONF.
@@ -2722,7 +2723,8 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
stcb->sctp_ep, stcb,
stcb->asoc.primary_destination);
#else
- sctp_send_asconf(stcb, stcb->asoc.primary_destination);
+ sctp_send_asconf(stcb, stcb->asoc.primary_destination,
+ SCTP_ADDR_NOT_LOCKED);
#endif
}
}
@@ -2880,7 +2882,7 @@ sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
&laddr->ifa->address.sa)) {
/* try to add it */
sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
- SCTP_ADD_IP_ADDRESS);
+ SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED);
}
}
}
@@ -2928,7 +2930,8 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
&sctp_ifa->address.sa)) {
/* try to add it */
sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
- sctp_ifa, SCTP_ADD_IP_ADDRESS);
+ sctp_ifa, SCTP_ADD_IP_ADDRESS,
+ SCTP_ADDR_LOCKED);
}
} /* end foreach ifa */
} /* end foreach ifn */
OpenPOWER on IntegriCloud