Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Aug 2011 20:21:00 +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: r224641 - in head: lib/libc/net sys/netinet sys/netinet6
Message-ID:  <201108032021.p73KL0sH028281@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tuexen
Date: Wed Aug  3 20:21:00 2011
New Revision: 224641
URL: http://svn.freebsd.org/changeset/base/224641

Log:
  The result of a joint work between rrs@ and myself at the IETF:
  * Decouple the path supervision using a separate HB timer per path.
  * Add support for potentially failed state.
  * Bring back RTO.min to 1 second.
  * Accept packets on IP-addresses already announced via an ASCONF
  * While there: do some cleanups.
  
  Approved by: re@
  MFC after: 2 months.

Modified:
  head/lib/libc/net/sctp_sys_calls.c
  head/sys/netinet/sctp.h
  head/sys/netinet/sctp_asconf.c
  head/sys/netinet/sctp_cc_functions.c
  head/sys/netinet/sctp_constants.h
  head/sys/netinet/sctp_header.h
  head/sys/netinet/sctp_indata.c
  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_pcb.h
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_sysctl.c
  head/sys/netinet/sctp_sysctl.h
  head/sys/netinet/sctp_timer.c
  head/sys/netinet/sctp_timer.h
  head/sys/netinet/sctp_uio.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctp_var.h
  head/sys/netinet/sctputil.c
  head/sys/netinet6/sctp6_usrreq.c

Modified: head/lib/libc/net/sctp_sys_calls.c
==============================================================================
--- head/lib/libc/net/sctp_sys_calls.c	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/lib/libc/net/sctp_sys_calls.c	Wed Aug  3 20:21:00 2011	(r224641)
@@ -410,6 +410,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, i
 	case SCTP_DEFAULT_PRINFO:
 		((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
 		break;
+	case SCTP_PEER_ADDR_THLDS:
+		((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
+		break;
 	case SCTP_MAX_BURST:
 		((struct sctp_assoc_value *)arg)->assoc_id = id;
 		break;

Modified: head/sys/netinet/sctp.h
==============================================================================
--- head/sys/netinet/sctp.h	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp.h	Wed Aug  3 20:21:00 2011	(r224641)
@@ -119,6 +119,7 @@ struct sctp_paramhdr {
 #define SCTP_RECVNXTINFO                0x00000020
 #define SCTP_DEFAULT_SNDINFO            0x00000021
 #define SCTP_DEFAULT_PRINFO             0x00000022
+#define SCTP_PEER_ADDR_THLDS            0x00000023
 
 /*
  * read-only options
@@ -564,7 +565,6 @@ struct sctp_error_unrecognized_chunk {
 #define SCTP_BLK_LOGGING_ENABLE				0x00000001
 #define SCTP_CWND_MONITOR_ENABLE			0x00000002
 #define SCTP_CWND_LOGGING_ENABLE			0x00000004
-#define SCTP_EARLYFR_LOGGING_ENABLE			0x00000010
 #define SCTP_FLIGHT_LOGGING_ENABLE			0x00000020
 #define SCTP_FR_LOGGING_ENABLE				0x00000040
 #define SCTP_LOCK_LOGGING_ENABLE			0x00000080
@@ -572,23 +572,23 @@ struct sctp_error_unrecognized_chunk {
 #define SCTP_MBCNT_LOGGING_ENABLE			0x00000200
 #define SCTP_MBUF_LOGGING_ENABLE			0x00000400
 #define SCTP_NAGLE_LOGGING_ENABLE			0x00000800
-#define SCTP_RECV_RWND_LOGGING_ENABLE		0x00001000
+#define SCTP_RECV_RWND_LOGGING_ENABLE			0x00001000
 #define SCTP_RTTVAR_LOGGING_ENABLE			0x00002000
 #define SCTP_SACK_LOGGING_ENABLE			0x00004000
-#define SCTP_SACK_RWND_LOGGING_ENABLE		0x00008000
+#define SCTP_SACK_RWND_LOGGING_ENABLE			0x00008000
 #define SCTP_SB_LOGGING_ENABLE				0x00010000
 #define SCTP_STR_LOGGING_ENABLE				0x00020000
 #define SCTP_WAKE_LOGGING_ENABLE			0x00040000
 #define SCTP_LOG_MAXBURST_ENABLE			0x00080000
 #define SCTP_LOG_RWND_ENABLE    			0x00100000
-#define SCTP_LOG_SACK_ARRIVALS_ENABLE       0x00200000
-#define SCTP_LTRACE_CHUNK_ENABLE            0x00400000
-#define SCTP_LTRACE_ERROR_ENABLE            0x00800000
-#define SCTP_LAST_PACKET_TRACING            0x01000000
-#define SCTP_THRESHOLD_LOGGING              0x02000000
-#define SCTP_LOG_AT_SEND_2_SCTP             0x04000000
-#define SCTP_LOG_AT_SEND_2_OUTQ             0x08000000
-#define SCTP_LOG_TRY_ADVANCE                0x10000000
+#define SCTP_LOG_SACK_ARRIVALS_ENABLE			0x00200000
+#define SCTP_LTRACE_CHUNK_ENABLE			0x00400000
+#define SCTP_LTRACE_ERROR_ENABLE			0x00800000
+#define SCTP_LAST_PACKET_TRACING			0x01000000
+#define SCTP_THRESHOLD_LOGGING				0x02000000
+#define SCTP_LOG_AT_SEND_2_SCTP				0x04000000
+#define SCTP_LOG_AT_SEND_2_OUTQ				0x08000000
+#define SCTP_LOG_TRY_ADVANCE				0x10000000
 
 
 #undef SCTP_PACKED

Modified: head/sys/netinet/sctp_asconf.c
==============================================================================
--- head/sys/netinet/sctp_asconf.c	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp_asconf.c	Wed Aug  3 20:21:00 2011	(r224641)
@@ -198,8 +198,9 @@ sctp_asconf_error_response(uint32_t id, 
 
 static struct mbuf *
 sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
-    struct sctp_tcb *stcb, int response_required)
+    struct sctp_tcb *stcb, int send_hb, int response_required)
 {
+	struct sctp_nets *net;
 	struct mbuf *m_reply = NULL;
 	struct sockaddr_storage sa_source, sa_store;
 	struct sctp_paramhdr *ph;
@@ -284,7 +285,7 @@ sctp_process_asconf_add_ip(struct mbuf *
 		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
 	}
 	/* add the address */
-	if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE,
+	if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
 	    SCTP_ADDR_DYNAMIC_ADDED) != 0) {
 		SCTPDBG(SCTP_DEBUG_ASCONF1,
 		    "process_asconf_add_ip: error adding address\n");
@@ -298,10 +299,12 @@ sctp_process_asconf_add_ip(struct mbuf *
 			m_reply =
 			    sctp_asconf_success_response(aph->correlation_id);
 		}
-		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_PATHMTURAISE, stcb->sctp_ep, stcb, net);
 		sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
-		    stcb, NULL);
+		    stcb, net);
+		if (send_hb) {
+			sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
+		}
 	}
 	return m_reply;
 }
@@ -554,7 +557,12 @@ sctp_process_asconf_set_primary(struct m
 		    "process_asconf_set_primary: primary address set\n");
 		/* notify upper layer */
 		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
-
+		if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
+		    (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
+		    (stcb->asoc.alternate)) {
+			sctp_free_remote_addr(stcb->asoc.alternate);
+			stcb->asoc.alternate = NULL;
+		}
 		if (response_required) {
 			m_reply = sctp_asconf_success_response(aph->correlation_id);
 		}
@@ -622,7 +630,7 @@ sctp_handle_asconf(struct mbuf *m, unsig
 	struct sctp_asconf_ack_chunk *ack_cp;
 	struct sctp_asconf_paramhdr *aph, *ack_aph;
 	struct sctp_ipv6addr_param *p_addr;
-	unsigned int asconf_limit;
+	unsigned int asconf_limit, cnt;
 	int error = 0;		/* did an error occur? */
 
 	/* asconf param buffer */
@@ -717,6 +725,7 @@ sctp_handle_asconf(struct mbuf *m, unsig
 		goto send_reply;
 	}
 	/* process through all parameters */
+	cnt = 0;
 	while (aph != NULL) {
 		unsigned int param_length, param_type;
 
@@ -749,7 +758,8 @@ sctp_handle_asconf(struct mbuf *m, unsig
 		case SCTP_ADD_IP_ADDRESS:
 			asoc->peer_supports_asconf = 1;
 			m_result = sctp_process_asconf_add_ip(m, aph, stcb,
-			    error);
+			    (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
+			cnt++;
 			break;
 		case SCTP_DEL_IP_ADDRESS:
 			asoc->peer_supports_asconf = 1;
@@ -1959,7 +1969,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *
 	int status;
 
 
-	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
+	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
 	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
 		/* subset bound, no ASCONF allowed case, so ignore */
 		return;
@@ -2075,8 +2085,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *
 				sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
 				    stcb, stcb->asoc.primary_destination);
 #else
-				sctp_send_asconf(stcb, stcb->asoc.primary_destination,
-				    addr_locked);
+				sctp_send_asconf(stcb, NULL, addr_locked);
 #endif
 			}
 		}
@@ -2328,8 +2337,7 @@ sctp_asconf_iterator_stcb(struct sctp_in
 	 * 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_ADDR_NOT_LOCKED);
+		sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
 	}
 }
 
@@ -2384,8 +2392,7 @@ sctp_set_primary_ip_address_sa(struct sc
 			    stcb->sctp_ep, stcb,
 			    stcb->asoc.primary_destination);
 #else
-			sctp_send_asconf(stcb, stcb->asoc.primary_destination,
-			    SCTP_ADDR_NOT_LOCKED);
+			sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
 #endif
 		}
 	} else {
@@ -2421,8 +2428,7 @@ sctp_set_primary_ip_address(struct sctp_
 					    stcb->sctp_ep, stcb,
 					    stcb->asoc.primary_destination);
 #else
-					sctp_send_asconf(stcb, stcb->asoc.primary_destination,
-					    SCTP_ADDR_NOT_LOCKED);
+					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
 #endif
 				}
 			}
@@ -2965,8 +2971,7 @@ sctp_process_initack_addresses(struct sc
 					    stcb->sctp_ep, stcb,
 					    stcb->asoc.primary_destination);
 #else
-					sctp_send_asconf(stcb, stcb->asoc.primary_destination,
-					    SCTP_ADDR_NOT_LOCKED);
+					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
 #endif
 				}
 			}
@@ -3540,5 +3545,5 @@ sctp_asconf_send_nat_state_update(struct
 	}
 skip_rest:
 	/* Now we must send the asconf into the queue */
-	sctp_send_asconf(stcb, net, 0);
+	sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
 }

Modified: head/sys/netinet/sctp_cc_functions.c
==============================================================================
--- head/sys/netinet/sctp_cc_functions.c	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp_cc_functions.c	Wed Aug  3 20:21:00 2011	(r224641)
@@ -728,40 +728,6 @@ sctp_cwnd_update_after_sack_common(struc
 			}
 		}
 #endif
-		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
-			/*
-			 * So, first of all do we need to have a Early FR
-			 * timer running?
-			 */
-			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
-			    (net->ref_count > 1) &&
-			    (net->flight_size < net->cwnd)) ||
-			    (reneged_all)) {
-				/*
-				 * yes, so in this case stop it if its
-				 * running, and then restart it. Reneging
-				 * all is a special case where we want to
-				 * run the Early FR timer and then force the
-				 * last few unacked to be sent, causing us
-				 * to illicit a sack with gaps to force out
-				 * the others.
-				 */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
-				}
-				SCTP_STAT_INCR(sctps_earlyfrstrid);
-				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
-			} else {
-				/* No, stop it if its running */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
-				}
-			}
-		}
 		/* if nothing was acked on this destination skip it */
 		if (net->net_ack == 0) {
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@@ -769,51 +735,6 @@ sctp_cwnd_update_after_sack_common(struc
 			}
 			continue;
 		}
-		if (net->net_ack2 > 0) {
-			/*
-			 * Karn's rule applies to clearing error count, this
-			 * is optional.
-			 */
-			net->error_count = 0;
-			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
-			    SCTP_ADDR_NOT_REACHABLE) {
-				/* addr came good */
-				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
-				net->dest_state |= SCTP_ADDR_REACHABLE;
-				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
-				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
-				/* now was it the primary? if so restore */
-				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
-					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
-				}
-			}
-			/*
-			 * JRS 5/14/07 - If CMT PF is on and the destination
-			 * is in PF state, set the destination to active
-			 * state and set the cwnd to one or two MTU's based
-			 * on whether PF1 or PF2 is being used.
-			 * 
-			 * Should we stop any running T3 timer here?
-			 */
-			if ((asoc->sctp_cmt_on_off > 0) &&
-			    (asoc->sctp_cmt_pf > 0) &&
-			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
-				net->dest_state &= ~SCTP_ADDR_PF;
-				old_cwnd = net->cwnd;
-				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
-				SDT_PROBE(sctp, cwnd, net, ack,
-				    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
-				    old_cwnd, net->cwnd);
-				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
-				    net, net->cwnd);
-				/*
-				 * Since the cwnd value is explicitly set,
-				 * skip the code that updates the cwnd
-				 * value.
-				 */
-				goto skip_cwnd_update;
-			}
-		}
 #ifdef JANA_CMT_FAST_RECOVERY
 		/*
 		 * CMT fast recovery code
@@ -833,7 +754,7 @@ sctp_cwnd_update_after_sack_common(struc
 			 * If we are in loss recovery we skip any cwnd
 			 * update
 			 */
-			goto skip_cwnd_update;
+			return;
 		}
 		/*
 		 * Did any measurements go on for this network?
@@ -856,7 +777,7 @@ sctp_cwnd_update_after_sack_common(struc
 			if (net->cc_mod.rtcc.lbw) {
 				if (cc_bw_limit(stcb, net, nbw)) {
 					/* Hold here, no update */
-					goto skip_cwnd_update;
+					continue;
 				}
 			} else {
 				uint64_t vtag, probepoint;
@@ -1049,27 +970,25 @@ sctp_cwnd_update_after_sack_common(struc
 				    SCTP_CWND_LOG_NO_CUMACK);
 			}
 		}
-skip_cwnd_update:
-		/*
-		 * NOW, according to Karn's rule do we need to restore the
-		 * RTO timer back? Check our net_ack2. If not set then we
-		 * have a ambiguity.. i.e. all data ack'd was sent to more
-		 * than one place.
-		 */
-		if (net->net_ack2) {
-			/* restore any doubled timers */
-			net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
-			if (net->RTO < stcb->asoc.minrto) {
-				net->RTO = stcb->asoc.minrto;
-			}
-			if (net->RTO > stcb->asoc.maxrto) {
-				net->RTO = stcb->asoc.maxrto;
-			}
-		}
 	}
 }
 
 static void
+sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net)
+{
+	int old_cwnd;
+
+	old_cwnd = net->cwnd;
+	net->cwnd = net->mtu;
+	SDT_PROBE(sctp, cwnd, net, ack,
+	    stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
+	    old_cwnd, net->cwnd);
+	SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
+	    net, net->cwnd);
+}
+
+
+static void
 sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
 {
 	int old_cwnd = net->cwnd;
@@ -1344,32 +1263,6 @@ sctp_cwnd_update_after_output(struct sct
 }
 
 static void
-sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
-    struct sctp_tcb *stcb, struct sctp_nets *net)
-{
-	int old_cwnd = net->cwnd;
-
-	sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
-	/*
-	 * make a small adjustment to cwnd and force to CA.
-	 */
-	if (net->cwnd > net->mtu)
-		/* drop down one MTU after sending */
-		net->cwnd -= net->mtu;
-	if (net->cwnd < net->ssthresh)
-		/* still in SS move to CA */
-		net->ssthresh = net->cwnd - 1;
-	SDT_PROBE(sctp, cwnd, net, fr,
-	    stcb->asoc.my_vtag,
-	    ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
-	    net,
-	    old_cwnd, net->cwnd);
-	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
-		sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
-	}
-}
-
-static void
 sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
     struct sctp_association *asoc,
     int accum_moved, int reneged_all, int will_exit)
@@ -1858,40 +1751,6 @@ sctp_hs_cwnd_update_after_sack(struct sc
 			}
 		}
 #endif
-		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
-			/*
-			 * So, first of all do we need to have a Early FR
-			 * timer running?
-			 */
-			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
-			    (net->ref_count > 1) &&
-			    (net->flight_size < net->cwnd)) ||
-			    (reneged_all)) {
-				/*
-				 * yes, so in this case stop it if its
-				 * running, and then restart it. Reneging
-				 * all is a special case where we want to
-				 * run the Early FR timer and then force the
-				 * last few unacked to be sent, causing us
-				 * to illicit a sack with gaps to force out
-				 * the others.
-				 */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
-				}
-				SCTP_STAT_INCR(sctps_earlyfrstrid);
-				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
-			} else {
-				/* No, stop it if its running */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
-				}
-			}
-		}
 		/* if nothing was acked on this destination skip it */
 		if (net->net_ack == 0) {
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@@ -1899,47 +1758,6 @@ sctp_hs_cwnd_update_after_sack(struct sc
 			}
 			continue;
 		}
-		if (net->net_ack2 > 0) {
-			/*
-			 * Karn's rule applies to clearing error count, this
-			 * is optional.
-			 */
-			net->error_count = 0;
-			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
-			    SCTP_ADDR_NOT_REACHABLE) {
-				/* addr came good */
-				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
-				net->dest_state |= SCTP_ADDR_REACHABLE;
-				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
-				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
-				/* now was it the primary? if so restore */
-				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
-					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
-				}
-			}
-			/*
-			 * JRS 5/14/07 - If CMT PF is on and the destination
-			 * is in PF state, set the destination to active
-			 * state and set the cwnd to one or two MTU's based
-			 * on whether PF1 or PF2 is being used.
-			 * 
-			 * Should we stop any running T3 timer here?
-			 */
-			if ((asoc->sctp_cmt_on_off > 0) &&
-			    (asoc->sctp_cmt_pf > 0) &&
-			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
-				net->dest_state &= ~SCTP_ADDR_PF;
-				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
-				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
-				    net, net->cwnd);
-				/*
-				 * Since the cwnd value is explicitly set,
-				 * skip the code that updates the cwnd
-				 * value.
-				 */
-				goto skip_cwnd_update;
-			}
-		}
 #ifdef JANA_CMT_FAST_RECOVERY
 		/*
 		 * CMT fast recovery code
@@ -1959,7 +1777,7 @@ sctp_hs_cwnd_update_after_sack(struct sc
 			 * If we are in loss recovery we skip any cwnd
 			 * update
 			 */
-			goto skip_cwnd_update;
+			return;
 		}
 		/*
 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
@@ -2004,23 +1822,6 @@ sctp_hs_cwnd_update_after_sack(struct sc
 				    SCTP_CWND_LOG_NO_CUMACK);
 			}
 		}
-skip_cwnd_update:
-		/*
-		 * NOW, according to Karn's rule do we need to restore the
-		 * RTO timer back? Check our net_ack2. If not set then we
-		 * have a ambiguity.. i.e. all data ack'd was sent to more
-		 * than one place.
-		 */
-		if (net->net_ack2) {
-			/* restore any doubled timers */
-			net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
-			if (net->RTO < stcb->asoc.minrto) {
-				net->RTO = stcb->asoc.minrto;
-			}
-			if (net->RTO > stcb->asoc.maxrto) {
-				net->RTO = stcb->asoc.maxrto;
-			}
-		}
 	}
 }
 
@@ -2340,40 +2141,6 @@ sctp_htcp_cwnd_update_after_sack(struct 
 			}
 		}
 #endif
-		if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
-			/*
-			 * So, first of all do we need to have a Early FR
-			 * timer running?
-			 */
-			if ((!TAILQ_EMPTY(&asoc->sent_queue) &&
-			    (net->ref_count > 1) &&
-			    (net->flight_size < net->cwnd)) ||
-			    (reneged_all)) {
-				/*
-				 * yes, so in this case stop it if its
-				 * running, and then restart it. Reneging
-				 * all is a special case where we want to
-				 * run the Early FR timer and then force the
-				 * last few unacked to be sent, causing us
-				 * to illicit a sack with gaps to force out
-				 * the others.
-				 */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
-				}
-				SCTP_STAT_INCR(sctps_earlyfrstrid);
-				sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
-			} else {
-				/* No, stop it if its running */
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
-				}
-			}
-		}
 		/* if nothing was acked on this destination skip it */
 		if (net->net_ack == 0) {
 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
@@ -2381,47 +2148,6 @@ sctp_htcp_cwnd_update_after_sack(struct 
 			}
 			continue;
 		}
-		if (net->net_ack2 > 0) {
-			/*
-			 * Karn's rule applies to clearing error count, this
-			 * is optional.
-			 */
-			net->error_count = 0;
-			if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
-			    SCTP_ADDR_NOT_REACHABLE) {
-				/* addr came good */
-				net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
-				net->dest_state |= SCTP_ADDR_REACHABLE;
-				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
-				    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
-				/* now was it the primary? if so restore */
-				if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
-					(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
-				}
-			}
-			/*
-			 * JRS 5/14/07 - If CMT PF is on and the destination
-			 * is in PF state, set the destination to active
-			 * state and set the cwnd to one or two MTU's based
-			 * on whether PF1 or PF2 is being used.
-			 * 
-			 * Should we stop any running T3 timer here?
-			 */
-			if ((asoc->sctp_cmt_on_off > 0) &&
-			    (asoc->sctp_cmt_pf > 0) &&
-			    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
-				net->dest_state &= ~SCTP_ADDR_PF;
-				net->cwnd = net->mtu * asoc->sctp_cmt_pf;
-				SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n",
-				    net, net->cwnd);
-				/*
-				 * Since the cwnd value is explicitly set,
-				 * skip the code that updates the cwnd
-				 * value.
-				 */
-				goto skip_cwnd_update;
-			}
-		}
 #ifdef JANA_CMT_FAST_RECOVERY
 		/*
 		 * CMT fast recovery code
@@ -2441,7 +2167,7 @@ sctp_htcp_cwnd_update_after_sack(struct 
 			 * If we are in loss recovery we skip any cwnd
 			 * update
 			 */
-			goto skip_cwnd_update;
+			return;
 		}
 		/*
 		 * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
@@ -2457,23 +2183,6 @@ sctp_htcp_cwnd_update_after_sack(struct 
 				    SCTP_CWND_LOG_NO_CUMACK);
 			}
 		}
-skip_cwnd_update:
-		/*
-		 * NOW, according to Karn's rule do we need to restore the
-		 * RTO timer back? Check our net_ack2. If not set then we
-		 * have a ambiguity.. i.e. all data ack'd was sent to more
-		 * than one place.
-		 */
-		if (net->net_ack2) {
-			/* restore any doubled timers */
-			net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
-			if (net->RTO < stcb->asoc.minrto) {
-				net->RTO = stcb->asoc.minrto;
-			}
-			if (net->RTO > stcb->asoc.maxrto) {
-				net->RTO = stcb->asoc.maxrto;
-			}
-		}
 	}
 }
 
@@ -2566,30 +2275,6 @@ sctp_htcp_cwnd_update_after_timeout(stru
 }
 
 static void
-sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
-    struct sctp_tcb *stcb, struct sctp_nets *net)
-{
-	int old_cwnd;
-
-	old_cwnd = net->cwnd;
-
-	sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
-	net->cc_mod.htcp_ca.last_cong = sctp_get_tick_count();
-	/*
-	 * make a small adjustment to cwnd and force to CA.
-	 */
-	if (net->cwnd > net->mtu)
-		/* drop down one MTU after sending */
-		net->cwnd -= net->mtu;
-	if (net->cwnd < net->ssthresh)
-		/* still in SS move to CA */
-		net->ssthresh = net->cwnd - 1;
-	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
-		sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
-	}
-}
-
-static void
 sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
     struct sctp_nets *net, int in_window, int num_pkt_lost)
 {
@@ -2618,42 +2303,42 @@ struct sctp_cc_functions sctp_cc_functio
 	{
 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
 		.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
+		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
 		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
-		.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
 	},
 	{
 		.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
 		.sctp_cwnd_update_after_sack = sctp_hs_cwnd_update_after_sack,
+		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
 		.sctp_cwnd_update_after_fr = sctp_hs_cwnd_update_after_fr,
 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_after_ecn_echo,
 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
-		.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer
 	},
 	{
 		.sctp_set_initial_cc_param = sctp_htcp_set_initial_cc_param,
 		.sctp_cwnd_update_after_sack = sctp_htcp_cwnd_update_after_sack,
+		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
 		.sctp_cwnd_update_after_fr = sctp_htcp_cwnd_update_after_fr,
 		.sctp_cwnd_update_after_timeout = sctp_htcp_cwnd_update_after_timeout,
 		.sctp_cwnd_update_after_ecn_echo = sctp_htcp_cwnd_update_after_ecn_echo,
 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
-		.sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer
 	},
 	{
 		.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
 		.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
+		.sctp_cwnd_update_exit_pf = sctp_cwnd_update_exit_pf_common,
 		.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
 		.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
 		.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
 		.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
 		.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
-		.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer,
 		.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
 		.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
 		.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,

Modified: head/sys/netinet/sctp_constants.h
==============================================================================
--- head/sys/netinet/sctp_constants.h	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp_constants.h	Wed Aug  3 20:21:00 2011	(r224641)
@@ -416,7 +416,7 @@ __FBSDID("$FreeBSD$");
 #define SCTP_STR_RESET_IN_REQUEST	0x000e
 #define SCTP_STR_RESET_TSN_REQUEST	0x000f
 #define SCTP_STR_RESET_RESPONSE		0x0010
-#define SCTP_STR_RESET_ADD_STREAMS  0x0011
+#define SCTP_STR_RESET_ADD_STREAMS	0x0011
 
 #define SCTP_MAX_RESET_PARAMS 2
 #define SCTP_STREAM_RESET_TSN_DELTA    0x1000
@@ -508,14 +508,10 @@ __FBSDID("$FreeBSD$");
 
 /* SCTP reachability state for each address */
 #define SCTP_ADDR_REACHABLE		0x001
-#define SCTP_ADDR_NOT_REACHABLE		0x002
 #define SCTP_ADDR_NOHB			0x004
 #define SCTP_ADDR_BEING_DELETED		0x008
 #define SCTP_ADDR_NOT_IN_ASSOC		0x010
-#define SCTP_ADDR_WAS_PRIMARY		0x020
-#define SCTP_ADDR_SWITCH_PRIMARY	0x040
 #define SCTP_ADDR_OUT_OF_SCOPE		0x080
-#define SCTP_ADDR_DOUBLE_SWITCH		0x100
 #define SCTP_ADDR_UNCONFIRMED		0x200
 #define SCTP_ADDR_REQ_PRIMARY           0x400
 /* JRS 5/13/07 - Added potentially failed state for CMT PF */
@@ -579,14 +575,13 @@ __FBSDID("$FreeBSD$");
 #define SCTP_TIMER_TYPE_EVENTWAKE	13
 #define SCTP_TIMER_TYPE_STRRESET        14
 #define SCTP_TIMER_TYPE_INPKILL         15
-#define SCTP_TIMER_TYPE_EARLYFR         17
-#define SCTP_TIMER_TYPE_ASOCKILL        18
-#define SCTP_TIMER_TYPE_ADDR_WQ         19
-#define SCTP_TIMER_TYPE_ZERO_COPY       20
-#define SCTP_TIMER_TYPE_ZCOPY_SENDQ     21
-#define SCTP_TIMER_TYPE_PRIM_DELETED    22
+#define SCTP_TIMER_TYPE_ASOCKILL        16
+#define SCTP_TIMER_TYPE_ADDR_WQ         17
+#define SCTP_TIMER_TYPE_ZERO_COPY       18
+#define SCTP_TIMER_TYPE_ZCOPY_SENDQ     19
+#define SCTP_TIMER_TYPE_PRIM_DELETED    20
 /* add new timers here - and increment LAST */
-#define SCTP_TIMER_TYPE_LAST            23
+#define SCTP_TIMER_TYPE_LAST            21
 
 #define SCTP_IS_TIMER_TYPE_VALID(t)	(((t) > SCTP_TIMER_TYPE_NONE) && \
 					 ((t) < SCTP_TIMER_TYPE_LAST))
@@ -655,16 +650,17 @@ __FBSDID("$FreeBSD$");
 #define SCTP_DEFAULT_SECRET_LIFE_SEC 3600
 
 #define SCTP_RTO_UPPER_BOUND	(60000)	/* 60 sec in ms */
-#define SCTP_RTO_LOWER_BOUND	(300)	/* 0.3 sec is ms */
+#define SCTP_RTO_LOWER_BOUND	(1000)	/* 1 sec is ms */
 #define SCTP_RTO_INITIAL	(3000)	/* 3 sec in ms */
 
 
 #define SCTP_INP_KILL_TIMEOUT 20/* number of ms to retry kill of inpcb */
 #define SCTP_ASOC_KILL_TIMEOUT 10	/* number of ms to retry kill of inpcb */
 
-#define SCTP_DEF_MAX_INIT	8
-#define SCTP_DEF_MAX_SEND	10
-#define SCTP_DEF_MAX_PATH_RTX	5
+#define SCTP_DEF_MAX_INIT		8
+#define SCTP_DEF_MAX_SEND		10
+#define SCTP_DEF_MAX_PATH_RTX		5
+#define SCTP_DEF_PATH_PF_THRESHOLD	SCTP_DEF_MAX_PATH_RTX
 
 #define SCTP_DEF_PMTU_RAISE_SEC	600	/* 10 min between raise attempts */
 
@@ -679,7 +675,7 @@ __FBSDID("$FreeBSD$");
 /* Send window update (incr * this > hiwat). Should be a power of 2 */
 #define SCTP_MINIMAL_RWND		(4096)	/* minimal rwnd */
 
-#define SCTP_ADDRMAX		24
+#define SCTP_ADDRMAX		16
 
 /* SCTP DEBUG Switch parameters */
 #define SCTP_DEBUG_TIMER1	0x00000001

Modified: head/sys/netinet/sctp_header.h
==============================================================================
--- head/sys/netinet/sctp_header.h	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp_header.h	Wed Aug  3 20:21:00 2011	(r224641)
@@ -98,9 +98,10 @@ struct sctp_heartbeat_info_param {
 	uint32_t time_value_2;
 	uint32_t random_value1;
 	uint32_t random_value2;
-	uint16_t user_req;
 	uint8_t addr_family;
 	uint8_t addr_len;
+	/* make sure that this structure is 4 byte aligned */
+	uint8_t padding[2];
 	char address[SCTP_ADDRMAX];
 }                         SCTP_PACKED;
 

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c	Wed Aug  3 20:00:36 2011	(r224640)
+++ head/sys/netinet/sctp_indata.c	Wed Aug  3 20:21:00 2011	(r224641)
@@ -2434,7 +2434,8 @@ sctp_sack_check(struct sctp_tcb *stcb, i
 			sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
 			    stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
 		}
-		sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
+		sctp_send_shutdown(stcb,
+		    ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
 		sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
 	} else {
 		int is_a_gap;
@@ -4054,9 +4055,50 @@ sctp_express_handle_sack(struct sctp_tcb
 	}
 
 	/* JRS - Use the congestion control given in the CC module */
-	if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0))
+	if ((asoc->last_acked_seq != cumack) && (ecne_seen == 0)) {
+		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
+			if (net->net_ack2 > 0) {
+				/*
+				 * Karn's rule applies to clearing error
+				 * count, this is optional.
+				 */
+				net->error_count = 0;
+				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
+					/* addr came good */
+					net->dest_state |= SCTP_ADDR_REACHABLE;
+					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
+					    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
+				}
+				if (net == stcb->asoc.primary_destination) {
+					if (stcb->asoc.alternate) {
+						/*
+						 * release the alternate,
+						 * primary is good
+						 */
+						sctp_free_remote_addr(stcb->asoc.alternate);
+						stcb->asoc.alternate = NULL;
+					}
+				}
+				if (net->dest_state & SCTP_ADDR_PF) {
+					net->dest_state &= ~SCTP_ADDR_PF;
+					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
+					asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
+					/* Done with this net */
+					net->net_ack = 0;
+				}
+				/* restore any doubled timers */
+				net->RTO = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv;
+				if (net->RTO < stcb->asoc.minrto) {
+					net->RTO = stcb->asoc.minrto;
+				}
+				if (net->RTO > stcb->asoc.maxrto) {
+					net->RTO = stcb->asoc.maxrto;
+				}
+			}
+		}
 		asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
-
+	}
 	asoc->last_acked_seq = cumack;
 
 	if (TAILQ_EMPTY(&asoc->sent_queue)) {
@@ -4127,13 +4169,6 @@ again:
 				    stcb, net,
 				    SCTP_FROM_SCTP_INDATA + SCTP_LOC_22);
 			}
-			if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck4);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_23);
-				}
-			}
 		}
 	}
 	if ((j == 0) &&
@@ -4222,6 +4257,8 @@ again:
 				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
 				sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
 			} else {
+				struct sctp_nets *netp;
+
 				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
 				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
 					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@@ -4229,26 +4266,36 @@ again:
 				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
 				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
 				sctp_stop_timers_for_shutdown(stcb);
-				sctp_send_shutdown(stcb,
-				    stcb->asoc.primary_destination);
+				if (asoc->alternate) {
+					netp = asoc->alternate;
+				} else {
+					netp = asoc->primary_destination;
+				}
+				sctp_send_shutdown(stcb, netp);
 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
-				    stcb->sctp_ep, stcb, asoc->primary_destination);
+				    stcb->sctp_ep, stcb, netp);
 				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
-				    stcb->sctp_ep, stcb, asoc->primary_destination);
+				    stcb->sctp_ep, stcb, netp);
 			}
 		} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
 		    (asoc->stream_queue_cnt == 0)) {
+			struct sctp_nets *netp;
+
+			if (asoc->alternate) {
+				netp = asoc->alternate;
+			} else {
+				netp = asoc->primary_destination;
+			}
 			if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
 				goto abort_out_now;
 			}
 			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
 			SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
 			SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
-			sctp_send_shutdown_ack(stcb,
-			    stcb->asoc.primary_destination);
+			sctp_send_shutdown_ack(stcb, netp);
 			sctp_stop_timers_for_shutdown(stcb);
 			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK,
-			    stcb->sctp_ep, stcb, asoc->primary_destination);
+			    stcb->sctp_ep, stcb, netp);
 		}
 	}
 	/*********************************************/
@@ -4380,7 +4427,7 @@ sctp_handle_sack(struct mbuf *m, int off
 		    num_dup,
 		    SCTP_LOG_NEW_SACK);
 	}
-	if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) {
+	if ((num_dup) && (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE)) {
 		uint16_t i;
 		uint32_t *dupdata, dblock;
 
@@ -4468,13 +4515,6 @@ sctp_handle_sack(struct mbuf *m, int off
 		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
 			sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
 			    stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
-			if (SCTP_BASE_SYSCTL(sctp_early_fr)) {
-				if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
-					SCTP_STAT_INCR(sctps_earlyfrstpidsck1);
-					sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
-					    SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
-				}
-			}
 			net->partial_bytes_acked = 0;
 			net->flight_size = 0;
 		}
@@ -4830,20 +4870,54 @@ sctp_handle_sack(struct mbuf *m, int off
 		asoc->saw_sack_with_nr_frags = 0;
 
 	/* JRS - Use the congestion control given in the CC module */
-	if (ecne_seen == 0)
+	if (ecne_seen == 0) {
+		TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
+			if (net->net_ack2 > 0) {
+				/*
+				 * Karn's rule applies to clearing error
+				 * count, this is optional.
+				 */
+				net->error_count = 0;
+				if (!(net->dest_state & SCTP_ADDR_REACHABLE)) {
+					/* addr came good */
+					net->dest_state |= SCTP_ADDR_REACHABLE;
+					sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
+					    SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
+				}
+				if (net == stcb->asoc.primary_destination) {
+					if (stcb->asoc.alternate) {
+						/*
+						 * release the alternate,
+						 * primary is good
+						 */
+						sctp_free_remote_addr(stcb->asoc.alternate);
+						stcb->asoc.alternate = NULL;
+					}
+				}
+				if (net->dest_state & SCTP_ADDR_PF) {
+					net->dest_state &= ~SCTP_ADDR_PF;
+					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
+					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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