Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Sep 2010 23:10:45 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r212712 - head/sys/netinet
Message-ID:  <201009152310.o8FNAjbX053895@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Wed Sep 15 23:10:45 2010
New Revision: 212712
URL: http://svn.freebsd.org/changeset/base/212712

Log:
  Delay the assignment of a path for DATA chunk until they hit
  the sent_queue. Honor a given path when the SCTP_ADDR_OVER
  flag is set.
  
  MFC after: 2 weeks.

Modified:
  head/sys/netinet/sctp_asconf.c
  head/sys/netinet/sctp_asconf.h
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_output.h
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_timer.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp_asconf.c
==============================================================================
--- head/sys/netinet/sctp_asconf.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_asconf.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -581,8 +581,8 @@ sctp_process_asconf_set_primary(struct m
 			}
 			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
 			    SCTP_MOBILITY_BASE)) {
-				sctp_move_chunks_from_deleted_prim(stcb,
-				    stcb->asoc.primary_destination);
+				sctp_move_chunks_from_net(stcb,
+				    stcb->asoc.deleted_primary);
 			}
 			sctp_delete_prim_timer(stcb->sctp_ep, stcb,
 			    stcb->asoc.deleted_primary);
@@ -1041,47 +1041,6 @@ sctp_asconf_nets_cleanup(struct sctp_tcb
 	}
 }
 
-void
-sctp_move_chunks_from_deleted_prim(struct sctp_tcb *stcb, struct sctp_nets *dst)
-{
-	struct sctp_association *asoc;
-	struct sctp_stream_out *outs;
-	struct sctp_tmit_chunk *chk;
-	struct sctp_stream_queue_pending *sp;
-
-	if (dst->dest_state & SCTP_ADDR_UNCONFIRMED) {
-		return;
-	}
-	if (stcb->asoc.deleted_primary == NULL) {
-		return;
-	}
-	asoc = &stcb->asoc;
-
-	/*
-	 * now through all the streams checking for chunks sent to our bad
-	 * network.
-	 */
-	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
-		/* now clean up any chunks here */
-		TAILQ_FOREACH(sp, &outs->outqueue, next) {
-			if (sp->net == asoc->deleted_primary) {
-				sctp_free_remote_addr(sp->net);
-				sp->net = dst;
-				atomic_add_int(&dst->ref_count, 1);
-			}
-		}
-	}
-	/* Now check the pending queue */
-	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
-		if (chk->whoTo == asoc->deleted_primary) {
-			sctp_free_remote_addr(chk->whoTo);
-			chk->whoTo = dst;
-			atomic_add_int(&dst->ref_count, 1);
-		}
-	}
-
-}
-
 
 void
 sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
@@ -2080,13 +2039,11 @@ sctp_asconf_iterator_ep(struct sctp_inpc
 	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) {

Modified: head/sys/netinet/sctp_asconf.h
==============================================================================
--- head/sys/netinet/sctp_asconf.h	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_asconf.h	Wed Sep 15 23:10:45 2010	(r212712)
@@ -80,8 +80,6 @@ sctp_check_address_list(struct sctp_tcb 
     struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t);
 
 extern void
-     sctp_move_chunks_from_deleted_prim(struct sctp_tcb *, struct sctp_nets *);
-extern void
      sctp_assoc_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);
 extern void
      sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_input.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -232,7 +232,10 @@ sctp_is_there_unsent_data(struct sctp_tc
 				}
 				atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
 				TAILQ_REMOVE(&strq->outqueue, sp, next);
-				sctp_free_remote_addr(sp->net);
+				if (sp->net) {
+					sctp_free_remote_addr(sp->net);
+					sp->net = NULL;
+				}
 				if (sp->data) {
 					sctp_m_freem(sp->data);
 					sp->data = NULL;
@@ -263,7 +266,7 @@ sctp_process_init(struct sctp_init_chunk
 	/* save off parameters */
 	asoc->peer_vtag = ntohl(init->initiate_tag);
 	asoc->peers_rwnd = ntohl(init->a_rwnd);
-	if (TAILQ_FIRST(&asoc->nets)) {
+	if (!TAILQ_EMPTY(&asoc->nets)) {
 		/* update any ssthresh's that may have a default */
 		TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) {
 			lnet->ssthresh = asoc->peers_rwnd;
@@ -318,8 +321,10 @@ sctp_process_init(struct sctp_init_chunk
 						sctp_m_freem(sp->data);
 						sp->data = NULL;
 					}
-					sctp_free_remote_addr(sp->net);
-					sp->net = NULL;
+					if (sp->net) {
+						sctp_free_remote_addr(sp->net);
+						sp->net = NULL;
+					}
 					/* Free the chunk */
 					sctp_free_a_strmoq(stcb, sp);
 					/* sa_ignore FREED_MEMORY */
@@ -650,8 +655,8 @@ sctp_handle_heartbeat_ack(struct sctp_he
 			}
 			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
 			    SCTP_MOBILITY_BASE)) {
-				sctp_move_chunks_from_deleted_prim(stcb,
-				    stcb->asoc.primary_destination);
+				sctp_move_chunks_from_net(stcb,
+				    stcb->asoc.deleted_primary);
 			}
 			sctp_delete_prim_timer(stcb->sctp_ep, stcb,
 			    stcb->asoc.deleted_primary);

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_output.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -5911,10 +5911,10 @@ sctp_msg_append(struct sctp_tcb *stcb,
 	sp->strseq = 0;
 	if (sp->sinfo_flags & SCTP_ADDR_OVER) {
 		sp->net = net;
+		atomic_add_int(&sp->net->ref_count, 1);
 	} else {
-		sp->net = stcb->asoc.primary_destination;
+		sp->net = NULL;
 	}
-	atomic_add_int(&sp->net->ref_count, 1);
 	(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
 	sp->stream = srcv->sinfo_stream;
 	sp->msg_is_complete = 1;
@@ -6513,7 +6513,6 @@ sctp_toss_old_asconf(struct sctp_tcb *st
 
 static void
 sctp_clean_up_datalist(struct sctp_tcb *stcb,
-
     struct sctp_association *asoc,
     struct sctp_tmit_chunk **data_list,
     int bundle_at,
@@ -6524,7 +6523,9 @@ sctp_clean_up_datalist(struct sctp_tcb *
 
 	for (i = 0; i < bundle_at; i++) {
 		/* off of the send queue */
-		if (i) {
+		TAILQ_REMOVE(&asoc->send_queue, data_list[i], sctp_next);
+		asoc->send_queue_cnt--;
+		if (i > 0) {
 			/*
 			 * Any chunk NOT 0 you zap the time chunk 0 gets
 			 * zapped or set based on if a RTO measurment is
@@ -6535,9 +6536,10 @@ sctp_clean_up_datalist(struct sctp_tcb *
 		/* record time */
 		data_list[i]->sent_rcv_time = net->last_sent_time;
 		data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.TSN_seq;
-		TAILQ_REMOVE(&asoc->send_queue,
-		    data_list[i],
-		    sctp_next);
+		if (data_list[i]->whoTo == NULL) {
+			data_list[i]->whoTo = net;
+			atomic_add_int(&net->ref_count, 1);
+		}
 		/* on to the sent queue */
 		tp1 = TAILQ_LAST(&asoc->sent_queue, sctpchunk_listhead);
 		if ((tp1) && (compare_with_wrap(tp1->rec.data.TSN_seq,
@@ -6565,7 +6567,6 @@ sctp_clean_up_datalist(struct sctp_tcb *
 all_done:
 		/* This does not lower until the cum-ack passes it */
 		asoc->sent_queue_cnt++;
-		asoc->send_queue_cnt--;
 		if ((asoc->peers_rwnd <= 0) &&
 		    (asoc->total_flight == 0) &&
 		    (bundle_at == 1)) {
@@ -6703,7 +6704,7 @@ sctp_can_we_split_this(struct sctp_tcb *
 }
 
 static uint32_t
-sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
+sctp_move_to_outqueue(struct sctp_tcb *stcb,
     struct sctp_stream_out *strq,
     uint32_t goal_mtu,
     uint32_t frag_point,
@@ -6772,7 +6773,10 @@ one_more_time:
 			}
 			atomic_subtract_int(&asoc->stream_queue_cnt, 1);
 			TAILQ_REMOVE(&strq->outqueue, sp, next);
-			sctp_free_remote_addr(sp->net);
+			if (sp->net) {
+				sctp_free_remote_addr(sp->net);
+				sp->net = NULL;
+			}
 			if (sp->data) {
 				sctp_m_freem(sp->data);
 				sp->data = NULL;
@@ -7089,8 +7093,11 @@ dont_do_it:
 	chk->rec.data.timetodrop = sp->ts;
 	chk->flags = sp->act_flags;
 
-	chk->whoTo = net;
-	atomic_add_int(&chk->whoTo->ref_count, 1);
+	if (sp->net) {
+		chk->whoTo = sp->net;
+		atomic_add_int(&chk->whoTo->ref_count, 1);
+	} else
+		chk->whoTo = NULL;
 
 	if (sp->holds_key_ref) {
 		chk->auth_keyid = sp->auth_keyid;
@@ -7175,7 +7182,10 @@ dont_do_it:
 			send_lock_up = 1;
 		}
 		TAILQ_REMOVE(&strq->outqueue, sp, next);
-		sctp_free_remote_addr(sp->net);
+		if (sp->net) {
+			sctp_free_remote_addr(sp->net);
+			sp->net = NULL;
+		}
 		if (sp->data) {
 			sctp_m_freem(sp->data);
 			sp->data = NULL;
@@ -7248,31 +7258,29 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
 	goal_mtu &= 0xfffffffc;
 	if (asoc->locked_on_sending) {
 		/* We are stuck on one stream until the message completes. */
-		strqn = strq = asoc->locked_on_sending;
+		strq = asoc->locked_on_sending;
 		locked = 1;
 	} else {
-		strqn = strq = sctp_select_a_stream(stcb, asoc);
+		strq = sctp_select_a_stream(stcb, asoc);
 		locked = 0;
 	}
-
+	strqn = strq;
 	while ((goal_mtu > 0) && strq) {
 		sp = TAILQ_FIRST(&strq->outqueue);
-		/*
-		 * If CMT is off, we must validate that the stream in
-		 * question has the first item pointed towards are network
-		 * destionation requested by the caller. Note that if we
-		 * turn out to be locked to a stream (assigning TSN's then
-		 * we must stop, since we cannot look for another stream
-		 * with data to send to that destination). In CMT's case, by
-		 * skipping this check, we will send one data packet towards
-		 * the requested net.
-		 */
 		if (sp == NULL) {
 			break;
 		}
-		if ((sp->net != net) &&
-		    (asoc->sctp_cmt_on_off == 0)) {
-			/* none for this network */
+		/**
+		 * Honor the users' choice if given. If not given,
+		 * pull it only to the primary path in case of not using
+		 * CMT.
+		 */
+		if (((sp->net != NULL) &&
+		    (sp->net != net)) ||
+		    ((sp->net == NULL) &&
+		    (asoc->sctp_cmt_on_off == 0) &&
+		    (asoc->primary_destination != net))) {
+			/* Do not pull to this network */
 			if (locked) {
 				break;
 			} else {
@@ -7289,7 +7297,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
 		}
 		giveup = 0;
 		bail = 0;
-		moved_how_much = sctp_move_to_outqueue(stcb, net, strq, goal_mtu, frag_point, &locked,
+		moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked,
 		    &giveup, eeor_mode, &bail);
 		if (moved_how_much)
 			asoc->last_out_stream = strq;
@@ -7353,43 +7361,32 @@ sctp_fix_ecn_echo(struct sctp_associatio
 	}
 }
 
-static void
-sctp_move_to_an_alt(struct sctp_tcb *stcb,
-    struct sctp_association *asoc,
-    struct sctp_nets *net)
+void
+sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net)
 {
+	struct sctp_association *asoc;
+	struct sctp_stream_out *outs;
 	struct sctp_tmit_chunk *chk;
-	struct sctp_nets *a_net;
+	struct sctp_stream_queue_pending *sp;
 
-	SCTP_TCB_LOCK_ASSERT(stcb);
-	/*
-	 * JRS 5/14/07 - If CMT PF is turned on, find an alternate
-	 * destination using the PF algorithm for finding alternate
-	 * destinations.
-	 */
-	if ((asoc->sctp_cmt_on_off == 1) &&
-	    (asoc->sctp_cmt_pf > 0)) {
-		a_net = sctp_find_alternate_net(stcb, net, 2);
-	} else {
-		a_net = sctp_find_alternate_net(stcb, net, 0);
+	if (net == NULL) {
+		return;
 	}
-	if ((a_net != net) &&
-	    ((a_net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE)) {
-		/*
-		 * We only proceed if a valid alternate is found that is not
-		 * this one and is reachable. Here we must move all chunks
-		 * queued in the send queue off of the destination address
-		 * to our alternate.
-		 */
-		TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
-			if (chk->whoTo == net) {
-				/* Move the chunk to our alternate */
-				sctp_free_remote_addr(chk->whoTo);
-				chk->whoTo = a_net;
-				atomic_add_int(&a_net->ref_count, 1);
+	asoc = &stcb->asoc;
+	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
+		TAILQ_FOREACH(sp, &outs->outqueue, next) {
+			if (sp->net == net) {
+				sctp_free_remote_addr(sp->net);
+				sp->net = NULL;
 			}
 		}
 	}
+	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
+		if (chk->whoTo == net) {
+			sctp_free_remote_addr(chk->whoTo);
+			chk->whoTo = NULL;
+		}
+	}
 }
 
 int
@@ -7497,7 +7494,8 @@ sctp_med_chunk_output(struct sctp_inpcb 
 			 * copy by reference (we hope).
 			 */
 			net->window_probe = 0;
-			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
+			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ||
+			    (net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
 					sctp_log_cwnd(stcb, net, 1,
 					    SCTP_CWND_LOG_FILL_OUTQ_CALLED);
@@ -7505,6 +7503,7 @@ sctp_med_chunk_output(struct sctp_inpcb 
 				continue;
 			}
 			if ((asoc->sctp_cmt_on_off == 0) &&
+			    (asoc->primary_destination != net) &&
 			    (net->ref_count < 2)) {
 				/* nothing can be in queue for this guy */
 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@@ -7534,9 +7533,9 @@ sctp_med_chunk_output(struct sctp_inpcb 
 	}
 	/* now service each destination and send out what we can for it */
 	/* Nothing to send? */
-	if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) &&
-	    (TAILQ_FIRST(&asoc->asconf_send_queue) == NULL) &&
-	    (TAILQ_FIRST(&asoc->send_queue) == NULL)) {
+	if (TAILQ_EMPTY(&asoc->control_send_queue) &&
+	    TAILQ_EMPTY(&asoc->asconf_send_queue) &&
+	    TAILQ_EMPTY(&asoc->send_queue)) {
 		*reason_code = 8;
 		return (0);
 	}
@@ -7566,15 +7565,17 @@ again_one_more_time:
 			break;
 		}
 		tsns_sent = 0xa;
-		if ((asoc->sctp_cmt_on_off == 0) && (net->ref_count < 2)) {
+		if ((asoc->sctp_cmt_on_off == 0) &&
+		    (asoc->primary_destination != net) &&
+		    (net->ref_count < 2)) {
 			/*
 			 * Ref-count of 1 so we cannot have data or control
 			 * queued to this address. Skip it (non-CMT).
 			 */
 			continue;
 		}
-		if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) &&
-		    (TAILQ_FIRST(&asoc->asconf_send_queue) == NULL) &&
+		if (TAILQ_EMPTY(&asoc->control_send_queue) &&
+		    TAILQ_EMPTY(&asoc->asconf_send_queue) &&
 		    (net->flight_size >= net->cwnd)) {
 			/*
 			 * Nothing on control or asconf and flight is full,
@@ -7778,7 +7779,7 @@ again_one_more_time:
 							 * unreachable
 							 * during this send
 							 */
-							sctp_move_to_an_alt(stcb, asoc, net);
+							sctp_move_chunks_from_net(stcb, net);
 						}
 						*reason_code = 7;
 						continue;
@@ -8001,7 +8002,7 @@ again_one_more_time:
 							 * unreachable
 							 * during this send
 							 */
-							sctp_move_to_an_alt(stcb, asoc, net);
+							sctp_move_chunks_from_net(stcb, net);
 						}
 						*reason_code = 7;
 						continue;
@@ -8102,19 +8103,9 @@ again_one_more_time:
 					break;
 				}
 				nchk = TAILQ_NEXT(chk, sctp_next);
-				if (asoc->sctp_cmt_on_off == 1) {
-					if (chk->whoTo != net) {
-						/*
-						 * For CMT, steal the data
-						 * to this network if its
-						 * not set here.
-						 */
-						sctp_free_remote_addr(chk->whoTo);
-						chk->whoTo = net;
-						atomic_add_int(&chk->whoTo->ref_count, 1);
-					}
-				} else if (chk->whoTo != net) {
-					/* No, not sent to this net */
+				if ((chk->whoTo != NULL) &&
+				    (chk->whoTo != net)) {
+					/* Don't send the chunk on this net */
 					continue;
 				}
 				if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) {
@@ -8330,7 +8321,7 @@ no_data_fill:
 					 * Destination went unreachable
 					 * during this send
 					 */
-					sctp_move_to_an_alt(stcb, asoc, net);
+					sctp_move_chunks_from_net(stcb, net);
 				}
 				*reason_code = 6;
 				/*-
@@ -9584,7 +9575,7 @@ sctp_chunk_output(struct sctp_inpcb *inp
 			 * out wheel to this alternate address.
 			 */
 			if (net->ref_count > 1)
-				sctp_move_to_an_alt(stcb, asoc, net);
+				sctp_move_chunks_from_net(stcb, net);
 		} else if ((asoc->sctp_cmt_on_off == 1) &&
 			    (asoc->sctp_cmt_pf > 0) &&
 		    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
@@ -9594,7 +9585,7 @@ sctp_chunk_output(struct sctp_inpcb *inp
 			 * to an alternate desination.
 			 */
 			if (net->ref_count > 1)
-				sctp_move_to_an_alt(stcb, asoc, net);
+				sctp_move_chunks_from_net(stcb, net);
 		} else {
 			/*-
 			 * if ((asoc->sat_network) || (net->addr_is_local))
@@ -12103,10 +12094,10 @@ skip_copy:
 	} else {
 		if (sp->sinfo_flags & SCTP_ADDR_OVER) {
 			sp->net = net;
+			atomic_add_int(&sp->net->ref_count, 1);
 		} else {
-			sp->net = asoc->primary_destination;
+			sp->net = NULL;
 		}
-		atomic_add_int(&sp->net->ref_count, 1);
 		sctp_set_prsctp_policy(sp);
 	}
 out_now:

Modified: head/sys/netinet/sctp_output.h
==============================================================================
--- head/sys/netinet/sctp_output.h	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_output.h	Wed Sep 15 23:10:45 2010	(r212712)
@@ -129,6 +129,8 @@ void sctp_toss_old_asconf(struct sctp_tc
 
 void sctp_fix_ecn_echo(struct sctp_association *);
 
+void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net);
+
 int
 sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
     struct mbuf *, struct thread *, int);

Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_pcb.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -4843,7 +4843,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 					sp->tail_mbuf = NULL;
 				}
 			}
-			sctp_free_remote_addr(sp->net);
+			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);
@@ -4914,7 +4917,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 			if (chk->holds_key_ref)
 				sctp_auth_key_release(stcb, chk->auth_keyid);
 			ccnt++;
-			sctp_free_remote_addr(chk->whoTo);
+			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 */

Modified: head/sys/netinet/sctp_timer.c
==============================================================================
--- head/sys/netinet/sctp_timer.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctp_timer.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -969,46 +969,6 @@ start_again:
 	return (0);
 }
 
-static void
-sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb,
-    struct sctp_nets *net,
-    struct sctp_nets *alt)
-{
-	struct sctp_association *asoc;
-	struct sctp_stream_out *outs;
-	struct sctp_tmit_chunk *chk;
-	struct sctp_stream_queue_pending *sp;
-
-	if (net == alt)
-		/* nothing to do */
-		return;
-
-	asoc = &stcb->asoc;
-
-	/*
-	 * now through all the streams checking for chunks sent to our bad
-	 * network.
-	 */
-	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
-		/* now clean up any chunks here */
-		TAILQ_FOREACH(sp, &outs->outqueue, next) {
-			if (sp->net == net) {
-				sctp_free_remote_addr(sp->net);
-				sp->net = alt;
-				atomic_add_int(&alt->ref_count, 1);
-			}
-		}
-	}
-	/* Now check the pending queue */
-	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
-		if (chk->whoTo == net) {
-			sctp_free_remote_addr(chk->whoTo);
-			chk->whoTo = alt;
-			atomic_add_int(&alt->ref_count, 1);
-		}
-	}
-
-}
 
 int
 sctp_t3rxt_timer(struct sctp_inpcb *inp,
@@ -1141,7 +1101,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
 	}
 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
 		/* Move all pending over too */
-		sctp_move_all_chunks_to_alt(stcb, net, alt);
+		sctp_move_chunks_from_net(stcb, net);
 
 		/*
 		 * Get the address that failed, to force a new src address
@@ -1256,7 +1216,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp
 
 		alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0);
 		if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
-			sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt);
+			sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination);
 			stcb->asoc.primary_destination = alt;
 		}
 	}
@@ -1396,7 +1356,7 @@ sctp_strreset_timer(struct sctp_inpcb *i
 		 * If the address went un-reachable, we need to move to
 		 * alternates for ALL chk's in queue
 		 */
-		sctp_move_all_chunks_to_alt(stcb, net, alt);
+		sctp_move_chunks_from_net(stcb, net);
 	}
 	/* mark the retran info */
 	if (strrst->sent != SCTP_DATAGRAM_RESEND)
@@ -1487,8 +1447,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp
 			 * If the address went un-reachable, we need to move
 			 * to the alternate for ALL chunks in queue
 			 */
-			sctp_move_all_chunks_to_alt(stcb, net, alt);
-			net = alt;
+			sctp_move_chunks_from_net(stcb, net);
 		}
 		/* mark the retran info */
 		if (asconf->sent != SCTP_DATAGRAM_RESEND)

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c	Wed Sep 15 21:53:10 2010	(r212711)
+++ head/sys/netinet/sctputil.c	Wed Sep 15 23:10:45 2010	(r212712)
@@ -2500,7 +2500,6 @@ sctp_mtu_size_reset(struct sctp_inpcb *i
 	}
 	eff_mtu = mtu - ovh;
 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
-
 		if (chk->send_size > eff_mtu) {
 			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
 		}
@@ -3763,9 +3762,10 @@ sctp_report_all_outbound(struct sctp_tcb
 					sp->data = NULL;
 				}
 			}
-			if (sp->net)
+			if (sp->net) {
 				sctp_free_remote_addr(sp->net);
-			sp->net = NULL;
+				sp->net = NULL;
+			}
 			/* Free the chunk */
 			sctp_free_a_strmoq(stcb, sp);
 			/* sa_ignore FREED_MEMORY */
@@ -4818,7 +4818,10 @@ next_on_sent:
 					chk->rec.data.payloadtype = sp->ppid;
 					chk->rec.data.context = sp->context;
 					chk->flags = sp->act_flags;
-					chk->whoTo = sp->net;
+					if (sp->net)
+						chk->whoTo = sp->net;
+					else
+						chk->whoTo = stcb->asoc.primary_destination;
 					atomic_add_int(&chk->whoTo->ref_count, 1);
 					chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
 					stcb->asoc.pr_sctp_cnt++;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009152310.o8FNAjbX053895>