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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to