]> Pileus Git - ~andy/linux/blobdiff - net/sctp/sm_sideeffect.c
sctp: Implement quick failover draft from tsvwg
[~andy/linux] / net / sctp / sm_sideeffect.c
index 8716da1a859221dc96d206ed517190e9e9cfa2ca..fe99628e1257bd1173dadfa1826a0f2d5f35c7f6 100644 (file)
@@ -76,6 +76,8 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
                             sctp_cmd_seq_t *commands,
                             gfp_t gfp);
 
+static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
+                                    struct sctp_transport *t);
 /********************************************************************
  * Helper functions
  ********************************************************************/
@@ -470,7 +472,8 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
  * notification SHOULD be sent to the upper layer.
  *
  */
-static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
+static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
+                                        struct sctp_association *asoc,
                                         struct sctp_transport *transport,
                                         int is_hb)
 {
@@ -495,6 +498,23 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
                        transport->error_count++;
        }
 
+       /* If the transport error count is greater than the pf_retrans
+        * threshold, and less than pathmaxrtx, then mark this transport
+        * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
+        * point 1
+        */
+       if ((transport->state != SCTP_PF) &&
+          (asoc->pf_retrans < transport->pathmaxrxt) &&
+          (transport->error_count > asoc->pf_retrans)) {
+
+               sctp_assoc_control_transport(asoc, transport,
+                                            SCTP_TRANSPORT_PF,
+                                            0);
+
+               /* Update the hb timer to resend a heartbeat every rto */
+               sctp_cmd_hb_timer_update(commands, transport);
+       }
+
        if (transport->state != SCTP_INACTIVE &&
            (transport->error_count > transport->pathmaxrxt)) {
                SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p",
@@ -699,6 +719,10 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
                                             SCTP_HEARTBEAT_SUCCESS);
        }
 
+       if (t->state == SCTP_PF)
+               sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
+                                            SCTP_HEARTBEAT_SUCCESS);
+
        /* The receiver of the HEARTBEAT ACK should also perform an
         * RTT measurement for that destination transport address
         * using the time value carried in the HEARTBEAT ACK chunk.
@@ -1565,8 +1589,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 
                case SCTP_CMD_STRIKE:
                        /* Mark one strike against a transport.  */
-                       sctp_do_8_2_transport_strike(asoc, cmd->obj.transport,
-                                                   0);
+                       sctp_do_8_2_transport_strike(commands, asoc,
+                                                   cmd->obj.transport, 0);
                        break;
 
                case SCTP_CMD_TRANSPORT_IDLE:
@@ -1576,7 +1600,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 
                case SCTP_CMD_TRANSPORT_HB_SENT:
                        t = cmd->obj.transport;
-                       sctp_do_8_2_transport_strike(asoc, t, 1);
+                       sctp_do_8_2_transport_strike(commands, asoc,
+                                                    t, 1);
                        t->hb_sent = 1;
                        break;