RDMA/nes: Fix TCP compliance test failures
Faisal Latif [Sat, 22 Nov 2008 02:50:52 +0000 (20:50 -0600)]
ANVL testing showed we are not handling all cm_node states during
connection establishment.  Add missing state handlers and fix sequence
number send reset in handle_tcp_options().

Signed-off-by: Faisal Latif <faisal.latif@intel.com>
Signed-off-by: Chien Tung <chien.tin.tung@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

drivers/infiniband/hw/nes/nes_cm.c

index f34fa6f..0997c7b 100644 (file)
@@ -1508,7 +1508,7 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        int optionsize;
 
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-       skb_pull(skb, tcph->doff << 2);
+       skb_trim(skb, 0);
        inc_sequence = ntohl(tcph->seq);
 
        switch (cm_node->state) {
@@ -1541,6 +1541,10 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                cm_node->state = NES_CM_STATE_SYN_RCVD;
                send_syn(cm_node, 1, skb);
                break;
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_TSA:
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_FIN_WAIT1:
@@ -1549,7 +1553,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_LAST_ACK:
        case NES_CM_STATE_CLOSING:
        case NES_CM_STATE_UNKNOWN:
-       case NES_CM_STATE_CLOSED:
        default:
                drop_packet(skb);
                break;
@@ -1565,7 +1568,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        int optionsize;
 
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-       skb_pull(skb, tcph->doff << 2);
+       skb_trim(skb, 0);
        inc_sequence = ntohl(tcph->seq);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_SENT:
@@ -1589,6 +1592,12 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                /* passive open, so should not be here */
                passive_open_err(cm_node, skb, 1);
                break;
+       case NES_CM_STATE_LISTENING:
+       case NES_CM_STATE_CLOSED:
+               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_FIN_WAIT1:
        case NES_CM_STATE_FIN_WAIT2:
@@ -1596,7 +1605,6 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_TSA:
        case NES_CM_STATE_CLOSING:
        case NES_CM_STATE_UNKNOWN:
-       case NES_CM_STATE_CLOSED:
        case NES_CM_STATE_MPAREQ_SENT:
        default:
                drop_packet(skb);
@@ -1611,6 +1619,13 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        u32 inc_sequence;
        u32 rem_seq_ack;
        u32 rem_seq;
+       int ret;
+       int optionsize;
+       u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+       cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+
        if (check_seq(cm_node, tcph, skb))
                return;
 
@@ -1623,7 +1638,18 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_RCVD:
                /* Passive OPEN */
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
+               if (ret)
+                       break;
                cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               cm_node->tcp_cntxt.loc_seq_num = temp_seq;
+               if (cm_node->tcp_cntxt.rem_ack_num !=
+                   cm_node->tcp_cntxt.loc_seq_num) {
+                       nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
+                       cleanup_retrans_entry(cm_node);
+                       send_reset(cm_node, skb);
+                       return;
+               }
                cm_node->state = NES_CM_STATE_ESTABLISHED;
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
@@ -1655,11 +1681,15 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                        dev_kfree_skb_any(skb);
                }
                break;
+       case NES_CM_STATE_LISTENING:
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_FIN_WAIT1:
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_FIN_WAIT2:
        case NES_CM_STATE_TSA:
-       case NES_CM_STATE_CLOSED:
        case NES_CM_STATE_MPAREQ_RCVD:
        case NES_CM_STATE_LAST_ACK:
        case NES_CM_STATE_CLOSING:
@@ -1682,9 +1712,9 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
                        nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
                                __func__, cm_node);
                        if (passive)
-                               passive_open_err(cm_node, skb, 0);
+                               passive_open_err(cm_node, skb, 1);
                        else
-                               active_open_err(cm_node, skb, 0);
+                               active_open_err(cm_node, skb, 1);
                        return 1;
                }
        }