RDMA/nes: Handle MPA Reject message properly
authorFaisal Latif <faisal.latif@intel.com>
Fri, 6 Mar 2009 23:15:01 +0000 (15:15 -0800)
committerRoland Dreier <rolandd@cisco.com>
Fri, 6 Mar 2009 23:15:01 +0000 (15:15 -0800)
While doing testing, there are failures as MPA Reject call is not
handled.  To handle MPA Reject call, following changes are done:

*Handle inbound/outbound MPA Reject response message.
When nes_reject() is called for pending MPA request reply,
send the MPA Reject message to its peer (active
side)cm_node. The peer cm_node (active side) will indicate
Reject message event for the pending Connect Request.

*Handle MPA Reject response message for loopback connections and listener.
When MPA Request is rejected, check if it is a loopback
connection and if it is then it will send Reject message event
to its peer loopback node. Also when destroying listener,
check if the cm_nodes for that listener are loopback or not.

*Add gracefull connection close with the MPA Reject response message.
Send gracefull close (FIN, FIN ACK..) to terminate the cm_nodes.

*Some code re-org while making the above changes.
Removed recv_list and recv_list_lock from the cm_node
structure as there can be only one receive close entry on the
timer. Also implemented handle_recv_entry() as receive close
entry is processed from both nes_rem_ref_cm_node() as well as
nes_cm_timer_tick().

Signed-off-by: Faisal Latif <faisal.latif@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_cm.h

index bd918df..5327f2b 100644 (file)
@@ -103,6 +103,7 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
 static void nes_disconnect_worker(struct work_struct *work);
 
 static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
+static int send_mpa_reject(struct nes_cm_node *);
 static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);
 static int send_reset(struct nes_cm_node *, struct sk_buff *);
 static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);
@@ -113,8 +114,7 @@ static void process_packet(struct nes_cm_node *, struct sk_buff *,
 static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);
 static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
 static void cleanup_retrans_entry(struct nes_cm_node *);
-static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *,
-       enum nes_cm_event_type);
+static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);
 static void free_retrans_entry(struct nes_cm_node *cm_node);
 static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
        struct sk_buff *skb, int optionsize, int passive);
@@ -124,6 +124,8 @@ static void cm_event_connected(struct nes_cm_event *);
 static void cm_event_connect_error(struct nes_cm_event *);
 static void cm_event_reset(struct nes_cm_event *);
 static void cm_event_mpa_req(struct nes_cm_event *);
+static void cm_event_mpa_reject(struct nes_cm_event *);
+static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node);
 
 static void print_core(struct nes_cm_core *core);
 
@@ -196,7 +198,6 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
  */
 static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
-       int ret;
        if (!skb) {
                nes_debug(NES_DBG_CM, "skb set to NULL\n");
                return -1;
@@ -206,11 +207,27 @@ static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
        form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
                        cm_node->mpa_frame_size, SET_ACK);
 
-       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
-       if (ret < 0)
-               return ret;
+       return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+}
 
-       return 0;
+
+
+static int send_mpa_reject(struct nes_cm_node *cm_node)
+{
+       struct sk_buff  *skb = NULL;
+
+       skb = dev_alloc_skb(MAX_CM_BUFFER);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -ENOMEM;
+       }
+
+       /* send an MPA reject frame */
+       form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
+                       cm_node->mpa_frame_size, SET_ACK | SET_FIN);
+
+       cm_node->state = NES_CM_STATE_FIN_WAIT1;
+       return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
 }
 
 
@@ -218,14 +235,17 @@ static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
  * recv_mpa - process a received TCP pkt, we are expecting an
  * IETF MPA frame
  */
-static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
+static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,
+               u32 len)
 {
        struct ietf_mpa_frame *mpa_frame;
 
+       *type = NES_MPA_REQUEST_ACCEPT;
+
        /* assume req frame is in tcp data payload */
        if (len < sizeof(struct ietf_mpa_frame)) {
                nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
-               return -1;
+               return -EINVAL;
        }
 
        mpa_frame = (struct ietf_mpa_frame *)buffer;
@@ -234,14 +254,25 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
        if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
                nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
                                " complete (%x + %x != %x)\n",
-                               cm_node->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
-               return -1;
+                               cm_node->mpa_frame_size,
+                               (u32)sizeof(struct ietf_mpa_frame), len);
+               return -EINVAL;
+       }
+       /* make sure it does not exceed the max size */
+       if (len > MAX_CM_BUFFER) {
+               nes_debug(NES_DBG_CM, "The received ietf buffer was too large"
+                               " (%x + %x != %x)\n",
+                               cm_node->mpa_frame_size,
+                               (u32)sizeof(struct ietf_mpa_frame), len);
+               return -EINVAL;
        }
 
        /* copy entire MPA frame to our cm_node's frame */
        memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
                        cm_node->mpa_frame_size);
 
+       if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)
+               *type = NES_MPA_REQUEST_REJECT;
        return 0;
 }
 
@@ -380,7 +411,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 
        new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
        if (!new_send)
-               return -1;
+               return -ENOMEM;
 
        /* new_send->timetosend = currenttime */
        new_send->retrycount = NES_DEFAULT_RETRYS;
@@ -394,9 +425,11 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
 
        if (type == NES_TIMER_TYPE_CLOSE) {
                new_send->timetosend += (HZ/10);
-               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-               list_add_tail(&new_send->list, &cm_node->recv_list);
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+               if (cm_node->recv_entry) {
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
+               cm_node->recv_entry = new_send;
        }
 
        if (type == NES_TIMER_TYPE_SEND) {
@@ -435,24 +468,78 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        return ret;
 }
 
+static void nes_retrans_expired(struct nes_cm_node *cm_node)
+{
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_CLOSING:
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               break;
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_MPAREJ_RCVD:
+               send_reset(cm_node, NULL);
+               break;
+       default:
+               create_event(cm_node, NES_CM_EVENT_ABORTED);
+       }
+}
+
+static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)
+{
+       struct nes_timer_entry *recv_entry = cm_node->recv_entry;
+       struct iw_cm_id *cm_id = cm_node->cm_id;
+       struct nes_qp *nesqp;
+       unsigned long qplockflags;
+
+       if (!recv_entry)
+               return;
+       nesqp = (struct nes_qp *)recv_entry->skb;
+       if (nesqp) {
+               spin_lock_irqsave(&nesqp->lock, qplockflags);
+               if (nesqp->cm_id) {
+                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+                               "refcount = %d: HIT A "
+                               "NES_TIMER_TYPE_CLOSE with something "
+                               "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+                               atomic_read(&nesqp->refcount));
+                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                       nesqp->ibqp_state = IB_QPS_ERR;
+                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                       nes_cm_disconn(nesqp);
+               } else {
+                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
+                               "refcount = %d: HIT A "
+                               "NES_TIMER_TYPE_CLOSE with nothing "
+                               "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
+                               atomic_read(&nesqp->refcount));
+               }
+       } else if (rem_node) {
+               /* TIME_WAIT state */
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+       }
+       if (cm_node->cm_id)
+               cm_id->rem_ref(cm_id);
+       kfree(recv_entry);
+       cm_node->recv_entry = NULL;
+}
 
 /**
  * nes_cm_timer_tick
  */
 static void nes_cm_timer_tick(unsigned long pass)
 {
-       unsigned long flags, qplockflags;
+       unsigned long flags;
        unsigned long nexttimeout = jiffies + NES_LONG_TIME;
-       struct iw_cm_id *cm_id;
        struct nes_cm_node *cm_node;
        struct nes_timer_entry *send_entry, *recv_entry;
-       struct list_head *list_core, *list_core_temp;
-       struct list_head *list_node, *list_node_temp;
+       struct list_head *list_core_temp;
+       struct list_head *list_node;
        struct nes_cm_core *cm_core = g_cm_core;
-       struct nes_qp *nesqp;
        u32 settimer = 0;
        int ret = NETDEV_TX_OK;
-       enum nes_cm_node_state last_state;
 
        struct list_head timer_list;
        INIT_LIST_HEAD(&timer_list);
@@ -461,7 +548,7 @@ static void nes_cm_timer_tick(unsigned long pass)
        list_for_each_safe(list_node, list_core_temp,
                                &cm_core->connected_nodes) {
                cm_node = container_of(list_node, struct nes_cm_node, list);
-               if (!list_empty(&cm_node->recv_list) || (cm_node->send_entry)) {
+               if ((cm_node->recv_entry) || (cm_node->send_entry)) {
                        add_ref_cm_node(cm_node);
                        list_add(&cm_node->timer_entry, &timer_list);
                }
@@ -471,54 +558,18 @@ static void nes_cm_timer_tick(unsigned long pass)
        list_for_each_safe(list_node, list_core_temp, &timer_list) {
                cm_node = container_of(list_node, struct nes_cm_node,
                                        timer_entry);
-               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-               list_for_each_safe(list_core, list_node_temp,
-                       &cm_node->recv_list) {
-                       recv_entry = container_of(list_core,
-                               struct nes_timer_entry, list);
-                       if (!recv_entry)
-                               break;
+               recv_entry = cm_node->recv_entry;
+
+               if (recv_entry) {
                        if (time_after(recv_entry->timetosend, jiffies)) {
                                if (nexttimeout > recv_entry->timetosend ||
-                                       !settimer) {
+                                               !settimer) {
                                        nexttimeout = recv_entry->timetosend;
                                        settimer = 1;
                                }
-                               continue;
-                       }
-                       list_del(&recv_entry->list);
-                       cm_id = cm_node->cm_id;
-                       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-                       nesqp = (struct nes_qp *)recv_entry->skb;
-                       spin_lock_irqsave(&nesqp->lock, qplockflags);
-                       if (nesqp->cm_id) {
-                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
-                                       "refcount = %d: HIT A "
-                                       "NES_TIMER_TYPE_CLOSE with something "
-                                       "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
-                                       atomic_read(&nesqp->refcount));
-                               nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-                               nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-                               nesqp->ibqp_state = IB_QPS_ERR;
-                               spin_unlock_irqrestore(&nesqp->lock,
-                                       qplockflags);
-                               nes_cm_disconn(nesqp);
-                       } else {
-                               spin_unlock_irqrestore(&nesqp->lock,
-                                       qplockflags);
-                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
-                                       "refcount = %d: HIT A "
-                                       "NES_TIMER_TYPE_CLOSE with nothing "
-                                       "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
-                                       atomic_read(&nesqp->refcount));
-                       }
-                       if (cm_id)
-                               cm_id->rem_ref(cm_id);
-
-                       kfree(recv_entry);
-                       spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+                       } else
+                               handle_recv_entry(cm_node, 1);
                }
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
 
                spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
                do {
@@ -533,12 +584,11 @@ static void nes_cm_timer_tick(unsigned long pass)
                                                nexttimeout =
                                                        send_entry->timetosend;
                                                settimer = 1;
-                                               break;
                                        }
                                } else {
                                        free_retrans_entry(cm_node);
-                                       break;
                                }
+                               break;
                        }
 
                        if ((cm_node->state == NES_CM_STATE_TSA) ||
@@ -550,16 +600,12 @@ static void nes_cm_timer_tick(unsigned long pass)
                        if (!send_entry->retranscount ||
                                !send_entry->retrycount) {
                                cm_packets_dropped++;
-                               last_state = cm_node->state;
-                               cm_node->state = NES_CM_STATE_CLOSED;
                                free_retrans_entry(cm_node);
+
                                spin_unlock_irqrestore(
                                        &cm_node->retrans_list_lock, flags);
-                               if (last_state == NES_CM_STATE_SYN_RCVD)
-                                       rem_ref_cm_node(cm_core, cm_node);
-                               else
-                                       create_event(cm_node,
-                                               NES_CM_EVENT_ABORTED);
+                               nes_retrans_expired(cm_node);
+                               cm_node->state = NES_CM_STATE_CLOSED;
                                spin_lock_irqsave(&cm_node->retrans_list_lock,
                                        flags);
                                break;
@@ -714,7 +760,7 @@ static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
                skb = dev_alloc_skb(MAX_CM_BUFFER);
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
-               return -1;
+               return -ENOMEM;
        }
 
        form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
@@ -871,7 +917,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
 static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
        struct nes_cm_listener *listener, int free_hanging_nodes)
 {
-       int ret = 1;
+       int ret = -EINVAL;
+       int err = 0;
        unsigned long flags;
        struct list_head *list_pos = NULL;
        struct list_head *list_temp = NULL;
@@ -900,10 +947,60 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
 
        list_for_each_safe(list_pos, list_temp, &reset_list) {
                cm_node = container_of(list_pos, struct nes_cm_node,
-                                       reset_entry);
-               cleanup_retrans_entry(cm_node);
-               send_reset(cm_node, NULL);
-               rem_ref_cm_node(cm_node->cm_core, cm_node);
+                               reset_entry);
+               {
+                       struct nes_cm_node *loopback = cm_node->loopbackpartner;
+                       if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {
+                               rem_ref_cm_node(cm_node->cm_core, cm_node);
+                       } else {
+                               if (!loopback) {
+                                       cleanup_retrans_entry(cm_node);
+                                       err = send_reset(cm_node, NULL);
+                                       if (err) {
+                                               cm_node->state =
+                                                        NES_CM_STATE_CLOSED;
+                                               WARN_ON(1);
+                                       } else {
+                                               cm_node->state =
+                                                       NES_CM_STATE_CLOSED;
+                                               rem_ref_cm_node(
+                                                       cm_node->cm_core,
+                                                       cm_node);
+                                       }
+                               } else {
+                                       struct nes_cm_event event;
+
+                                       event.cm_node = loopback;
+                                       event.cm_info.rem_addr =
+                                                       loopback->rem_addr;
+                                       event.cm_info.loc_addr =
+                                                       loopback->loc_addr;
+                                       event.cm_info.rem_port =
+                                                       loopback->rem_port;
+                                       event.cm_info.loc_port =
+                                                        loopback->loc_port;
+                                       event.cm_info.cm_id = loopback->cm_id;
+                                       cm_event_connect_error(&event);
+                                       loopback->state = NES_CM_STATE_CLOSED;
+
+                                       event.cm_node = cm_node;
+                                       event.cm_info.rem_addr =
+                                                        cm_node->rem_addr;
+                                       event.cm_info.loc_addr =
+                                                        cm_node->loc_addr;
+                                       event.cm_info.rem_port =
+                                                        cm_node->rem_port;
+                                       event.cm_info.loc_port =
+                                                        cm_node->loc_port;
+                                       event.cm_info.cm_id = cm_node->cm_id;
+                                       cm_event_reset(&event);
+
+                                       rem_ref_cm_node(cm_node->cm_core,
+                                                        cm_node);
+
+                               }
+                       }
+               }
        }
 
        spin_lock_irqsave(&cm_core->listen_list_lock, flags);
@@ -964,6 +1061,7 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
        if (cm_node->accept_pend) {
                BUG_ON(!cm_node->listener);
                atomic_dec(&cm_node->listener->pend_accepts_cnt);
+               cm_node->accept_pend = 0;
                BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
 
@@ -990,7 +1088,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
        memset(&fl, 0, sizeof fl);
        fl.nl_u.ip4_u.daddr = htonl(dst_ip);
        if (ip_route_output_key(&init_net, &rt, &fl)) {
-               printk("%s: ip_route_output_key failed for 0x%08X\n",
+               printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
                                __func__, dst_ip);
                return rc;
        }
@@ -1053,8 +1151,6 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
                        cm_node->cm_id);
 
        spin_lock_init(&cm_node->retrans_list_lock);
-       INIT_LIST_HEAD(&cm_node->recv_list);
-       spin_lock_init(&cm_node->recv_list_lock);
 
        cm_node->loopbackpartner = NULL;
        atomic_set(&cm_node->ref_count, 1);
@@ -1122,10 +1218,7 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)
 static int rem_ref_cm_node(struct nes_cm_core *cm_core,
        struct nes_cm_node *cm_node)
 {
-       unsigned long flags, qplockflags;
-       struct nes_timer_entry *recv_entry;
-       struct iw_cm_id *cm_id;
-       struct list_head *list_core, *list_node_temp;
+       unsigned long flags;
        struct nes_qp *nesqp;
 
        if (!cm_node)
@@ -1146,38 +1239,9 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
                atomic_dec(&cm_node->listener->pend_accepts_cnt);
                BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
        }
-       BUG_ON(cm_node->send_entry);
-       spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-       list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
-               recv_entry = container_of(list_core, struct nes_timer_entry,
-                               list);
-               list_del(&recv_entry->list);
-               cm_id = cm_node->cm_id;
-               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-               nesqp = (struct nes_qp *)recv_entry->skb;
-               spin_lock_irqsave(&nesqp->lock, qplockflags);
-               if (nesqp->cm_id) {
-                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
-                               "NES_TIMER_TYPE_CLOSE with something to do!\n",
-                               nesqp->hwqp.qp_id, cm_id);
-                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
-                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
-                       nesqp->ibqp_state = IB_QPS_ERR;
-                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                       nes_cm_disconn(nesqp);
-               } else {
-                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
-                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
-                               "NES_TIMER_TYPE_CLOSE with nothing to do!\n",
-                               nesqp->hwqp.qp_id, cm_id);
-               }
-               cm_id->rem_ref(cm_id);
-
-               kfree(recv_entry);
-               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
-       }
-       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
-
+       WARN_ON(cm_node->send_entry);
+       if (cm_node->recv_entry)
+               handle_recv_entry(cm_node, 0);
        if (cm_node->listener) {
                mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
        } else {
@@ -1262,8 +1326,7 @@ static void drop_packet(struct sk_buff *skb)
        dev_kfree_skb_any(skb);
 }
 
-static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
-       struct tcphdr *tcph)
+static void handle_fin_pkt(struct nes_cm_node *cm_node)
 {
        nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
                "refcnt=%d\n", cm_node, cm_node->state,
@@ -1275,23 +1338,30 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_MPAREQ_SENT:
+       case NES_CM_STATE_MPAREJ_RCVD:
                cm_node->state = NES_CM_STATE_LAST_ACK;
-               send_fin(cm_node, skb);
+               send_fin(cm_node, NULL);
                break;
        case NES_CM_STATE_FIN_WAIT1:
                cm_node->state = NES_CM_STATE_CLOSING;
-               send_ack(cm_node, skb);
+               send_ack(cm_node, NULL);
+               /* Wait for ACK as this is simultanous close..
+               * After we receive ACK, do not send anything..
+               * Just rm the node.. Done.. */
                break;
        case NES_CM_STATE_FIN_WAIT2:
                cm_node->state = NES_CM_STATE_TIME_WAIT;
-               send_ack(cm_node, skb);
+               send_ack(cm_node, NULL);
+               schedule_nes_timer(cm_node, NULL,  NES_TIMER_TYPE_CLOSE, 1, 0);
+               break;
+       case NES_CM_STATE_TIME_WAIT:
                cm_node->state = NES_CM_STATE_CLOSED;
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
                break;
        case NES_CM_STATE_TSA:
        default:
                nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
                        cm_node, cm_node->state);
-               drop_packet(skb);
                break;
        }
 }
@@ -1337,23 +1407,35 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                cleanup_retrans_entry(cm_node);
                drop_packet(skb);
                break;
+       case NES_CM_STATE_TIME_WAIT:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               drop_packet(skb);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+               cleanup_retrans_entry(cm_node);
+               nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
        default:
                drop_packet(skb);
                break;
        }
 }
 
-static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
-       enum nes_cm_event_type type)
+
+static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
 
-       int     ret;
+       int     ret = 0;
        int datasize = skb->len;
        u8 *dataloc = skb->data;
-       ret = parse_mpa(cm_node, dataloc, datasize);
-       if (ret < 0) {
+
+       enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN;
+       u32     res_type;
+       ret = parse_mpa(cm_node, dataloc, &res_type, datasize);
+       if (ret) {
                nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
-               if (type == NES_CM_EVENT_CONNECTED) {
+               if (cm_node->state == NES_CM_STATE_MPAREQ_SENT) {
                        nes_debug(NES_DBG_CM, "%s[%u] create abort for "
                                "cm_node=%p listener=%p state=%d\n", __func__,
                                __LINE__, cm_node, cm_node->listener,
@@ -1362,18 +1444,38 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
                } else {
                        passive_open_err(cm_node, skb, 1);
                }
-       } else {
-               cleanup_retrans_entry(cm_node);
-               dev_kfree_skb_any(skb);
-               if (type == NES_CM_EVENT_CONNECTED)
+               return;
+       }
+
+       switch (cm_node->state) {
+       case NES_CM_STATE_ESTABLISHED:
+               if (res_type == NES_MPA_REQUEST_REJECT) {
+                       /*BIG problem as we are receiving the MPA.. So should
+                       * not be REJECT.. This is Passive Open.. We can
+                       * only receive it Reject for Active Open...*/
+                       WARN_ON(1);
+               }
+               cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
+               type = NES_CM_EVENT_MPA_REQ;
+               atomic_set(&cm_node->passive_state,
+                               NES_PASSIVE_STATE_INDICATED);
+               break;
+       case NES_CM_STATE_MPAREQ_SENT:
+               if (res_type == NES_MPA_REQUEST_REJECT) {
+                       type = NES_CM_EVENT_MPA_REJECT;
+                       cm_node->state = NES_CM_STATE_MPAREJ_RCVD;
+               } else {
+                       type = NES_CM_EVENT_CONNECTED;
                        cm_node->state = NES_CM_STATE_TSA;
-               else
-                       atomic_set(&cm_node->passive_state,
-                                       NES_PASSIVE_STATE_INDICATED);
-               create_event(cm_node, type);
+               }
 
+               break;
+       default:
+               WARN_ON(1);
+               break;
        }
-       return ;
+       dev_kfree_skb_any(skb);
+       create_event(cm_node, type);
 }
 
 static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
@@ -1461,8 +1563,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                break;
        case NES_CM_STATE_LISTENING:
                /* Passive OPEN */
-               cm_node->accept_pend = 1;
-               atomic_inc(&cm_node->listener->pend_accepts_cnt);
                if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
                                cm_node->listener->backlog) {
                        nes_debug(NES_DBG_CM, "drop syn due to backlog "
@@ -1480,6 +1580,9 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                }
                cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
                BUG_ON(cm_node->send_entry);
+               cm_node->accept_pend = 1;
+               atomic_inc(&cm_node->listener->pend_accepts_cnt);
+
                cm_node->state = NES_CM_STATE_SYN_RCVD;
                send_syn(cm_node, 1, skb);
                break;
@@ -1514,6 +1617,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        inc_sequence = ntohl(tcph->seq);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_SENT:
+               cleanup_retrans_entry(cm_node);
                /* active open */
                if (check_syn(cm_node, tcph, skb))
                        return;
@@ -1563,10 +1667,7 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        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;
@@ -1576,7 +1677,7 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        rem_seq = ntohl(tcph->seq);
        rem_seq_ack =  ntohl(tcph->ack_seq);
        datasize = skb->len;
-
+       cleanup_retrans_entry(cm_node);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_RCVD:
                /* Passive OPEN */
@@ -1584,7 +1685,6 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                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");
@@ -1593,31 +1693,30 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                        return;
                }
                cm_node->state = NES_CM_STATE_ESTABLISHED;
+               cleanup_retrans_entry(cm_node);
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-                       cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
-                       handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_MPA_REQ);
-                } else { /* rcvd ACK only */
+                       handle_rcv_mpa(cm_node, skb);
+               } else { /* rcvd ACK only */
                        dev_kfree_skb_any(skb);
                        cleanup_retrans_entry(cm_node);
                 }
                break;
        case NES_CM_STATE_ESTABLISHED:
                /* Passive OPEN */
-               /* We expect mpa frame to be received only */
+               cleanup_retrans_entry(cm_node);
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-                       cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
-                       handle_rcv_mpa(cm_node, skb,
-                               NES_CM_EVENT_MPA_REQ);
+                       handle_rcv_mpa(cm_node, skb);
                } else
                        drop_packet(skb);
                break;
        case NES_CM_STATE_MPAREQ_SENT:
+               cleanup_retrans_entry(cm_node);
                cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
-                       handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_CONNECTED);
+                       handle_rcv_mpa(cm_node, skb);
                } else { /* Could be just an ack pkt.. */
                        cleanup_retrans_entry(cm_node);
                        dev_kfree_skb_any(skb);
@@ -1628,13 +1727,24 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                cleanup_retrans_entry(cm_node);
                send_reset(cm_node, skb);
                break;
+       case NES_CM_STATE_LAST_ACK:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               cm_node->cm_id->rem_ref(cm_node->cm_id);
+       case NES_CM_STATE_CLOSING:
+               cleanup_retrans_entry(cm_node);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               drop_packet(skb);
+               break;
        case NES_CM_STATE_FIN_WAIT1:
+               cleanup_retrans_entry(cm_node);
+               drop_packet(skb);
+               cm_node->state = NES_CM_STATE_FIN_WAIT2;
+               break;
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_FIN_WAIT2:
        case NES_CM_STATE_TSA:
        case NES_CM_STATE_MPAREQ_RCVD:
-       case NES_CM_STATE_LAST_ACK:
-       case NES_CM_STATE_CLOSING:
        case NES_CM_STATE_UNKNOWN:
        default:
                drop_packet(skb);
@@ -1744,6 +1854,7 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
 {
        enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
        struct tcphdr *tcph = tcp_hdr(skb);
+       u32     fin_set = 0;
        skb_pull(skb, ip_hdr(skb)->ihl << 2);
 
        nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
@@ -1756,10 +1867,10 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
                pkt_type = NES_PKT_TYPE_SYN;
                if (tcph->ack)
                        pkt_type = NES_PKT_TYPE_SYNACK;
-       } else if (tcph->fin)
-               pkt_type = NES_PKT_TYPE_FIN;
-       else if (tcph->ack)
+       } else if (tcph->ack)
                pkt_type = NES_PKT_TYPE_ACK;
+       if (tcph->fin)
+               fin_set = 1;
 
        switch (pkt_type) {
        case NES_PKT_TYPE_SYN:
@@ -1770,15 +1881,16 @@ static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
                break;
        case NES_PKT_TYPE_ACK:
                handle_ack_pkt(cm_node, skb, tcph);
+               if (fin_set)
+                       handle_fin_pkt(cm_node);
                break;
        case NES_PKT_TYPE_RST:
                handle_rst_pkt(cm_node, skb, tcph);
                break;
-       case NES_PKT_TYPE_FIN:
-               handle_fin_pkt(cm_node, skb, tcph);
-               break;
        default:
                drop_packet(skb);
+               if (fin_set)
+                       handle_fin_pkt(cm_node);
                break;
        }
 }
@@ -1921,7 +2033,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
                                loopbackremotenode->tcp_cntxt.rcv_wscale;
                        loopbackremotenode->tcp_cntxt.snd_wscale =
                                cm_node->tcp_cntxt.rcv_wscale;
-
+                       loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;
                        create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
                }
                return cm_node;
@@ -1976,7 +2088,11 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
        struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        int ret = 0;
+       int err = 0;
        int passive_state;
+       struct nes_cm_event event;
+       struct iw_cm_id *cm_id = cm_node->cm_id;
+       struct nes_cm_node *loopback = cm_node->loopbackpartner;
 
        nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
                __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
@@ -1985,12 +2101,38 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
                return ret;
        cleanup_retrans_entry(cm_node);
 
-       passive_state = atomic_add_return(1, &cm_node->passive_state);
-       cm_node->state = NES_CM_STATE_CLOSED;
-       if (passive_state == NES_SEND_RESET_EVENT)
+       if (!loopback) {
+               passive_state = atomic_add_return(1, &cm_node->passive_state);
+               if (passive_state == NES_SEND_RESET_EVENT) {
+                       cm_node->state = NES_CM_STATE_CLOSED;
+                       rem_ref_cm_node(cm_core, cm_node);
+               } else {
+                       ret = send_mpa_reject(cm_node);
+                       if (ret) {
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               err = send_reset(cm_node, NULL);
+                               if (err)
+                                       WARN_ON(1);
+                       } else
+                               cm_id->add_ref(cm_id);
+               }
+       } else {
+               cm_node->cm_id = NULL;
+               event.cm_node = loopback;
+               event.cm_info.rem_addr = loopback->rem_addr;
+               event.cm_info.loc_addr = loopback->loc_addr;
+               event.cm_info.rem_port = loopback->rem_port;
+               event.cm_info.loc_port = loopback->loc_port;
+               event.cm_info.cm_id = loopback->cm_id;
+               cm_event_mpa_reject(&event);
                rem_ref_cm_node(cm_core, cm_node);
-       else
-               ret = send_reset(cm_node, NULL);
+               loopback->state = NES_CM_STATE_CLOSING;
+
+               cm_id = loopback->cm_id;
+               rem_ref_cm_node(cm_core, loopback);
+               cm_id->rem_ref(cm_id);
+       }
+
        return ret;
 }
 
@@ -2027,6 +2169,7 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
        case NES_CM_STATE_CLOSING:
                ret = -1;
                break;
+       case NES_CM_STATE_MPAREJ_RCVD:
        case NES_CM_STATE_LISTENING:
        case NES_CM_STATE_UNKNOWN:
        case NES_CM_STATE_INITED:
@@ -2223,15 +2366,15 @@ static int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
        int ret = 0;
 
        switch (type) {
-               case NES_CM_SET_PKT_SIZE:
-                       cm_core->mtu = value;
-                       break;
-               case NES_CM_SET_FREE_PKT_Q_SIZE:
-                       cm_core->free_tx_pkt_max = value;
-                       break;
-               default:
-                       /* unknown set option */
-                       ret = -EINVAL;
+       case NES_CM_SET_PKT_SIZE:
+               cm_core->mtu = value;
+               break;
+       case NES_CM_SET_FREE_PKT_Q_SIZE:
+               cm_core->free_tx_pkt_max = value;
+               break;
+       default:
+               /* unknown set option */
+               ret = -EINVAL;
        }
 
        return ret;
@@ -2621,9 +2764,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                        NES_QPCONTEXT_ORDIRD_WRPDU);
        } else {
                nesqp->nesqp_context->ird_ord_sizes |=
-                       cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
-                       NES_QPCONTEXT_ORDIRD_WRPDU |
-                       NES_QPCONTEXT_ORDIRD_ALSMM));
+                       cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);
        }
        nesqp->skip_lsmm = 1;
 
@@ -2745,23 +2886,35 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
 {
        struct nes_cm_node *cm_node;
+       struct nes_cm_node *loopback;
+
        struct nes_cm_core *cm_core;
 
        atomic_inc(&cm_rejects);
        cm_node = (struct nes_cm_node *) cm_id->provider_data;
+       loopback = cm_node->loopbackpartner;
        cm_core = cm_node->cm_core;
+       cm_node->cm_id = cm_id;
        cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
 
+       if (cm_node->mpa_frame_size > MAX_CM_BUFFER)
+               return -EINVAL;
+
        strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
-       memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+       if (loopback) {
+               memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);
+               loopback->mpa_frame.priv_data_len = pdata_len;
+               loopback->mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+                               pdata_len;
+       } else {
+               memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+               cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
+       }
 
-       cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
        cm_node->mpa_frame.rev = mpa_version;
        cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
 
-       cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
-
-       return 0;
+       return cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
 }
 
 
@@ -3270,13 +3423,56 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
        cm_event.remote_addr.sin_family = AF_INET;
        cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
        cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
+       cm_event.private_data = cm_node->mpa_frame_buf;
+       cm_event.private_data_len  = (u8) cm_node->mpa_frame_size;
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (ret)
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __func__, __LINE__, ret);
+       return;
+}
+
+
+static void cm_event_mpa_reject(struct nes_cm_event *event)
+{
+       struct iw_cm_id   *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_cm_node *cm_node;
+       int ret;
+
+       cm_node = event->cm_node;
+       if (!cm_node)
+               return;
+       cm_id = cm_node->cm_id;
+
+       atomic_inc(&cm_connect_reqs);
+       nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
+                       cm_node, cm_id, jiffies);
+
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = -ECONNREFUSED;
+       cm_event.provider_data = cm_id->provider_data;
+
+       cm_event.local_addr.sin_family = AF_INET;
+       cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
+       cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
+
+       cm_event.remote_addr.sin_family = AF_INET;
+       cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
+       cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
 
-               cm_event.private_data                = cm_node->mpa_frame_buf;
-               cm_event.private_data_len            = (u8) cm_node->mpa_frame_size;
+       cm_event.private_data = cm_node->mpa_frame_buf;
+       cm_event.private_data_len = (u8) cm_node->mpa_frame_size;
+
+       nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_REJECTED, local_addr=%08x, "
+                       "remove_addr=%08x\n",
+                       cm_event.local_addr.sin_addr.s_addr,
+                       cm_event.remote_addr.sin_addr.s_addr);
 
        ret = cm_id->event_handler(cm_id, &cm_event);
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",
                                __func__, __LINE__, ret);
 
        return;
@@ -3341,6 +3537,14 @@ static void nes_cm_event_handler(struct work_struct *work)
                cm_event_connected(event);
                nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
                break;
+       case NES_CM_EVENT_MPA_REJECT:
+               if ((!event->cm_node->cm_id) ||
+                               (event->cm_node->state == NES_CM_STATE_TSA))
+                       break;
+               cm_event_mpa_reject(event);
+               nes_debug(NES_DBG_CM, "CM Event: REJECT\n");
+               break;
+
        case NES_CM_EVENT_ABORTED:
                if ((!event->cm_node->cm_id) ||
                        (event->cm_node->state == NES_CM_STATE_TSA))
index 4ab2beb..d5f7782 100644 (file)
@@ -39,6 +39,9 @@
 #define NES_MANAGE_APBVT_DEL 0
 #define NES_MANAGE_APBVT_ADD 1
 
+#define NES_MPA_REQUEST_ACCEPT  1
+#define NES_MPA_REQUEST_REJECT  2
+
 /* IETF MPA -- defines, enums, structs */
 #define IEFT_MPA_KEY_REQ  "MPA ID Req Frame"
 #define IEFT_MPA_KEY_REP  "MPA ID Rep Frame"
@@ -186,6 +189,7 @@ enum nes_cm_node_state {
        NES_CM_STATE_ACCEPTING,
        NES_CM_STATE_MPAREQ_SENT,
        NES_CM_STATE_MPAREQ_RCVD,
+       NES_CM_STATE_MPAREJ_RCVD,
        NES_CM_STATE_TSA,
        NES_CM_STATE_FIN_WAIT1,
        NES_CM_STATE_FIN_WAIT2,
@@ -278,13 +282,12 @@ struct nes_cm_node {
        struct nes_timer_entry  *send_entry;
 
        spinlock_t                retrans_list_lock;
-       struct list_head          recv_list;
-       spinlock_t                recv_list_lock;
+       struct nes_timer_entry  *recv_entry;
 
        int                       send_write0;
        union {
                struct ietf_mpa_frame mpa_frame;
-               u8                    mpa_frame_buf[NES_CM_DEFAULT_MTU];
+               u8                    mpa_frame_buf[MAX_CM_BUFFER];
        };
        u16                       mpa_frame_size;
        struct iw_cm_id           *cm_id;
@@ -326,6 +329,7 @@ enum  nes_cm_event_type {
        NES_CM_EVENT_MPA_REQ,
        NES_CM_EVENT_MPA_CONNECT,
        NES_CM_EVENT_MPA_ACCEPT,
+       NES_CM_EVENT_MPA_REJECT,
        NES_CM_EVENT_MPA_ESTABLISHED,
        NES_CM_EVENT_CONNECTED,
        NES_CM_EVENT_CLOSED,