summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-08-16 01:51:22 +0000
committerrrs <rrs@FreeBSD.org>2007-08-16 01:51:22 +0000
commit1bcb372970356c4bb20cdd532350ea0df88a6f20 (patch)
tree2530cafc57ae1f3f5858ead34bf340916e72c7a1
parentba0da0a95deba64ddb6dc37fb2698973ff97e1ef (diff)
downloadFreeBSD-src-1bcb372970356c4bb20cdd532350ea0df88a6f20.zip
FreeBSD-src-1bcb372970356c4bb20cdd532350ea0df88a6f20.tar.gz
- Remove extra comment for 7.0 (no GIANT here).
- Remove unneeded WLOCK/UNLOCK of inp for getting TCB lock. - Fix panic that may occur when freeing an assoc that has partial delivery in progress (may dereference null socket pointer when queuing partial delivery aborted notification) - Some spacing and comment fixes. - Fix address add handling to clear cached routes and source addresses when peer acks the add in case the routing table changes. Approved by: re@freebsd.org (Bruce Mah)
-rw-r--r--sys/netinet/sctp_asconf.c51
-rw-r--r--sys/netinet/sctp_input.c10
-rw-r--r--sys/netinet/sctp_output.c89
-rw-r--r--sys/netinet/sctp_pcb.c5
-rw-r--r--sys/netinet/sctp_timer.c2
-rw-r--r--sys/netinet/sctp_usrreq.c3
-rw-r--r--sys/netinet/sctputil.c9
7 files changed, 106 insertions, 63 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index a091011..b66e1b2 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -872,6 +872,47 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
}
/*
+ * cleanup any cached source addresses that may be topologically
+ * incorrect after a new address has been added to this interface.
+ */
+static void
+sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
+{
+ struct sctp_nets *net;
+
+ /*
+ * Ideally, we want to only clear cached routes and source addresses
+ * that are topologically incorrect. But since there is no easy way
+ * to know whether the newly added address on the ifn would cause a
+ * routing change (i.e. a new egress interface would be chosen)
+ * without doing a new routing lookup and source address selection,
+ * we will (for now) just flush any cached route using a different
+ * ifn (and cached source addrs) and let output re-choose them
+ * during the next send on that net.
+ */
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ /*
+ * clear any cached route (and cached source address) if the
+ * route's interface is NOT the same as the address change.
+ * If it's the same interface, just clear the cached source
+ * address.
+ */
+ if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
+ SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index) {
+ /* clear any cached route */
+ RTFREE(net->ro.ro_rt);
+ net->ro.ro_rt = NULL;
+ }
+ /* clear any cached source address */
+ if (net->src_addr_selected) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ net->src_addr_selected = 0;
+ }
+ }
+}
+
+/*
* process an ADD/DELETE IP ack from peer.
* addr: corresponding sctp_ifa to the address being added/deleted.
* type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
@@ -883,8 +924,8 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
{
/*
* do the necessary asoc list work- if we get a failure indication,
- * leave the address on the "do not use" asoc list if we get a
- * success indication, remove the address from the list
+ * leave the address on the assoc's restricted list. If we get a
+ * success indication, remove the address from the restricted list.
*/
/*
* Note: this will only occur for ADD_IP_ADDRESS, since
@@ -893,6 +934,12 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
if (flag) {
/* success case, so remove from the restricted list */
sctp_del_local_addr_restricted(stcb, addr);
+
+ /*
+ * clear any cached, topologically incorrect source
+ * addresses
+ */
+ sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
}
/* else, leave it on the list */
}
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 5a278c1..46c23cd 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -2186,16 +2186,13 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
return (m);
}
oso = (*inp_p)->sctp_socket;
- /*
- * We do this to keep the sockets side happy durin
- * the sonewcon ONLY.
- */
+ atomic_add_int(&(*stcb)->asoc.refcnt, 1);
SCTP_TCB_UNLOCK((*stcb));
so = sonewconn(oso, 0
);
- SCTP_INP_WLOCK((*stcb)->sctp_ep);
SCTP_TCB_LOCK((*stcb));
- SCTP_INP_WUNLOCK((*stcb)->sctp_ep);
+ atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
+
if (so == NULL) {
struct mbuf *op_err;
@@ -3968,7 +3965,6 @@ process_control_chunks:
SCTP_TCB_UNLOCK(locked_tcb);
}
return (NULL);
-
}
if (netp && *netp) {
int abort_flag = 0;
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 7d12369..9e4f0f0 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -2692,11 +2692,11 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
uint32_t ifn_index;
struct sctp_vrf *vrf;
- /*
- * For boundall we can use any address in the association. If
- * non_asoc_addr_ok is set we can use any address (at least in
- * theory). So we look for preferred addresses first. If we find
- * one, we use it. Otherwise we next try to get an address on the
+ /*-
+ * For boundall we can use any address in the association.
+ * If non_asoc_addr_ok is set we can use any address (at least in
+ * theory). So we look for preferred addresses first. If we find one,
+ * we use it. Otherwise we next try to get an address on the
* interface, which we should be able to do (unless non_asoc_addr_ok
* is false and we are routed out that way). In these cases where we
* can't use the address of the interface we go through all the
@@ -2898,43 +2898,51 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
struct sctp_nets *net,
int non_asoc_addr_ok, uint32_t vrf_id)
{
-
struct sockaddr_in *to = (struct sockaddr_in *)&ro->ro_dst;
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst;
struct sctp_ifa *answer;
uint8_t dest_is_priv, dest_is_loop;
sa_family_t fam;
- /*
+ /*-
* Rules: - Find the route if needed, cache if I can. - Look at
* interface address in route, Is it in the bound list. If so we
* have the best source. - If not we must rotate amongst the
* addresses.
- *
+ *
* Cavets and issues
- *
+ *
* Do we need to pay attention to scope. We can have a private address
* or a global address we are sourcing or sending to. So if we draw
- * it out zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
- * For V4 ------------------------------------------ source *
- * dest * result ----------------------------------------- <a>
- * Private * Global * NAT
- * ----------------------------------------- <b> Private *
- * Private * No problem -----------------------------------------
- * <c> Global * Private * Huh, How will this work?
- * ----------------------------------------- <d> Global *
- * Global * No Problem ------------------------------------------
- * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz For V6
- * ------------------------------------------ source * dest *
- * result ----------------------------------------- <a> Linklocal *
- * Global * ----------------------------------------- <b>
- * Linklocal * Linklocal * No problem
- * ----------------------------------------- <c> Global *
- * Linklocal * Huh, How will this work?
- * ----------------------------------------- <d> Global *
- * Global * No Problem ------------------------------------------
+ * it out
* zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
- *
+ * For V4
+ *------------------------------------------
+ * source * dest * result
+ * -----------------------------------------
+ * <a> Private * Global * NAT
+ * -----------------------------------------
+ * <b> Private * Private * No problem
+ * -----------------------------------------
+ * <c> Global * Private * Huh, How will this work?
+ * -----------------------------------------
+ * <d> Global * Global * No Problem
+ *------------------------------------------
+ * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+ * For V6
+ *------------------------------------------
+ * source * dest * result
+ * -----------------------------------------
+ * <a> Linklocal * Global *
+ * -----------------------------------------
+ * <b> Linklocal * Linklocal * No problem
+ * -----------------------------------------
+ * <c> Global * Linklocal * Huh, How will this work?
+ * -----------------------------------------
+ * <d> Global * Global * No Problem
+ *------------------------------------------
+ * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
+ *
* And then we add to that what happens if there are multiple addresses
* assigned to an interface. Remember the ifa on a ifn is a linked
* list of addresses. So one interface can have more than one IP
@@ -2943,18 +2951,20 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
* one is best? And what about NAT's sending P->G may get you a NAT
* translation, or should you select the G thats on the interface in
* preference.
- *
+ *
* Decisions:
- *
- * - count the number of addresses on the interface. - if it is one, no
- * problem except case <c>. For <a> we will assume a NAT out there.
+ *
+ * - count the number of addresses on the interface.
+ * - if it is one, no problem except case <c>.
+ * For <a> we will assume a NAT out there.
* - if there are more than one, then we need to worry about scope P
- * or G. We should prefer G -> G and P -> P if possible. Then as a
- * secondary fall back to mixed types G->P being a last ditch one. -
- * The above all works for bound all, but bound specific we need to
- * use the same concept but instead only consider the bound
- * addresses. If the bound set is NOT assigned to the interface then
- * we must use rotation amongst the bound addresses..
+ * or G. We should prefer G -> G and P -> P if possible.
+ * Then as a secondary fall back to mixed types G->P being a last
+ * ditch one.
+ * - The above all works for bound all, but bound specific we need to
+ * use the same concept but instead only consider the bound
+ * addresses. If the bound set is NOT assigned to the interface then
+ * we must use rotation amongst the bound addresses..
*/
if (ro->ro_rt == NULL) {
/*
@@ -11535,7 +11545,6 @@ sctp_lower_sosend(struct socket *so,
if ((net->flight_size > net->cwnd) &&
(sctp_cmt_on_off == 0)) {
queue_only = 1;
-
} else if (asoc->ifp_had_enobuf) {
SCTP_STAT_INCR(sctps_ifnomemqueued);
if (net->flight_size > (net->mtu * 2)) {
@@ -11624,7 +11633,6 @@ sctp_lower_sosend(struct socket *so,
sctp_chunk_output(inp,
stcb,
SCTP_OUTPUT_FROM_USR_SEND);
-
}
} else {
sctp_chunk_output(inp,
@@ -11835,7 +11843,6 @@ skip_out_eof:
(stcb->asoc.total_flight > 0) &&
(un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))
) {
-
/*-
* Ok, Nagle is set on and we have data outstanding.
* Don't send anything and let SACKs drive out the
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index df6689f..b4c2def 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -1263,7 +1263,6 @@ sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
/* Find the head of the ALLADDR chain */
if (have_lock == 0) {
SCTP_INP_INFO_RLOCK();
-
}
head = &sctppcbinfo.sctp_ephash[SCTP_PCBHASH_ALLADDR(lport,
sctppcbinfo.hashmark)];
@@ -3785,7 +3784,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)) {
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) {
/*
* Need to add a PD-API
* aborted indication.
@@ -3917,7 +3916,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
LIST_REMOVE(stcb, sctp_asocs);
sctp_add_vtag_to_timewait(inp, asoc->my_vtag, SCTP_TIME_WAIT);
-
/*
* Now restop the timers to be sure - this is paranoia at is finest!
*/
@@ -3929,7 +3927,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
(void)SCTP_OS_TIMER_STOP(&asoc->shut_guard_timer.timer);
(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);
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index 75214ed..47720d3 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -478,7 +478,6 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
if (alt->ro._s_addr) {
sctp_free_ifa(alt->ro._s_addr);
alt->ro._s_addr = NULL;
-
}
alt->src_addr_selected = 0;
}
@@ -967,7 +966,6 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
*/
net->find_pseudo_cumack = 1;
net->find_rtx_pseudo_cumack = 1;
-
} else { /* CMT is OFF */
alt = sctp_find_alternate_net(stcb, net, 0);
}
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 54b31b53..fa2b922 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -1119,7 +1119,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
- actual += sizeof(sizeof(struct sockaddr_in6));
+ actual += sizeof(struct sockaddr_in6);
} else {
memcpy(sas, sin, sizeof(*sin));
((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
@@ -3480,7 +3480,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sasoc->sasoc_local_rwnd = 0;
if (sasoc->sasoc_cookie_life) {
stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
-
}
SCTP_TCB_UNLOCK(stcb);
} else {
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 573c3d3..e7e0987 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1163,7 +1163,6 @@ sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
uint8_t *new_array;
uint32_t new_size;
-
new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR);
SCTP_MALLOC(new_array, uint8_t *, new_size, SCTP_M_MAP);
if (new_array == NULL) {
@@ -3146,15 +3145,16 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
/* This always must be called with the read-queue LOCKED in the INP */
void
-sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
- uint32_t error, int nolock, uint32_t val)
+sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
+ int nolock, uint32_t val)
{
struct mbuf *m_notify;
struct sctp_pdapi_event *pdapi;
struct sctp_queued_to_read *control;
struct sockbuf *sb;
- if ((stcb == NULL) || sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT))
+ if ((stcb == NULL) || (stcb->sctp_socket == NULL) ||
+ sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT))
/* event not enabled */
return;
@@ -4484,7 +4484,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
uint32_t
sctp_get_ifa_hash_val(struct sockaddr *addr)
{
-
if (addr->sa_family == AF_INET) {
struct sockaddr_in *sin;
OpenPOWER on IntegriCloud