include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[linux-2.6.git] / drivers / infiniband / hw / nes / nes_cm.c
index 6aa531d..986d6f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2006 - 2009 Intel Corporation.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
 #include <linux/random.h>
 #include <linux/list.h>
 #include <linux/threads.h>
-
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <net/arp.h>
 #include <net/neighbour.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
+#include <net/tcp.h>
 
 #include "nes.h"
 
@@ -65,8 +68,8 @@ u32 cm_packets_dropped;
 u32 cm_packets_retrans;
 u32 cm_packets_created;
 u32 cm_packets_received;
-u32 cm_listens_created;
-u32 cm_listens_destroyed;
+atomic_t cm_listens_created;
+atomic_t cm_listens_destroyed;
 u32 cm_backlog_drops;
 atomic_t cm_loopbacks;
 atomic_t cm_nodes_created;
@@ -74,36 +77,60 @@ atomic_t cm_nodes_destroyed;
 atomic_t cm_accel_dropped_pkts;
 atomic_t cm_resets_recvd;
 
-static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
+static inline int mini_cm_accelerated(struct nes_cm_core *,
+       struct nes_cm_node *);
 static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
-               struct nes_vnic *, struct nes_cm_info *);
-static int add_ref_cm_node(struct nes_cm_node *);
-static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+       struct nes_vnic *, struct nes_cm_info *);
 static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
-static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
-                                    void *, u32, void *, u32, u8);
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
-
 static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *,
-                                          struct nes_vnic *,
-                                          struct ietf_mpa_frame *,
-                                          struct nes_cm_info *);
+       struct nes_vnic *, u16, void *, struct nes_cm_info *);
+static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
 static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,
-                         struct nes_cm_node *);
+       struct nes_cm_node *);
 static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
-                         struct nes_cm_node *);
-static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
+       struct nes_cm_node *);
 static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
-                           struct sk_buff *);
+       struct sk_buff *);
 static int mini_cm_dealloc_core(struct nes_cm_core *);
 static int mini_cm_get(struct nes_cm_core *);
 static int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+static void form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+       void *, u32, void *, u32, u8);
+static int add_ref_cm_node(struct nes_cm_node *);
+static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+
 static int nes_cm_disconn_true(struct nes_qp *);
 static int nes_cm_post_event(struct nes_cm_event *event);
 static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
 static void nes_disconnect_worker(struct work_struct *work);
-static int send_ack(struct nes_cm_node *cm_node);
+
+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);
 static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb);
+static void process_packet(struct nes_cm_node *, struct sk_buff *,
+       struct nes_cm_core *);
+
+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 *);
+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);
+
+/* CM event handler functions */
+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);
 
 /* External CM API Interface */
 /* instance of function pointers for client API */
@@ -158,11 +185,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
        event->cm_info.loc_port = cm_node->loc_port;
        event->cm_info.cm_id = cm_node->cm_id;
 
-       nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x],"
-                       " src_addr=%08x[%x]\n",
-                       event, type,
-                       event->cm_info.loc_addr, event->cm_info.loc_port,
-                       event->cm_info.rem_addr, event->cm_info.rem_port);
+       nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, "
+               "dst_addr=%08x[%x], src_addr=%08x[%x]\n",
+               cm_node, event, type, event->cm_info.loc_addr,
+               event->cm_info.loc_port, event->cm_info.rem_addr,
+               event->cm_info.rem_port);
 
        nes_cm_post_event(event);
        return event;
@@ -172,14 +199,10 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
 /**
  * send_mpa_request
  */
-static int send_mpa_request(struct nes_cm_node *cm_node)
+static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-       int ret;
-
-       skb = get_free_pkt(cm_node);
        if (!skb) {
-               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               nes_debug(NES_DBG_CM, "skb set to NULL\n");
                return -1;
        }
 
@@ -187,12 +210,27 @@ static int send_mpa_request(struct nes_cm_node *cm_node)
        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);
+}
+
+
+
+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;
        }
 
-       return 0;
+       /* 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);
 }
 
 
@@ -200,75 +238,82 @@ static int send_mpa_request(struct nes_cm_node *cm_node)
  * 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;
        cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len);
+       /* make sure mpa private data len is less than 512 bytes */
+       if (cm_node->mpa_frame_size > IETF_MAX_PRIV_DATA_LEN) {
+               nes_debug(NES_DBG_CM, "The received Length of Private"
+                       " Data field exceeds 512 octets\n");
+               return -EINVAL;
+       }
+       /*
+        * make sure MPA receiver interoperate with the
+        * received MPA version and MPA key information
+        *
+        */
+       if (mpa_frame->rev != mpa_version) {
+               nes_debug(NES_DBG_CM, "The received mpa version"
+                               " can not be interoperated\n");
+               return -EINVAL;
+       }
+       if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {
+               if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE)) {
+                       nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");
+                       return -EINVAL;
+               }
+       } else {
+               if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE)) {
+                       nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");
+                       return -EINVAL;
+               }
+       }
 
        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;
 }
 
 
 /**
- * handle_exception_pkt - process an exception packet.
- * We have been in a TSA state, and we have now received SW
- * TCP/IP traffic should be a FIN request or IP pkt with options
- */
-static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb)
-{
-       int ret = 0;
-       struct tcphdr *tcph = tcp_hdr(skb);
-
-       /* first check to see if this a FIN pkt */
-       if (tcph->fin) {
-               /* we need to ACK the FIN request */
-               send_ack(cm_node);
-
-               /* check which side we are (client/server) and set next state accordingly */
-               if (cm_node->tcp_cntxt.client)
-                       cm_node->state = NES_CM_STATE_CLOSING;
-               else {
-                       /* we are the server side */
-                       cm_node->state = NES_CM_STATE_CLOSE_WAIT;
-                       /* since this is a self contained CM we don't wait for */
-                       /* an APP to close us, just send final FIN immediately */
-                       ret = send_fin(cm_node, NULL);
-                       cm_node->state = NES_CM_STATE_LAST_ACK;
-               }
-       } else {
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-
-/**
  * form_cm_frame - get a free packet and build empty frame Use
  * node info to build.
  */
-static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node,
-                                    void *options, u32 optionsize, void *data,
-                                    u32 datasize, u8 flags)
+static void form_cm_frame(struct sk_buff *skb,
+       struct nes_cm_node *cm_node, void *options, u32 optionsize,
+       void *data, u32 datasize, u8 flags)
 {
        struct tcphdr *tcph;
        struct iphdr *iph;
@@ -332,10 +377,12 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm
                cm_node->tcp_cntxt.loc_seq_num++;
                tcph->syn = 1;
        } else
-               cm_node->tcp_cntxt.loc_seq_num += datasize;     /* data (no headers) */
+               cm_node->tcp_cntxt.loc_seq_num += datasize;
 
-       if (flags & SET_FIN)
+       if (flags & SET_FIN) {
+               cm_node->tcp_cntxt.loc_seq_num++;
                tcph->fin = 1;
+       }
 
        if (flags & SET_RST)
                tcph->rst = 1;
@@ -352,7 +399,6 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm
        skb_shinfo(skb)->nr_frags = 0;
        cm_packets_created++;
 
-       return skb;
 }
 
 
@@ -369,7 +415,6 @@ static void print_core(struct nes_cm_core *core)
 
        nes_debug(NES_DBG_CM, "State         : %u \n",  core->state);
 
-       nes_debug(NES_DBG_CM, "Tx Free cnt   : %u \n", skb_queue_len(&core->tx_free_list));
        nes_debug(NES_DBG_CM, "Listen Nodes  : %u \n", atomic_read(&core->listen_node_cnt));
        nes_debug(NES_DBG_CM, "Active Nodes  : %u \n", atomic_read(&core->node_cnt));
 
@@ -389,16 +434,14 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
                int close_when_complete)
 {
        unsigned long  flags;
-       struct nes_cm_core *cm_core;
+       struct nes_cm_core *cm_core = cm_node->cm_core;
        struct nes_timer_entry *new_send;
        int ret = 0;
        u32 was_timer_set;
 
-       if (!cm_node)
-               return -EINVAL;
        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;
@@ -411,45 +454,40 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        new_send->close_when_complete = close_when_complete;
 
        if (type == NES_TIMER_TYPE_CLOSE) {
-               new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
-               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);
+               new_send->timetosend += (HZ/10);
+               if (cm_node->recv_entry) {
+                       kfree(new_send);
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
+               cm_node->recv_entry = new_send;
        }
 
        if (type == NES_TIMER_TYPE_SEND) {
                new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
                atomic_inc(&new_send->skb->users);
+               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+               cm_node->send_entry = new_send;
+               add_ref_cm_node(cm_node);
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
 
                ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
                if (ret != NETDEV_TX_OK) {
-                       nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n",
-                                       new_send, jiffies);
-                       atomic_dec(&new_send->skb->users);
+                       nes_debug(NES_DBG_CM, "Error sending packet %p "
+                               "(jiffies = %lu)\n", new_send, jiffies);
                        new_send->timetosend = jiffies;
+                       ret = NETDEV_TX_OK;
                } else {
                        cm_packets_sent++;
                        if (!send_retrans) {
+                               cleanup_retrans_entry(cm_node);
                                if (close_when_complete)
-                                       rem_ref_cm_node(cm_node->cm_core, cm_node);
-                               dev_kfree_skb_any(new_send->skb);
-                               kfree(new_send);
+                                       rem_ref_cm_node(cm_core, cm_node);
                                return ret;
                        }
-                       new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
                }
-               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-               list_add_tail(&new_send->list, &cm_node->retrans_list);
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
        }
-       if (type == NES_TIMER_TYPE_RECV) {
-               new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
-               new_send->timetosend = jiffies;
-               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);
-       }
-       cm_core = cm_node->cm_core;
 
        was_timer_set = timer_pending(&cm_core->tcp_timer);
 
@@ -461,199 +499,213 @@ 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)
+{
+       struct iw_cm_id *cm_id = cm_node->cm_id;
+       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:
+               if (cm_node->cm_id)
+                       cm_id->rem_ref(cm_id);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               send_reset(cm_node, NULL);
+               break;
+       default:
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, NULL);
+               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;
-       struct sk_buff *skb;
        u32 settimer = 0;
+       unsigned long timetosend;
        int ret = NETDEV_TX_OK;
-       int    node_done;
 
+       struct list_head timer_list;
+       INIT_LIST_HEAD(&timer_list);
        spin_lock_irqsave(&cm_core->ht_lock, flags);
 
-       list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) {
+       list_for_each_safe(list_node, list_core_temp,
+                               &cm_core->connected_nodes) {
                cm_node = container_of(list_node, struct nes_cm_node, list);
-               add_ref_cm_node(cm_node);
-               spin_unlock_irqrestore(&cm_core->ht_lock, flags);
-               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 ((time_after(recv_entry->timetosend, jiffies)) &&
-                                       (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
-                               if (nexttimeout > recv_entry->timetosend || !settimer) {
+               if ((cm_node->recv_entry) || (cm_node->send_entry)) {
+                       add_ref_cm_node(cm_node);
+                       list_add(&cm_node->timer_entry, &timer_list);
+               }
+       }
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       list_for_each_safe(list_node, list_core_temp, &timer_list) {
+               cm_node = container_of(list_node, struct nes_cm_node,
+                                       timer_entry);
+               recv_entry = cm_node->recv_entry;
+
+               if (recv_entry) {
+                       if (time_after(recv_entry->timetosend, jiffies)) {
+                               if (nexttimeout > recv_entry->timetosend ||
+                                               !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);
-                       if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
-                               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));
-                                       nes_rem_ref(&nesqp->ibqp);
-                               }
-                               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);
-               node_done = 0;
-               list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
-                       if (node_done) {
+               do {
+                       send_entry = cm_node->send_entry;
+                       if (!send_entry)
                                break;
-                       }
-                       send_entry = container_of(list_core, struct nes_timer_entry, list);
                        if (time_after(send_entry->timetosend, jiffies)) {
                                if (cm_node->state != NES_CM_STATE_TSA) {
-                                       if ((nexttimeout > send_entry->timetosend) || !settimer) {
-                                               nexttimeout = send_entry->timetosend;
+                                       if ((nexttimeout >
+                                               send_entry->timetosend) ||
+                                               !settimer) {
+                                               nexttimeout =
+                                                       send_entry->timetosend;
                                                settimer = 1;
                                        }
-                                       node_done = 1;
-                                       continue;
                                } else {
-                                       list_del(&send_entry->list);
-                                       skb = send_entry->skb;
-                                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                                       dev_kfree_skb_any(skb);
-                                       kfree(send_entry);
-                                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                                       continue;
+                                       free_retrans_entry(cm_node);
                                }
+                               break;
                        }
-                       if (send_entry->type == NES_TIMER_NODE_CLEANUP) {
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               kfree(send_entry);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
-                       }
-                       if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) ||
-                                       (cm_node->state == NES_CM_STATE_TSA) ||
-                                       (cm_node->state == NES_CM_STATE_CLOSED)) {
-                               skb = send_entry->skb;
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               kfree(send_entry);
-                               dev_kfree_skb_any(skb);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
+
+                       if ((cm_node->state == NES_CM_STATE_TSA) ||
+                               (cm_node->state == NES_CM_STATE_CLOSED)) {
+                               free_retrans_entry(cm_node);
+                               break;
                        }
 
-                       if (!send_entry->retranscount || !send_entry->retrycount) {
+                       if (!send_entry->retranscount ||
+                               !send_entry->retrycount) {
                                cm_packets_dropped++;
-                               skb = send_entry->skb;
-                               list_del(&send_entry->list);
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               dev_kfree_skb_any(skb);
-                               kfree(send_entry);
-                               if (cm_node->state == NES_CM_STATE_SYN_RCVD) {
-                                       /* this node never even generated an indication up to the cm */
-                                       rem_ref_cm_node(cm_core, cm_node);
-                               } else {
-                                       cm_node->state = NES_CM_STATE_CLOSED;
-                                       create_event(cm_node, NES_CM_EVENT_ABORTED);
-                               }
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
+                               free_retrans_entry(cm_node);
+
+                               spin_unlock_irqrestore(
+                                       &cm_node->retrans_list_lock, flags);
+                               nes_retrans_expired(cm_node);
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               spin_lock_irqsave(&cm_node->retrans_list_lock,
+                                       flags);
+                               break;
                        }
-                       /* this seems like the correct place, but leave send entry unprotected */
-                       /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */
                        atomic_inc(&send_entry->skb->users);
                        cm_packets_retrans++;
-                       nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
-                                       " jiffies = %lu, time to send =  %lu, retranscount = %u, "
-                                       "send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n",
-                                       send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount,
-                                       send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num);
-
-                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                       nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
+                               "for node %p, jiffies = %lu, time to send = "
+                               "%lu, retranscount = %u, send_entry->seq_num = "
+                               "0x%08X, cm_node->tcp_cntxt.rem_ack_num = "
+                               "0x%08X\n", send_entry, cm_node, jiffies,
+                               send_entry->timetosend,
+                               send_entry->retranscount,
+                               send_entry->seq_num,
+                               cm_node->tcp_cntxt.rem_ack_num);
+
+                       spin_unlock_irqrestore(&cm_node->retrans_list_lock,
+                               flags);
                        ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
+                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
                        if (ret != NETDEV_TX_OK) {
+                               nes_debug(NES_DBG_CM, "rexmit failed for "
+                                       "node=%p\n", cm_node);
                                cm_packets_bounced++;
-                               atomic_dec(&send_entry->skb->users);
                                send_entry->retrycount--;
                                nexttimeout = jiffies + NES_SHORT_TIME;
                                settimer = 1;
-                               node_done = 1;
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
+                               break;
                        } else {
                                cm_packets_sent++;
                        }
-                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                       list_del(&send_entry->list);
-                       nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n",
-                                       send_entry->retranscount, send_entry->retrycount);
+                       nes_debug(NES_DBG_CM, "Packet Sent: retrans count = "
+                               "%u, retry count = %u.\n",
+                               send_entry->retranscount,
+                               send_entry->retrycount);
                        if (send_entry->send_retrans) {
                                send_entry->retranscount--;
-                               send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
-                               if (nexttimeout > send_entry->timetosend || !settimer) {
+                               timetosend = (NES_RETRY_TIMEOUT <<
+                                       (NES_DEFAULT_RETRANS - send_entry->retranscount));
+
+                               send_entry->timetosend = jiffies +
+                                       min(timetosend, NES_MAX_TIMEOUT);
+                               if (nexttimeout > send_entry->timetosend ||
+                                       !settimer) {
                                        nexttimeout = send_entry->timetosend;
                                        settimer = 1;
                                }
-                               list_add(&send_entry->list, &cm_node->retrans_list);
-                               continue;
                        } else {
                                int close_when_complete;
-                               skb = send_entry->skb;
-                               close_when_complete = send_entry->close_when_complete;
-                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-                               if (close_when_complete) {
-                                       BUG_ON(atomic_read(&cm_node->ref_count) == 1);
-                                       rem_ref_cm_node(cm_core, cm_node);
-                               }
-                               dev_kfree_skb_any(skb);
-                               kfree(send_entry);
-                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-                               continue;
+                               close_when_complete =
+                                       send_entry->close_when_complete;
+                               nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n",
+                                       cm_node, cm_node->state);
+                               free_retrans_entry(cm_node);
+                               if (close_when_complete)
+                                       rem_ref_cm_node(cm_node->cm_core,
+                                               cm_node);
                        }
-               }
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               } while (0);
 
-               rem_ref_cm_node(cm_core, cm_node);
-
-               spin_lock_irqsave(&cm_core->ht_lock, flags);
-               if (ret != NETDEV_TX_OK)
-                       break;
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
        }
-       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 
        if (settimer) {
                if (!timer_pending(&cm_core->tcp_timer)) {
@@ -667,14 +719,14 @@ static void nes_cm_timer_tick(unsigned long pass)
 /**
  * send_syn
  */
-static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
+static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
+       struct sk_buff *skb)
 {
        int ret;
        int flags = SET_SYN;
-       struct sk_buff *skb;
        char optionsbuffer[sizeof(struct option_mss) +
-                       sizeof(struct option_windowscale) +
-                       sizeof(struct option_base) + 1];
+               sizeof(struct option_windowscale) + sizeof(struct option_base) +
+               TCP_OPTIONS_PADDING];
 
        int optionssize = 0;
        /* Sending MSS option */
@@ -695,8 +747,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
        options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
        optionssize += sizeof(struct option_windowscale);
 
-       if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)
-                       ) {
+       if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {
                options = (union all_known_options *)&optionsbuffer[optionssize];
                options->as_base.optionnum = OPTION_NUMBER_WRITE0;
                options->as_base.length = sizeof(struct option_base);
@@ -714,7 +765,8 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
        options->as_end = OPTION_NUMBER_END;
        optionssize += 1;
 
-       skb = get_free_pkt(cm_node);
+       if (!skb)
+               skb = dev_alloc_skb(MAX_CM_BUFFER);
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
                return -1;
@@ -733,18 +785,18 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
 /**
  * send_reset
  */
-static int send_reset(struct nes_cm_node *cm_node)
+static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
        int ret;
-       struct sk_buff *skb = get_free_pkt(cm_node);
        int flags = SET_RST | SET_ACK;
 
+       if (!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;
        }
 
-       add_ref_cm_node(cm_node);
        form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
        ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
 
@@ -755,10 +807,12 @@ static int send_reset(struct nes_cm_node *cm_node)
 /**
  * send_ack
  */
-static int send_ack(struct nes_cm_node *cm_node)
+static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
 {
        int ret;
-       struct sk_buff *skb = get_free_pkt(cm_node);
+
+       if (!skb)
+               skb = dev_alloc_skb(MAX_CM_BUFFER);
 
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
@@ -781,7 +835,7 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
 
        /* if we didn't get a frame get one */
        if (!skb)
-               skb = get_free_pkt(cm_node);
+               skb = dev_alloc_skb(MAX_CM_BUFFER);
 
        if (!skb) {
                nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
@@ -796,65 +850,18 @@ static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
 
 
 /**
- * get_free_pkt
- */
-static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
-{
-       struct sk_buff *skb, *new_skb;
-
-       /* check to see if we need to repopulate the free tx pkt queue */
-       if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
-               while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
-                               cm_node->cm_core->free_tx_pkt_max) {
-                       /* replace the frame we took, we won't get it back */
-                       new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
-                       BUG_ON(!new_skb);
-                       /* add a replacement frame to the free tx list head */
-                       skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
-               }
-       }
-
-       skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
-
-       return skb;
-}
-
-
-/**
- * make_hashkey - generate hash key from node tuple
- */
-static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
-               nes_addr_t rem_addr)
-{
-       u32 hashkey = 0;
-
-       hashkey = loc_addr + rem_addr + loc_port + rem_port;
-       hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
-
-       return hashkey;
-}
-
-
-/**
  * find_node - find a cm node that matches the reference cm node
  */
 static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
                u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
 {
        unsigned long flags;
-       u32 hashkey;
        struct list_head *hte;
        struct nes_cm_node *cm_node;
 
-       /* make a hash index key for this packet */
-       hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
-
        /* get a handle on the hte */
        hte = &cm_core->connected_nodes;
 
-       nes_debug(NES_DBG_CM, "Searching for an owner node: " NIPQUAD_FMT ":%x from core %p->%p\n",
-                 HIPQUAD(loc_addr), loc_port, cm_core, hte);
-
        /* walk list and find cm_node associated with this session ID */
        spin_lock_irqsave(&cm_core->ht_lock, flags);
        list_for_each_entry(cm_node, hte, list) {
@@ -902,9 +909,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
        }
        spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
 
-       nes_debug(NES_DBG_CM, "Unable to find listener for " NIPQUAD_FMT ":%x\n",
-                 HIPQUAD(dst_addr), dst_port);
-
        /* no listener */
        return NULL;
 }
@@ -916,18 +920,13 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
 static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
 {
        unsigned long flags;
-       u32 hashkey;
        struct list_head *hte;
 
        if (!cm_node || !cm_core)
                return -EINVAL;
 
-       nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n");
-
-       /* first, make an index into our hash table */
-       hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
-                       cm_node->rem_port, cm_node->rem_addr);
-       cm_node->hashkey = hashkey;
+       nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
+               cm_node);
 
        spin_lock_irqsave(&cm_core->ht_lock, flags);
 
@@ -946,10 +945,86 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
  * mini_cm_dec_refcnt_listen
  */
 static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
-               struct nes_cm_listener *listener, int free_hanging_nodes)
+       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;
+       struct nes_cm_node *cm_node = NULL;
+       struct list_head reset_list;
+
+       nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
+               "refcnt=%d\n", listener, free_hanging_nodes,
+               atomic_read(&listener->ref_count));
+       /* free non-accelerated child nodes for this listener */
+       INIT_LIST_HEAD(&reset_list);
+       if (free_hanging_nodes) {
+               spin_lock_irqsave(&cm_core->ht_lock, flags);
+               list_for_each_safe(list_pos, list_temp,
+                                  &g_cm_core->connected_nodes) {
+                       cm_node = container_of(list_pos, struct nes_cm_node,
+                               list);
+                       if ((cm_node->listener == listener) &&
+                           (!cm_node->accelerated)) {
+                               add_ref_cm_node(cm_node);
+                               list_add(&cm_node->reset_entry, &reset_list);
+                       }
+               }
+               spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+       }
+
+       list_for_each_safe(list_pos, list_temp, &reset_list) {
+               cm_node = container_of(list_pos, struct nes_cm_node,
+                               reset_entry);
+               {
+                       struct nes_cm_node *loopback = cm_node->loopbackpartner;
+                       enum nes_cm_node_state old_state;
+                       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 {
+                                               old_state = cm_node->state;
+                                               cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
+                                               if (old_state != NES_CM_STATE_MPAREQ_RCVD)
+                                                       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;
+                                       add_ref_cm_node(loopback);
+                                       loopback->state = NES_CM_STATE_CLOSED;
+                                       cm_event_connect_error(&event);
+                                       cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;
+
+                                       rem_ref_cm_node(cm_node->cm_core,
+                                                        cm_node);
+
+                               }
+                       }
+               }
+       }
+
        spin_lock_irqsave(&cm_core->listen_list_lock, flags);
        if (!atomic_dec_return(&listener->ref_count)) {
                list_del(&listener->list);
@@ -969,7 +1044,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
                kfree(listener);
                listener = NULL;
                ret = 0;
-               cm_listens_destroyed++;
+               atomic_inc(&cm_listens_destroyed);
        } else {
                spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
        }
@@ -1008,6 +1083,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);
        }
 
@@ -1022,26 +1098,60 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
 
 
 /**
- * nes_addr_send_arp
+ * nes_addr_resolve_neigh
  */
-static void nes_addr_send_arp(u32 dst_ip)
+static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpindex)
 {
        struct rtable *rt;
        struct flowi fl;
+       struct neighbour *neigh;
+       int rc = arpindex;
+       struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
 
        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;
+               return rc;
+       }
+
+       neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev);
+       if (neigh) {
+               if (neigh->nud_state & NUD_VALID) {
+                       nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
+                                 " is %pM, Gateway is 0x%08X \n", dst_ip,
+                                 neigh->ha, ntohl(rt->rt_gateway));
+
+                       if (arpindex >= 0) {
+                               if (!memcmp(nesadapter->arp_table[arpindex].mac_addr,
+                                                       neigh->ha, ETH_ALEN)){
+                                       /* Mac address same as in nes_arp_table */
+                                       neigh_release(neigh);
+                                       ip_rt_put(rt);
+                                       return rc;
+                               }
+
+                               nes_manage_arp_cache(nesvnic->netdev,
+                                               nesadapter->arp_table[arpindex].mac_addr,
+                                               dst_ip, NES_ARP_DELETE);
+                       }
+
+                       nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
+                                            dst_ip, NES_ARP_ADD);
+                       rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
+                                          NES_ARP_RESOLVE);
+               }
+               neigh_release(neigh);
        }
 
-       neigh_event_send(rt->u.dst.neighbour, NULL);
+       if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
+               neigh_event_send(rt->u.dst.neighbour, NULL);
+
        ip_rt_put(rt);
+       return rc;
 }
 
-
 /**
  * make_cm_node - create a new instance of a cm node
  */
@@ -1051,10 +1161,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
 {
        struct nes_cm_node *cm_node;
        struct timespec ts;
+       int oldarpindex = 0;
        int arpindex = 0;
        struct nes_device *nesdev;
        struct nes_adapter *nesadapter;
-       DECLARE_MAC_BUF(mac);
 
        /* create an hte and cm_node for this instance */
        cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
@@ -1067,21 +1177,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
        cm_node->loc_port = cm_info->loc_port;
        cm_node->rem_port = cm_info->rem_port;
        cm_node->send_write0 = send_first;
-       nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT ":%x, rem = " NIPQUAD_FMT ":%x\n",
-                 HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
-                 HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
+       nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",
+                 &cm_node->loc_addr, cm_node->loc_port,
+                 &cm_node->rem_addr, cm_node->rem_port);
        cm_node->listener = listener;
        cm_node->netdev = nesvnic->netdev;
        cm_node->cm_id = cm_info->cm_id;
        memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
 
-       nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n",
-                       cm_node->listener, cm_node->cm_id);
+       nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener,
+                       cm_node->cm_id);
 
-       INIT_LIST_HEAD(&cm_node->retrans_list);
        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);
@@ -1108,18 +1215,24 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
        nesadapter = nesdev->nesadapter;
 
        cm_node->loopbackpartner = NULL;
+
        /* get the mac addr for the remote node */
-       arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+       if (ipv4_is_loopback(htonl(cm_node->rem_addr)))
+               arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE);
+       else {
+               oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+               arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex);
+
+       }
        if (arpindex < 0) {
                kfree(cm_node);
-               nes_addr_send_arp(cm_info->rem_addr);
                return NULL;
        }
 
        /* copy the mac addr to node context */
        memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
-       nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %s\n",
-                 print_mac(mac, cm_node->rem_mac));
+       nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n",
+                 cm_node->rem_mac);
 
        add_hte_node(cm_core, cm_node);
        atomic_inc(&cm_nodes_created);
@@ -1142,13 +1255,9 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)
  * rem_ref_cm_node - destroy an instance of a cm node
  */
 static int rem_ref_cm_node(struct nes_cm_core *cm_core,
-               struct nes_cm_node *cm_node)
+       struct nes_cm_node *cm_node)
 {
-       unsigned long flags, qplockflags;
-       struct nes_timer_entry *send_entry;
-       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)
@@ -1169,75 +1278,38 @@ 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);
        }
-
-       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-       list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
-               send_entry = container_of(list_core, struct nes_timer_entry, list);
-               list_del(&send_entry->list);
-               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-               dev_kfree_skb_any(send_entry->skb);
-               kfree(send_entry);
-               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
-               continue;
-       }
-       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
-
-       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);
-               if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
-                       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);
-                               nes_rem_ref(&nesqp->ibqp);
-                       }
-                       cm_id->rem_ref(cm_id);
-               } else if (recv_entry->type == NES_TIMER_TYPE_RECV) {
-                       dev_kfree_skb_any(recv_entry->skb);
-               }
-               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 {
                if (cm_node->apbvt_set && cm_node->nesvnic) {
                        nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
-                                       PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
-                                       NES_MANAGE_APBVT_DEL);
+                               PCI_FUNC(
+                               cm_node->nesvnic->nesdev->pcidev->devfn),
+                               NES_MANAGE_APBVT_DEL);
                }
        }
 
-       kfree(cm_node);
        atomic_dec(&cm_core->node_cnt);
        atomic_inc(&cm_nodes_destroyed);
+       nesqp = cm_node->nesqp;
+       if (nesqp) {
+               nesqp->cm_node = NULL;
+               nes_rem_ref(&nesqp->ibqp);
+               cm_node->nesqp = NULL;
+       }
 
+       kfree(cm_node);
        return 0;
 }
 
-
 /**
  * process_options
  */
-static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet)
+static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,
+       u32 optionsize, u32 syn_packet)
 {
        u32 tmp;
        u32 offset = 0;
@@ -1247,35 +1319,37 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
        while (offset < optionsize) {
                all_options = (union all_known_options *)(optionsloc + offset);
                switch (all_options->as_base.optionnum) {
-                       case OPTION_NUMBER_END:
-                               offset = optionsize;
-                               break;
-                       case OPTION_NUMBER_NONE:
-                               offset += 1;
-                               continue;
-                       case OPTION_NUMBER_MSS:
-                               nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n",
-                                               __func__,
-                                               all_options->as_mss.length, offset, optionsize);
-                               got_mss_option = 1;
-                               if (all_options->as_mss.length != 4) {
-                                       return 1;
-                               } else {
-                                       tmp = ntohs(all_options->as_mss.mss);
-                                       if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss)
-                                               cm_node->tcp_cntxt.mss = tmp;
-                               }
-                               break;
-                       case OPTION_NUMBER_WINDOW_SCALE:
-                               cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount;
-                               break;
-                       case OPTION_NUMBER_WRITE0:
-                               cm_node->send_write0 = 1;
-                               break;
-                       default:
-                               nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
-                                               all_options->as_base.optionnum);
-                               break;
+               case OPTION_NUMBER_END:
+                       offset = optionsize;
+                       break;
+               case OPTION_NUMBER_NONE:
+                       offset += 1;
+                       continue;
+               case OPTION_NUMBER_MSS:
+                       nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d "
+                               "Size: %d\n", __func__,
+                               all_options->as_mss.length, offset, optionsize);
+                       got_mss_option = 1;
+                       if (all_options->as_mss.length != 4) {
+                               return 1;
+                       } else {
+                               tmp = ntohs(all_options->as_mss.mss);
+                               if (tmp > 0 && tmp <
+                                       cm_node->tcp_cntxt.mss)
+                                       cm_node->tcp_cntxt.mss = tmp;
+                       }
+                       break;
+               case OPTION_NUMBER_WINDOW_SCALE:
+                       cm_node->tcp_cntxt.snd_wscale =
+                               all_options->as_windowscale.shiftcount;
+                       break;
+               case OPTION_NUMBER_WRITE0:
+                       cm_node->send_write0 = 1;
+                       break;
+               default:
+                       nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
+                               all_options->as_base.optionnum);
+                       break;
                }
                offset += all_options->as_base.length;
        }
@@ -1284,300 +1358,598 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
        return 0;
 }
 
+static void drop_packet(struct sk_buff *skb)
+{
+       atomic_inc(&cm_accel_dropped_pkts);
+       dev_kfree_skb_any(skb);
+}
 
-/**
- * process_packet
- */
-static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
-                         struct nes_cm_core *cm_core)
+static void handle_fin_pkt(struct nes_cm_node *cm_node)
 {
-       int optionsize;
-       int datasize;
-       int ret = 0;
-       struct tcphdr *tcph = tcp_hdr(skb);
-       u32 inc_sequence;
-       if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) {
-               inc_sequence = ntohl(tcph->seq);
-               cm_node->tcp_cntxt.rcv_nxt = inc_sequence;
+       nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
+               "refcnt=%d\n", cm_node, cm_node->state,
+               atomic_read(&cm_node->ref_count));
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_MPAREJ_RCVD:
+               cm_node->tcp_cntxt.rcv_nxt++;
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_LAST_ACK;
+               send_fin(cm_node, NULL);
+               break;
+       case NES_CM_STATE_MPAREQ_SENT:
+               create_event(cm_node, NES_CM_EVENT_ABORTED);
+               cm_node->tcp_cntxt.rcv_nxt++;
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, NULL);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+               cm_node->tcp_cntxt.rcv_nxt++;
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSING;
+               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->tcp_cntxt.rcv_nxt++;
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_TIME_WAIT;
+               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->tcp_cntxt.rcv_nxt++;
+               cleanup_retrans_entry(cm_node);
+               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);
+               break;
        }
+}
 
-       if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) {
-               BUG_ON(!tcph);
-               atomic_inc(&cm_accel_dropped_pkts);
-               return -1;
+
+static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+
+       int     reset = 0;      /* whether to send reset in case of err.. */
+       int     passive_state;
+       atomic_inc(&cm_resets_recvd);
+       nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
+                       " refcnt=%d\n", cm_node, cm_node->state,
+                       atomic_read(&cm_node->ref_count));
+       cleanup_retrans_entry(cm_node);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case 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, cm_node->state);
+               active_open_err(cm_node, skb, reset);
+               break;
+       case NES_CM_STATE_MPAREQ_RCVD:
+               passive_state = atomic_add_return(1, &cm_node->passive_state);
+               if (passive_state ==  NES_SEND_RESET_EVENT)
+                       create_event(cm_node, NES_CM_EVENT_RESET);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               dev_kfree_skb_any(skb);
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_LISTENING:
+               nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
+               passive_open_err(cm_node, skb, reset);
+               break;
+       case NES_CM_STATE_TSA:
+               active_open_err(cm_node, skb, reset);
+               break;
+       case NES_CM_STATE_CLOSED:
+               drop_packet(skb);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_LAST_ACK:
+               cm_node->cm_id->rem_ref(cm_node->cm_id);
+       case NES_CM_STATE_TIME_WAIT:
+               cm_node->state = NES_CM_STATE_CLOSED;
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               drop_packet(skb);
+               break;
+       default:
+               drop_packet(skb);
+               break;
        }
+}
 
-       if (tcph->rst) {
-               atomic_inc(&cm_resets_recvd);
-               nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n",
-                               cm_node, cm_node->state, atomic_read(&cm_node->ref_count));
-               switch (cm_node->state) {
-                       case NES_CM_STATE_LISTENING:
-                               rem_ref_cm_node(cm_core, cm_node);
-                               break;
-                       case NES_CM_STATE_TSA:
-                       case NES_CM_STATE_CLOSED:
-                               break;
-                       case NES_CM_STATE_SYN_RCVD:
-                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
-                                                       " remote 0x%08X:%04X, node state = %u\n",
-                                                       cm_node->loc_addr, cm_node->loc_port,
-                                                       cm_node->rem_addr, cm_node->rem_port,
-                                                       cm_node->state);
-                               rem_ref_cm_node(cm_core, cm_node);
-                               break;
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                       default:
-                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
-                                                       " remote 0x%08X:%04X, node state = %u refcnt=%d\n",
-                                                       cm_node->loc_addr, cm_node->loc_port,
-                                                       cm_node->rem_addr, cm_node->rem_port,
-                                                       cm_node->state, atomic_read(&cm_node->ref_count));
-                               /* create event */
-                               cm_node->state = NES_CM_STATE_CLOSED;
 
-                               create_event(cm_node, NES_CM_EVENT_ABORTED);
-                               break;
+static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
 
+       int     ret = 0;
+       int datasize = skb->len;
+       u8 *dataloc = skb->data;
+
+       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 (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,
+                               cm_node->state);
+                       active_open_err(cm_node, skb, 1);
+               } else {
+                       passive_open_err(cm_node, skb, 1);
                }
-               return -1;
+               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:
+               cleanup_retrans_entry(cm_node);
+               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;
+               }
+
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+       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)
+{
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case 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, cm_node->state);
+               active_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_SYN_RCVD:
+               passive_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_TSA:
+       default:
+               drop_packet(skb);
+       }
+}
+
+static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb)
+{
+       int err;
+
+       err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1;
+       if (err)
+               active_open_err(cm_node, skb, 1);
+
+       return err;
+}
+
+static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb)
+{
+       int err = 0;
+       u32 seq;
+       u32 ack_seq;
+       u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;
+       u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
+       u32 rcv_wnd;
+       seq = ntohl(tcph->seq);
+       ack_seq = ntohl(tcph->ack_seq);
+       rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
+       if (ack_seq != loc_seq_num)
+               err = 1;
+       else if (!between(seq, rcv_nxt, (rcv_nxt+rcv_wnd)))
+               err = 1;
+       if (err) {
+               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, cm_node->state);
+               indicate_pkt_err(cm_node, skb);
+               nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X "
+                       "rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt,
+                       rcv_wnd);
+       }
+       return err;
+}
+
+/*
+ * handle_syn_pkt() is for Passive node. The syn packet is received when a node
+ * is created with a listener or it may comein as rexmitted packet which in
+ * that case will be just dropped.
+ */
+
+static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+       int ret;
+       u32 inc_sequence;
+       int optionsize;
+
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+       skb_trim(skb, 0);
+       inc_sequence = ntohl(tcph->seq);
 
-       skb_pull(skb, ip_hdr(skb)->ihl << 2);
-       skb_pull(skb, tcph->doff << 2);
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_MPAREQ_SENT:
+               /* Rcvd syn on active open connection*/
+               active_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_LISTENING:
+               /* Passive OPEN */
+               if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
+                               cm_node->listener->backlog) {
+                       nes_debug(NES_DBG_CM, "drop syn due to backlog "
+                               "pressure \n");
+                       cm_backlog_drops++;
+                       passive_open_err(cm_node, skb, 0);
+                       break;
+               }
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize,
+                       1);
+               if (ret) {
+                       passive_open_err(cm_node, skb, 0);
+                       /* drop pkt */
+                       break;
+               }
+               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;
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, skb);
+               break;
+       case NES_CM_STATE_TSA:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_FIN_WAIT2:
+       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);
+               break;
+       }
+}
 
-       datasize = skb->len;
+static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+
+       int ret;
+       u32 inc_sequence;
+       int optionsize;
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+       skb_trim(skb, 0);
        inc_sequence = ntohl(tcph->seq);
-       nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X,"
-                       " rcv_nxt = 0x%08X Flags: %s %s.\n",
-                       datasize, inc_sequence, ntohl(tcph->ack_seq),
-                       cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""),
-                       (tcph->ack ? "ACK":""));
-
-       if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt)
-               ) {
-               nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X,"
-                               " ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n",
-                               datasize, inc_sequence, ntohl(tcph->ack_seq),
-                               cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":""));
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       rem_ref_cm_node(cm_core, cm_node);
+       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;
+               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               /* setup options */
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);
+               if (ret) {
+                       nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n",
+                               cm_node);
+                       break;
                }
-               return -1;
+               cleanup_retrans_entry(cm_node);
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
+               send_mpa_request(cm_node, skb);
+               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
+               break;
+       case NES_CM_STATE_MPAREQ_RCVD:
+               /* passive open, so should not be here */
+               passive_open_err(cm_node, skb, 1);
+               break;
+       case NES_CM_STATE_LISTENING:
+               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               send_reset(cm_node, skb);
+               break;
+       case NES_CM_STATE_CLOSED:
+               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+               cleanup_retrans_entry(cm_node);
+               add_ref_cm_node(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:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_TSA:
+       case NES_CM_STATE_CLOSING:
+       case NES_CM_STATE_UNKNOWN:
+       case NES_CM_STATE_MPAREQ_SENT:
+       default:
+               drop_packet(skb);
+               break;
+       }
+}
+
+static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct tcphdr *tcph)
+{
+       int datasize = 0;
+       u32 inc_sequence;
+       u32 rem_seq_ack;
+       u32 rem_seq;
+       int ret = 0;
+       int optionsize;
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+
+       if (check_seq(cm_node, tcph, skb))
+               return -EINVAL;
+
+       skb_pull(skb, tcph->doff << 2);
+       inc_sequence = ntohl(tcph->seq);
+       rem_seq = ntohl(tcph->seq);
+       rem_seq_ack =  ntohl(tcph->ack_seq);
+       datasize = skb->len;
+       switch (cm_node->state) {
+       case NES_CM_STATE_SYN_RCVD:
+               /* Passive OPEN */
+               cleanup_retrans_entry(cm_node);
+               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->state = NES_CM_STATE_ESTABLISHED;
+               if (datasize) {
+                       cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       handle_rcv_mpa(cm_node, skb);
+               } else  /* rcvd ACK only */
+                       dev_kfree_skb_any(skb);
+               break;
+       case NES_CM_STATE_ESTABLISHED:
+               /* Passive OPEN */
+               cleanup_retrans_entry(cm_node);
+               if (datasize) {
+                       cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+                       handle_rcv_mpa(cm_node, skb);
+               } else
+                       drop_packet(skb);
+               break;
+       case NES_CM_STATE_MPAREQ_SENT:
+               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);
+               } else  /* Could be just an ack pkt.. */
+                       dev_kfree_skb_any(skb);
+               break;
+       case NES_CM_STATE_LISTENING:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               send_reset(cm_node, skb);
+               break;
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, skb);
+               break;
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_CLOSING:
+               cleanup_retrans_entry(cm_node);
+               cm_node->state = NES_CM_STATE_CLOSED;
+               cm_node->cm_id->rem_ref(cm_node->cm_id);
+               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_UNKNOWN:
+       default:
+               cleanup_retrans_entry(cm_node);
+               drop_packet(skb);
+               break;
        }
+       return ret;
+}
 
-               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
 
 
+static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
+       struct sk_buff *skb, int optionsize, int passive)
+{
+       u8 *optionsloc = (u8 *)&tcph[1];
        if (optionsize) {
-               u8 *optionsloc = (u8 *)&tcph[1];
-               if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) {
-                       nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __func__, cm_node);
-                       send_reset(cm_node);
-                       if (cm_node->state != NES_CM_STATE_SYN_SENT)
-                       rem_ref_cm_node(cm_core, cm_node);
-                       return 0;
+               if (process_options(cm_node, optionsloc, optionsize,
+                       (u32)tcph->syn)) {
+                       nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
+                               __func__, cm_node);
+                       if (passive)
+                               passive_open_err(cm_node, skb, 1);
+                       else
+                               active_open_err(cm_node, skb, 1);
+                       return 1;
                }
-       } else if (tcph->syn)
-               cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+       }
 
        cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
                        cm_node->tcp_cntxt.snd_wscale;
 
-       if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) {
+       if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)
                cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
-       }
+       return 0;
+}
 
-       if (tcph->ack) {
-               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
-               switch (cm_node->state) {
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                               /* read and stash current sequence number */
-                               if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) {
-                                       nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !="
-                                                       " cm_node->tcp_cntxt.loc_seq_num\n");
-                                       send_reset(cm_node);
-                                       return 0;
-                               }
-                               if (cm_node->state == NES_CM_STATE_SYN_SENT)
-                                       cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
-                               else {
-                                               cm_node->state = NES_CM_STATE_ESTABLISHED;
-                               }
-                               break;
-                       case NES_CM_STATE_LAST_ACK:
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_FIN_WAIT1:
-                               cm_node->state = NES_CM_STATE_FIN_WAIT2;
-                               break;
-                       case NES_CM_STATE_CLOSING:
-                               cm_node->state = NES_CM_STATE_TIME_WAIT;
-                               /* need to schedule this to happen in 2MSL timeouts */
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_TIME_WAIT:
-                       case NES_CM_STATE_CLOSED:
-                               break;
-                       case NES_CM_STATE_LISTENING:
-                               nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn);
-                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
-                               send_reset(cm_node);
-                               /* send_reset bumps refcount, this should have been a new node */
-                               rem_ref_cm_node(cm_core, cm_node);
-                               return -1;
-                               break;
-                       case NES_CM_STATE_TSA:
-                               nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n");
-                               break;
-                       case NES_CM_STATE_UNKNOWN:
-                       case NES_CM_STATE_INITED:
-                       case NES_CM_STATE_ACCEPTING:
-                       case NES_CM_STATE_FIN_WAIT2:
-                       default:
-                               nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n",
-                                               cm_node->state);
-                               send_reset(cm_node);
-                               break;
-               }
-       }
+/*
+ * active_open_err() will send reset() if flag set..
+ * It will also send ABORT event.
+ */
 
-       if (tcph->syn) {
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       /* do not exceed backlog */
-                       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 pressure \n");
-                               cm_backlog_drops++;
-                               atomic_dec(&cm_node->listener->pend_accepts_cnt);
-                               rem_ref_cm_node(cm_core, cm_node);
-                               return 0;
-                       }
-                       cm_node->accept_pend = 1;
+static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       int reset)
+{
+       cleanup_retrans_entry(cm_node);
+       if (reset) {
+               nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, "
+                               "state=%d\n", cm_node, cm_node->state);
+               add_ref_cm_node(cm_node);
+               send_reset(cm_node, skb);
+       } else
+               dev_kfree_skb_any(skb);
 
-               }
-               if (datasize == 0)
-                       cm_node->tcp_cntxt.rcv_nxt ++;
+       cm_node->state = NES_CM_STATE_CLOSED;
+       create_event(cm_node, NES_CM_EVENT_ABORTED);
+}
 
-               if (cm_node->state == NES_CM_STATE_LISTENING) {
-                       cm_node->state = NES_CM_STATE_SYN_RCVD;
-                       send_syn(cm_node, 1);
-               }
-               if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
-                       cm_node->state = NES_CM_STATE_ESTABLISHED;
-                       /* send final handshake ACK */
-                       ret = send_ack(cm_node);
-                       if (ret < 0)
-                               return ret;
+/*
+ * passive_open_err() will either do a reset() or will free up the skb and
+ * remove the cm_node.
+ */
 
-                               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
-                               ret = send_mpa_request(cm_node);
-                               if (ret < 0)
-                                       return ret;
-               }
+static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       int reset)
+{
+       cleanup_retrans_entry(cm_node);
+       cm_node->state = NES_CM_STATE_CLOSED;
+       if (reset) {
+               nes_debug(NES_DBG_CM, "passive_open_err sending RST for "
+                       "cm_node=%p state =%d\n", cm_node, cm_node->state);
+               send_reset(cm_node, skb);
+       } else {
+               dev_kfree_skb_any(skb);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
        }
+}
 
-       if (tcph->fin) {
-               cm_node->tcp_cntxt.rcv_nxt++;
-               switch (cm_node->state) {
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-                       case NES_CM_STATE_ESTABLISHED:
-                       case NES_CM_STATE_ACCEPTING:
-                       case NES_CM_STATE_MPAREQ_SENT:
-                               cm_node->state = NES_CM_STATE_CLOSE_WAIT;
-                               cm_node->state = NES_CM_STATE_LAST_ACK;
-                               ret = send_fin(cm_node, NULL);
-                               break;
-                       case NES_CM_STATE_FIN_WAIT1:
-                               cm_node->state = NES_CM_STATE_CLOSING;
-                               ret = send_ack(cm_node);
-                               break;
-                       case NES_CM_STATE_FIN_WAIT2:
-                               cm_node->state = NES_CM_STATE_TIME_WAIT;
-                               cm_node->tcp_cntxt.loc_seq_num ++;
-                               ret = send_ack(cm_node);
-                               /* need to schedule this to happen in 2MSL timeouts */
-                               cm_node->state = NES_CM_STATE_CLOSED;
-                               break;
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_LAST_ACK:
-                       case NES_CM_STATE_CLOSING:
-                       case NES_CM_STATE_TSA:
-                       default:
-                               nes_debug(NES_DBG_CM, "Received a fin while in %x state\n",
-                                               cm_node->state);
-                               ret = -EINVAL;
-                               break;
-               }
+/*
+ * free_retrans_entry() routines assumes that the retrans_list_lock has
+ * been acquired before calling.
+ */
+static void free_retrans_entry(struct nes_cm_node *cm_node)
+{
+       struct nes_timer_entry *send_entry;
+       send_entry = cm_node->send_entry;
+       if (send_entry) {
+               cm_node->send_entry = NULL;
+               dev_kfree_skb_any(send_entry->skb);
+               kfree(send_entry);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
        }
+}
 
-       if (datasize) {
-               u8 *dataloc = skb->data;
-               /* figure out what state we are in and handle transition to next state */
-               switch (cm_node->state) {
-                       case NES_CM_STATE_LISTENING:
-                       case NES_CM_STATE_SYN_RCVD:
-                       case NES_CM_STATE_SYN_SENT:
-                       case NES_CM_STATE_FIN_WAIT1:
-                       case NES_CM_STATE_FIN_WAIT2:
-                       case NES_CM_STATE_CLOSE_WAIT:
-                       case NES_CM_STATE_LAST_ACK:
-                       case NES_CM_STATE_CLOSING:
-                               break;
-                       case  NES_CM_STATE_MPAREQ_SENT:
-                               /* recv the mpa res frame, ret=frame len (incl priv data) */
-                               ret = parse_mpa(cm_node, dataloc, datasize);
-                               if (ret < 0)
-                                       break;
-                               /* set the req frame payload len in skb */
-                               /* we are done handling this state, set node to a TSA state */
-                               cm_node->state = NES_CM_STATE_TSA;
-                               send_ack(cm_node);
-                               create_event(cm_node, NES_CM_EVENT_CONNECTED);
-                               break;
-
-                       case  NES_CM_STATE_ESTABLISHED:
-                               /* we are expecting an MPA req frame */
-                               ret = parse_mpa(cm_node, dataloc, datasize);
-                               if (ret < 0) {
-                                       break;
-                               }
-                               cm_node->state = NES_CM_STATE_TSA;
-                               send_ack(cm_node);
-                               /* we got a valid MPA request, create an event */
-                               create_event(cm_node, NES_CM_EVENT_MPA_REQ);
-                               break;
-                       case  NES_CM_STATE_TSA:
-                               handle_exception_pkt(cm_node, skb);
-                               break;
-                       case NES_CM_STATE_UNKNOWN:
-                       case NES_CM_STATE_INITED:
-                       default:
-                               ret = -1;
-               }
-       }
+static void cleanup_retrans_entry(struct nes_cm_node *cm_node)
+{
+       unsigned long flags;
 
-       return ret;
+       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+       free_retrans_entry(cm_node);
+       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
 }
 
+/**
+ * process_packet
+ * Returns skb if to be freed, else it will return NULL if already used..
+ */
+static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
+       struct nes_cm_core *cm_core)
+{
+       enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
+       struct tcphdr *tcph = tcp_hdr(skb);
+       u32     fin_set = 0;
+       int ret = 0;
+       skb_pull(skb, ip_hdr(skb)->ihl << 2);
+
+       nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
+               "ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn,
+               tcph->ack, tcph->rst, tcph->fin);
+
+       if (tcph->rst)
+               pkt_type = NES_PKT_TYPE_RST;
+       else if (tcph->syn) {
+               pkt_type = NES_PKT_TYPE_SYN;
+               if (tcph->ack)
+                       pkt_type = NES_PKT_TYPE_SYNACK;
+       } else if (tcph->ack)
+               pkt_type = NES_PKT_TYPE_ACK;
+       if (tcph->fin)
+               fin_set = 1;
+
+       switch (pkt_type) {
+       case NES_PKT_TYPE_SYN:
+               handle_syn_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_SYNACK:
+               handle_synack_pkt(cm_node, skb, tcph);
+               break;
+       case NES_PKT_TYPE_ACK:
+               ret = handle_ack_pkt(cm_node, skb, tcph);
+               if (fin_set && !ret)
+                       handle_fin_pkt(cm_node);
+               break;
+       case NES_PKT_TYPE_RST:
+               handle_rst_pkt(cm_node, skb, tcph);
+               break;
+       default:
+               if ((fin_set) && (!check_seq(cm_node, tcph, skb)))
+                       handle_fin_pkt(cm_node);
+               drop_packet(skb);
+               break;
+       }
+}
 
 /**
  * mini_cm_listen - create a listen node with params
  */
 static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
-               struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
+       struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
 {
        struct nes_cm_listener *listener;
        unsigned long flags;
@@ -1645,65 +2017,77 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
  * mini_cm_connect - make a connection node with params
  */
 static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
-                                          struct nes_vnic *nesvnic,
-                                          struct ietf_mpa_frame *mpa_frame,
-                                          struct nes_cm_info *cm_info)
+       struct nes_vnic *nesvnic, u16 private_data_len,
+       void *private_data, struct nes_cm_info *cm_info)
 {
        int ret = 0;
        struct nes_cm_node *cm_node;
        struct nes_cm_listener *loopbackremotelistener;
        struct nes_cm_node *loopbackremotenode;
        struct nes_cm_info loopback_cm_info;
-
-       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
-                       ntohs(mpa_frame->priv_data_len);
-
-       cm_info->loc_addr = htonl(cm_info->loc_addr);
-       cm_info->rem_addr = htonl(cm_info->rem_addr);
-       cm_info->loc_port = htons(cm_info->loc_port);
-       cm_info->rem_port = htons(cm_info->rem_port);
+       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len;
+       struct ietf_mpa_frame *mpa_frame = NULL;
 
        /* create a CM connection node */
        cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
        if (!cm_node)
                return NULL;
+       mpa_frame = &cm_node->mpa_frame;
+       memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE);
+       mpa_frame->flags = IETF_MPA_FLAGS_CRC;
+       mpa_frame->rev =  IETF_MPA_VERSION;
+       mpa_frame->priv_data_len = htons(private_data_len);
 
        /* set our node side to client (active) side */
        cm_node->tcp_cntxt.client = 1;
        cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
 
        if (cm_info->loc_addr == cm_info->rem_addr) {
-               loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr,
-                               cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE);
+               loopbackremotelistener = find_listener(cm_core,
+                               ntohl(nesvnic->local_ipaddr), cm_node->rem_port,
+                               NES_CM_LISTENER_ACTIVE_STATE);
                if (loopbackremotelistener == NULL) {
                        create_event(cm_node, NES_CM_EVENT_ABORTED);
                } else {
-                       atomic_inc(&cm_loopbacks);
                        loopback_cm_info = *cm_info;
                        loopback_cm_info.loc_port = cm_info->rem_port;
                        loopback_cm_info.rem_port = cm_info->loc_port;
                        loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
-                       loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info,
-                                       loopbackremotelistener);
+                       loopbackremotenode = make_cm_node(cm_core, nesvnic,
+                               &loopback_cm_info, loopbackremotelistener);
+                       if (!loopbackremotenode) {
+                               rem_ref_cm_node(cm_node->cm_core, cm_node);
+                               return NULL;
+                       }
+                       atomic_inc(&cm_loopbacks);
                        loopbackremotenode->loopbackpartner = cm_node;
-                       loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+                       loopbackremotenode->tcp_cntxt.rcv_wscale =
+                               NES_CM_DEFAULT_RCV_WND_SCALE;
                        cm_node->loopbackpartner = loopbackremotenode;
-                       memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data,
-                                       mpa_frame_size);
-                       loopbackremotenode->mpa_frame_size = mpa_frame_size -
-                                       sizeof(struct ietf_mpa_frame);
+                       memcpy(loopbackremotenode->mpa_frame_buf, private_data,
+                               private_data_len);
+                       loopbackremotenode->mpa_frame_size = private_data_len;
 
-                       /* we are done handling this state, set node to a TSA state */
+                       /* we are done handling this state. */
+                       /* set node to a TSA state */
                        cm_node->state = NES_CM_STATE_TSA;
-                       cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
-                       loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
-                       cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
-                       loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
-                       cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
-                       loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
-                       cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale;
-                       loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale;
-
+                       cm_node->tcp_cntxt.rcv_nxt =
+                               loopbackremotenode->tcp_cntxt.loc_seq_num;
+                       loopbackremotenode->tcp_cntxt.rcv_nxt =
+                               cm_node->tcp_cntxt.loc_seq_num;
+                       cm_node->tcp_cntxt.max_snd_wnd =
+                               loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.max_snd_wnd =
+                               cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wnd =
+                               loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.snd_wnd =
+                               cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wscale =
+                               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;
@@ -1712,16 +2096,29 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
        /* set our node side to client (active) side */
        cm_node->tcp_cntxt.client = 1;
        /* init our MPA frame ptr */
-       memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size);
+       memcpy(mpa_frame->priv_data, private_data, private_data_len);
+
        cm_node->mpa_frame_size = mpa_frame_size;
 
        /* send a syn and goto syn sent state */
        cm_node->state = NES_CM_STATE_SYN_SENT;
-       ret = send_syn(cm_node, 0);
+       ret = send_syn(cm_node, 0, NULL);
+
+       if (ret) {
+               /* error in sending the syn free up the cm_node struct */
+               nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest "
+                       "addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n",
+                       cm_node->rem_addr, cm_node->rem_port, cm_node,
+                       cm_node->cm_id);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               cm_node = NULL;
+       }
 
-       nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x,"
-                       " cm_node=%p, cm_id = %p.\n",
-                       cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id);
+       if (cm_node)
+               nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X,"
+                       "port=0x%04x, cm_node=%p, cm_id = %p.\n",
+                       cm_node->rem_addr, cm_node->rem_port, cm_node,
+                       cm_node->cm_id);
 
        return cm_node;
 }
@@ -1731,8 +2128,8 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
  * mini_cm_accept - accept a connection
  * This function is never called
  */
-static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame,
-                         struct nes_cm_node *cm_node)
+static int mini_cm_accept(struct nes_cm_core *cm_core,
+       struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        return 0;
 }
@@ -1742,30 +2139,61 @@ static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mp
  * mini_cm_reject - reject and teardown a connection
  */
 static int mini_cm_reject(struct nes_cm_core *cm_core,
-                         struct ietf_mpa_frame *mpa_frame,
-                         struct nes_cm_node *cm_node)
+       struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        int ret = 0;
-       struct sk_buff *skb;
-       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
-                       ntohs(mpa_frame->priv_data_len);
+       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;
 
-       skb = get_free_pkt(cm_node);
-       if (!skb) {
-               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
-               return -1;
-       }
+       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);
 
-       /* send an MPA Request frame */
-       form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN);
-       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+       if (cm_node->tcp_cntxt.client)
+               return ret;
+       cleanup_retrans_entry(cm_node);
 
-       cm_node->state = NES_CM_STATE_CLOSED;
-       ret = send_fin(cm_node, NULL);
+       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 {
+                       if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
+                               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;
+               if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {
+                       rem_ref_cm_node(cm_core, cm_node);
+                       rem_ref_cm_node(cm_core, loopback);
+               } else {
+                       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);
+                       loopback->state = NES_CM_STATE_CLOSING;
 
-       if (ret < 0) {
-               printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n");
-               return ret;
+                       cm_id = loopback->cm_id;
+                       rem_ref_cm_node(cm_core, loopback);
+                       cm_id->rem_ref(cm_id);
+               }
        }
 
        return ret;
@@ -1783,37 +2211,45 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
                return -EINVAL;
 
        switch (cm_node->state) {
-               /* if passed in node is null, create a reference key node for node search */
-               /* check if we found an owner node for this pkt */
-               case NES_CM_STATE_SYN_RCVD:
-               case NES_CM_STATE_SYN_SENT:
-               case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
-               case NES_CM_STATE_ESTABLISHED:
-               case NES_CM_STATE_ACCEPTING:
-               case NES_CM_STATE_MPAREQ_SENT:
-                       cm_node->state = NES_CM_STATE_FIN_WAIT1;
-                       send_fin(cm_node, NULL);
-                       break;
-               case NES_CM_STATE_CLOSE_WAIT:
-                       cm_node->state = NES_CM_STATE_LAST_ACK;
-                       send_fin(cm_node, NULL);
-                       break;
-               case NES_CM_STATE_FIN_WAIT1:
-               case NES_CM_STATE_FIN_WAIT2:
-               case NES_CM_STATE_LAST_ACK:
-               case NES_CM_STATE_TIME_WAIT:
-               case NES_CM_STATE_CLOSING:
-                       ret = -1;
-                       break;
-               case NES_CM_STATE_LISTENING:
-               case NES_CM_STATE_UNKNOWN:
-               case NES_CM_STATE_INITED:
-               case NES_CM_STATE_CLOSED:
-               case NES_CM_STATE_TSA:
-                       ret = rem_ref_cm_node(cm_core, cm_node);
-                       break;
+       case NES_CM_STATE_SYN_RCVD:
+       case NES_CM_STATE_SYN_SENT:
+       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+       case NES_CM_STATE_ESTABLISHED:
+       case NES_CM_STATE_ACCEPTING:
+       case NES_CM_STATE_MPAREQ_SENT:
+       case NES_CM_STATE_MPAREQ_RCVD:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, NULL);
+               break;
+       case NES_CM_STATE_CLOSE_WAIT:
+               cm_node->state = NES_CM_STATE_LAST_ACK;
+               send_fin(cm_node, NULL);
+               break;
+       case NES_CM_STATE_FIN_WAIT1:
+       case NES_CM_STATE_FIN_WAIT2:
+       case NES_CM_STATE_LAST_ACK:
+       case NES_CM_STATE_TIME_WAIT:
+       case NES_CM_STATE_CLOSING:
+               ret = -1;
+               break;
+       case NES_CM_STATE_LISTENING:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, NULL);
+               break;
+       case NES_CM_STATE_MPAREJ_RCVD:
+       case NES_CM_STATE_UNKNOWN:
+       case NES_CM_STATE_INITED:
+       case NES_CM_STATE_CLOSED:
+       case NES_CM_STATE_LISTENER_DESTROYED:
+               ret = rem_ref_cm_node(cm_core, cm_node);
+               break;
+       case NES_CM_STATE_TSA:
+               if (cm_node->send_entry)
+                       printk(KERN_ERR "ERROR Close got called from STATE_TSA "
+                               "send_entry=%p\n", cm_node->send_entry);
+               ret = rem_ref_cm_node(cm_core, cm_node);
+               break;
        }
-       cm_node->cm_id = NULL;
        return ret;
 }
 
@@ -1822,92 +2258,93 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
  * recv_pkt - recv an ETHERNET packet, and process it through CM
  * node state machine
  */
-static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic,
-                           struct sk_buff *skb)
+static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
+       struct nes_vnic *nesvnic, struct sk_buff *skb)
 {
        struct nes_cm_node *cm_node = NULL;
        struct nes_cm_listener *listener = NULL;
        struct iphdr *iph;
        struct tcphdr *tcph;
        struct nes_cm_info nfo;
-       int ret = 0;
+       int skb_handled = 1;
+       __be32 tmp_daddr, tmp_saddr;
 
-       if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
-               ret = -EINVAL;
-               goto out;
+       if (!skb)
+               return 0;
+       if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
+               return 0;
        }
 
        iph = (struct iphdr *)skb->data;
        tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
-       skb_reset_network_header(skb);
-       skb_set_transport_header(skb, sizeof(*tcph));
-       skb->len = ntohs(iph->tot_len);
 
        nfo.loc_addr = ntohl(iph->daddr);
        nfo.loc_port = ntohs(tcph->dest);
        nfo.rem_addr = ntohl(iph->saddr);
        nfo.rem_port = ntohs(tcph->source);
 
-       nes_debug(NES_DBG_CM, "Received packet: dest=" NIPQUAD_FMT
-                 ":0x%04X src=" NIPQUAD_FMT ":0x%04X\n",
-                 NIPQUAD(iph->daddr), tcph->dest,
-                 NIPQUAD(iph->saddr), tcph->source);
+       tmp_daddr = cpu_to_be32(iph->daddr);
+       tmp_saddr = cpu_to_be32(iph->saddr);
+
+       nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n",
+                 &tmp_daddr, tcph->dest, &tmp_saddr, tcph->source);
 
-       /* note: this call is going to increment cm_node ref count */
-       cm_node = find_node(cm_core,
+       do {
+               cm_node = find_node(cm_core,
                        nfo.rem_port, nfo.rem_addr,
                        nfo.loc_port, nfo.loc_addr);
 
-       if (!cm_node) {
-               listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port,
+               if (!cm_node) {
+                       /* Only type of packet accepted are for */
+                       /* the PASSIVE open (syn only) */
+                       if ((!tcph->syn) || (tcph->ack)) {
+                               skb_handled = 0;
+                               break;
+                       }
+                       listener = find_listener(cm_core, nfo.loc_addr,
+                               nfo.loc_port,
                                NES_CM_LISTENER_ACTIVE_STATE);
-               if (listener) {
+                       if (!listener) {
+                               nfo.cm_id = NULL;
+                               nfo.conn_type = 0;
+                               nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n");
+                               skb_handled = 0;
+                               break;
+                       }
                        nfo.cm_id = listener->cm_id;
                        nfo.conn_type = listener->conn_type;
-               } else {
-                       nfo.cm_id = NULL;
-                       nfo.conn_type = 0;
-               }
-
-               cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener);
-               if (!cm_node) {
-                       nes_debug(NES_DBG_CM, "Unable to allocate node\n");
-                       if (listener) {
-                               nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n");
+                       cm_node = make_cm_node(cm_core, nesvnic, &nfo,
+                               listener);
+                       if (!cm_node) {
+                               nes_debug(NES_DBG_CM, "Unable to allocate "
+                                       "node\n");
+                               cm_packets_dropped++;
                                atomic_dec(&listener->ref_count);
+                               dev_kfree_skb_any(skb);
+                               break;
                        }
-                       ret = -1;
-                       goto out;
-               }
-               if (!listener) {
-                       nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n",
-                                       nfo.loc_port, atomic_read(&cm_node->ref_count));
-                       if (!tcph->rst) {
-                               nes_debug(NES_DBG_CM, "Packet found for unknown port=%d"
-                                               " rem_port=%d refcnt=%d\n",
-                                               nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count));
-
-                               cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq);
-                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
-                               send_reset(cm_node);
+                       if (!tcph->rst && !tcph->fin) {
+                               cm_node->state = NES_CM_STATE_LISTENING;
+                       } else {
+                               cm_packets_dropped++;
+                               rem_ref_cm_node(cm_core, cm_node);
+                               dev_kfree_skb_any(skb);
+                               break;
                        }
+                       add_ref_cm_node(cm_node);
+               } else if (cm_node->state == NES_CM_STATE_TSA) {
                        rem_ref_cm_node(cm_core, cm_node);
-                       ret = -1;
-                       goto out;
+                       atomic_inc(&cm_accel_dropped_pkts);
+                       dev_kfree_skb_any(skb);
+                       break;
                }
-               add_ref_cm_node(cm_node);
-               cm_node->state = NES_CM_STATE_LISTENING;
-       }
-
-       nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n",
-                       cm_node, skb->data);
-       process_packet(cm_node, skb, cm_core);
-
-       rem_ref_cm_node(cm_core, cm_node);
-       out:
-       if (skb)
-               dev_kfree_skb_any(skb);
-       return ret;
+               skb_reset_network_header(skb);
+               skb_set_transport_header(skb, sizeof(*tcph));
+               skb->len = ntohs(iph->tot_len);
+               process_packet(cm_node, skb, cm_core);
+               rem_ref_cm_node(cm_core, cm_node);
+       } while (0);
+       return skb_handled;
 }
 
 
@@ -1916,10 +2353,7 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni
  */
 static struct nes_cm_core *nes_cm_alloc_core(void)
 {
-       int i;
-
        struct nes_cm_core *cm_core;
-       struct sk_buff *skb = NULL;
 
        /* setup the CM core */
        /* alloc top level core control structure */
@@ -1937,19 +2371,6 @@ static struct nes_cm_core *nes_cm_alloc_core(void)
 
        atomic_set(&cm_core->events_posted, 0);
 
-       /* init the packet lists */
-       skb_queue_head_init(&cm_core->tx_free_list);
-
-       for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
-               skb = dev_alloc_skb(cm_core->mtu);
-               if (!skb) {
-                       kfree(cm_core);
-                       return NULL;
-               }
-               /* add 'raw' skb to free frame list */
-               skb_queue_head(&cm_core->tx_free_list, skb);
-       }
-
        cm_core->api = &nes_cm_api;
 
        spin_lock_init(&cm_core->ht_lock);
@@ -2012,15 +2433,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;
@@ -2101,22 +2522,16 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod
  */
 int nes_cm_disconn(struct nes_qp *nesqp)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&nesqp->lock, flags);
-       if (nesqp->disconn_pending == 0) {
-               nesqp->disconn_pending++;
-               spin_unlock_irqrestore(&nesqp->lock, flags);
-               /* nes_add_ref(&nesqp->ibqp); */
-               /* init our disconnect work element, to */
-               INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
+       struct disconn_work *work;
 
-               queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
-       } else {
-               spin_unlock_irqrestore(&nesqp->lock, flags);
-               nes_rem_ref(&nesqp->ibqp);
-       }
+       work = kzalloc(sizeof *work, GFP_ATOMIC);
+       if (!work)
+               return -ENOMEM; /* Timer will clean up */
 
+       nes_add_ref(&nesqp->ibqp);
+       work->nesqp = nesqp;
+       INIT_WORK(&work->work, nes_disconnect_worker);
+       queue_work(g_cm_core->disconn_wq, &work->work);
        return 0;
 }
 
@@ -2126,11 +2541,14 @@ int nes_cm_disconn(struct nes_qp *nesqp)
  */
 static void nes_disconnect_worker(struct work_struct *work)
 {
-       struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+       struct disconn_work *dwork = container_of(work, struct disconn_work, work);
+       struct nes_qp *nesqp = dwork->nesqp;
 
+       kfree(dwork);
        nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
                        nesqp->last_aeq, nesqp->hwqp.qp_id);
        nes_cm_disconn_true(nesqp);
+       nes_rem_ref(&nesqp->ibqp);
 }
 
 
@@ -2147,7 +2565,12 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
        u16 last_ae;
        u8 original_hw_tcp_state;
        u8 original_ibqp_state;
-       u8 issued_disconnect_reset = 0;
+       enum iw_cm_event_type disconn_status = IW_CM_EVENT_STATUS_OK;
+       int issue_disconn = 0;
+       int issue_close = 0;
+       int issue_flush = 0;
+       u32 flush_q = NES_CQP_FLUSH_RQ;
+       struct ib_event ibevent;
 
        if (!nesqp) {
                nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");
@@ -2161,7 +2584,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
                                nesqp->hwqp.qp_id);
                spin_unlock_irqrestore(&nesqp->lock, flags);
-               nes_rem_ref(&nesqp->ibqp);
                return -1;
        }
 
@@ -2172,58 +2594,75 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
        original_ibqp_state   = nesqp->ibqp_state;
        last_ae = nesqp->last_aeq;
 
+       if (nesqp->term_flags) {
+               issue_disconn = 1;
+               issue_close = 1;
+               nesqp->cm_id = NULL;
+               if (nesqp->flush_issued == 0) {
+                       nesqp->flush_issued = 1;
+                       issue_flush = 1;
+               }
+       } else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                       ((original_ibqp_state == IB_QPS_RTS) &&
+                       (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+               issue_disconn = 1;
+               if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET)
+                       disconn_status = IW_CM_EVENT_STATUS_RESET;
+       }
+
+       if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+                (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
+                (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
+                (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+               issue_close = 1;
+               nesqp->cm_id = NULL;
+               if (nesqp->flush_issued == 0) {
+                       nesqp->flush_issued = 1;
+                       issue_flush = 1;
+               }
+       }
+
+       spin_unlock_irqrestore(&nesqp->lock, flags);
+
+       if ((issue_flush) && (nesqp->destroyed == 0)) {
+               /* Flush the queue(s) */
+               if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE)
+                       flush_q |= NES_CQP_FLUSH_SQ;
+               flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1);
 
-       nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state);
+               if (nesqp->term_flags) {
+                       ibevent.device = nesqp->ibqp.device;
+                       ibevent.event = nesqp->terminate_eventtype;
+                       ibevent.element.qp = &nesqp->ibqp;
+                       nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+               }
+       }
 
-       if ((nesqp->cm_id) && (cm_id->event_handler)) {
-               if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
-                               ((original_ibqp_state == IB_QPS_RTS) &&
-                               (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+       if ((cm_id) && (cm_id->event_handler)) {
+               if (issue_disconn) {
                        atomic_inc(&cm_disconnects);
                        cm_event.event = IW_CM_EVENT_DISCONNECT;
-                       if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
-                               issued_disconnect_reset = 1;
-                               cm_event.status = IW_CM_EVENT_STATUS_RESET;
-                               nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for "
-                                               " QP%u, cm_id = %p. \n",
-                                               nesqp->hwqp.qp_id, cm_id);
-                       } else {
-                               cm_event.status = IW_CM_EVENT_STATUS_OK;
-                       }
-
+                       cm_event.status = disconn_status;
                        cm_event.local_addr = cm_id->local_addr;
                        cm_event.remote_addr = cm_id->remote_addr;
                        cm_event.private_data = NULL;
                        cm_event.private_data_len = 0;
 
-                       nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for "
-                                       " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n",
-                                       nesqp->hwqp.qp_id,
-                                       nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id,
-                                       atomic_read(&nesqp->refcount));
+                       nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event"
+                               " for  QP%u, SQ Head = %u, SQ Tail = %u. "
+                               "cm_id = %p, refcount = %u.\n",
+                               nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,
+                               nesqp->hwqp.sq_tail, cm_id,
+                               atomic_read(&nesqp->refcount));
 
-                       spin_unlock_irqrestore(&nesqp->lock, flags);
                        ret = cm_id->event_handler(cm_id, &cm_event);
                        if (ret)
-                               nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
-                       spin_lock_irqsave(&nesqp->lock, flags);
+                               nes_debug(NES_DBG_CM, "OFA CM event_handler "
+                                       "returned, ret=%d\n", ret);
                }
 
-               nesqp->disconn_pending = 0;
-               /* There might have been another AE while the lock was released */
-               original_hw_tcp_state = nesqp->hw_tcp_state;
-               original_ibqp_state   = nesqp->ibqp_state;
-               last_ae = nesqp->last_aeq;
-
-               if ((issued_disconnect_reset == 0) && (nesqp->cm_id) &&
-                               ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
-                                (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
-                                (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
-                                (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+               if (issue_close) {
                        atomic_inc(&cm_closes);
-                       nesqp->cm_id = NULL;
-                       nesqp->in_disconnect = 0;
-                       spin_unlock_irqrestore(&nesqp->lock, flags);
                        nes_disconnect(nesqp, 1);
 
                        cm_id->provider_data = nesqp;
@@ -2242,36 +2681,8 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        }
 
                        cm_id->rem_ref(cm_id);
-
-                       spin_lock_irqsave(&nesqp->lock, flags);
-                       if (nesqp->flush_issued == 0) {
-                               nesqp->flush_issued = 1;
-                               spin_unlock_irqrestore(&nesqp->lock, flags);
-                               flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1);
-                       } else {
-                               spin_unlock_irqrestore(&nesqp->lock, flags);
-                       }
-
-                       /* This reference is from either ModifyQP or the AE processing,
-                                       there is still a race here with modifyqp */
-                       nes_rem_ref(&nesqp->ibqp);
-
-               } else {
-                       cm_id = nesqp->cm_id;
-                       spin_unlock_irqrestore(&nesqp->lock, flags);
-                       /* check to see if the inbound reset beat the outbound reset */
-                       if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
-                               nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset"
-                                               " beating the outbound reset.\n",
-                                               nesqp->hwqp.qp_id);
-                               nes_rem_ref(&nesqp->ibqp);
-                       }
                }
-       } else {
-               nesqp->disconn_pending = 0;
-               spin_unlock_irqrestore(&nesqp->lock, flags);
        }
-       nes_rem_ref(&nesqp->ibqp);
 
        return 0;
 }
@@ -2285,12 +2696,14 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
        int ret = 0;
        struct nes_vnic *nesvnic;
        struct nes_device *nesdev;
+       struct nes_ib_device *nesibdev;
 
        nesvnic = to_nesvnic(nesqp->ibqp.device);
        if (!nesvnic)
                return -EINVAL;
 
        nesdev = nesvnic->nesdev;
+       nesibdev = nesvnic->nesibdev;
 
        nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
                        atomic_read(&nesvnic->netdev->refcnt));
@@ -2302,6 +2715,8 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
        } else {
                /* Need to free the Last Streaming Mode Message */
                if (nesqp->ietf_frame) {
+                       if (nesqp->lsmm_mr)
+                               nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);
                        pci_free_consistent(nesdev->pcidev,
                                        nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
                                        nesqp->ietf_frame, nesqp->ietf_frame_pbase);
@@ -2313,7 +2728,6 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
                nes_debug(NES_DBG_CM, "Call close API\n");
 
                g_cm_core->api->close(g_cm_core, nesqp->cm_node);
-               nesqp->cm_node = NULL;
        }
 
        return ret;
@@ -2338,6 +2752,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        struct nes_v4_quad nes_quad;
        u32 crc_value;
        int ret;
+       int passive_state;
+       struct nes_ib_device *nesibdev;
+       struct ib_mr *ibmr = NULL;
+       struct ib_phys_buf ibphysbuf;
+       struct nes_pd *nespd;
+       u64 tagged_offset;
 
        ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
        if (!ibqp)
@@ -2349,71 +2769,113 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        nesdev = nesvnic->nesdev;
        adapter = nesdev->nesadapter;
 
-       nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
-                       nesvnic, nesvnic->netdev, nesvnic->netdev->name);
-
-       /* since this is from a listen, we were able to put node handle into cm_id */
        cm_node = (struct nes_cm_node *)cm_id->provider_data;
+       nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p,"
+               "%s\n", cm_node, nesvnic, nesvnic->netdev,
+               nesvnic->netdev->name);
+
+       if (NES_CM_STATE_LISTENER_DESTROYED == cm_node->state) {
+               if (cm_node->loopbackpartner)
+                       rem_ref_cm_node(cm_node->cm_core, cm_node->loopbackpartner);
+               rem_ref_cm_node(cm_node->cm_core, cm_node);
+               return -EINVAL;
+       }
 
        /* associate the node with the QP */
        nesqp->cm_node = (void *)cm_node;
+       cm_node->nesqp = nesqp;
 
-       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n",
-                       nesqp->hwqp.qp_id, cm_node, jiffies);
+       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
+               nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
        atomic_inc(&cm_accepts);
 
        nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
                        atomic_read(&nesvnic->netdev->refcnt));
 
-               /* allocate the ietf frame and space for private data */
-               nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
-                               sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
-                               &nesqp->ietf_frame_pbase);
+       /* allocate the ietf frame and space for private data */
+       nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
+               sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
+               &nesqp->ietf_frame_pbase);
 
-               if (!nesqp->ietf_frame) {
-                       nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
-                       return -ENOMEM;
-               }
+       if (!nesqp->ietf_frame) {
+               nes_debug(NES_DBG_CM, "Unable to allocate memory for private "
+                       "data\n");
+               return -ENOMEM;
+       }
 
 
-               /* setup the MPA frame */
-               nesqp->private_data_len = conn_param->private_data_len;
-               memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
+       /* setup the MPA frame */
+       nesqp->private_data_len = conn_param->private_data_len;
+       memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
 
-               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
-                               conn_param->private_data_len);
+       memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+                       conn_param->private_data_len);
 
-               nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len);
-               nesqp->ietf_frame->rev = mpa_version;
-               nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+       nesqp->ietf_frame->priv_data_len =
+               cpu_to_be16(conn_param->private_data_len);
+       nesqp->ietf_frame->rev = mpa_version;
+       nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
 
-               /* setup our first outgoing iWarp send WQE (the IETF frame response) */
-               wqe = &nesqp->hwqp.sq_vbase[0];
+       /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+       wqe = &nesqp->hwqp.sq_vbase[0];
 
-               if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) {
-                       u64temp = (unsigned long)nesqp;
-                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
-                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
-                                           u64temp);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
-                                       cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
-                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
-                                       cpu_to_le32((u32)nesqp->ietf_frame_pbase);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
-                                       cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
-                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
-
-                       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
-                                       NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | 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));
+       if (cm_id->remote_addr.sin_addr.s_addr !=
+                       cm_id->local_addr.sin_addr.s_addr) {
+               u64temp = (unsigned long)nesqp;
+               nesibdev = nesvnic->nesibdev;
+               nespd = nesqp->nespd;
+               ibphysbuf.addr = nesqp->ietf_frame_pbase;
+               ibphysbuf.size = conn_param->private_data_len +
+                                       sizeof(struct ietf_mpa_frame);
+               tagged_offset = (u64)(unsigned long)nesqp->ietf_frame;
+               ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd,
+                                               &ibphysbuf, 1,
+                                               IB_ACCESS_LOCAL_WRITE,
+                                               &tagged_offset);
+               if (!ibmr) {
+                       nes_debug(NES_DBG_CM, "Unable to register memory region"
+                                       "for lSMM for cm_node = %p \n",
+                                       cm_node);
+                       pci_free_consistent(nesdev->pcidev,
+                               nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+                               nesqp->ietf_frame, nesqp->ietf_frame_pbase);
+                       return -ENOMEM;
                }
-               nesqp->skip_lsmm = 1;
+
+               ibmr->pd = &nespd->ibpd;
+               ibmr->device = nespd->ibpd.device;
+               nesqp->lsmm_mr = ibmr;
+
+               u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+               set_wqe_64bit_value(wqe->wqe_words,
+                       NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+                       u64temp);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+                       cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING |
+                       NES_IWARP_SQ_WQE_WRPDU);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+                       cpu_to_le32(conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
+               set_wqe_64bit_value(wqe->wqe_words,
+                                       NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
+                                       (u64)(unsigned long)nesqp->ietf_frame);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
+                       cpu_to_le32(conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
+               wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;
+               if (nesqp->sq_kmapped) {
+                       nesqp->sq_kmapped = 0;
+                       kunmap(nesqp->page);
+               }
+
+               nesqp->nesqp_context->ird_ord_sizes |=
+                       cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                       NES_QPCONTEXT_ORDIRD_WRPDU);
+       } else {
+               nesqp->nesqp_context->ird_ord_sizes |=
+                       cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);
+       }
+       nesqp->skip_lsmm = 1;
 
 
        /* Cache the cm_id in the qp */
@@ -2424,61 +2886,80 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        cm_id->provider_data = nesqp;
        nesqp->active_conn   = 0;
 
+       if (cm_node->state == NES_CM_STATE_TSA)
+               nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n",
+                       cm_node);
+
        nes_cm_init_tsa_conn(nesqp, cm_node);
 
-       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
-       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
-       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+       nesqp->nesqp_context->tcpPorts[0] =
+               cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] =
+               cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(nesvnic->local_ipaddr));
+       else
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
 
        nesqp->nesqp_context->misc2 |= cpu_to_le32(
-                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+                       NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
 
-       nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
-                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
+       nesqp->nesqp_context->arp_index_vlan |=
+               cpu_to_le32(nes_arp_table(nesdev,
+                       le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
                        NES_ARP_RESOLVE) << 16);
 
        nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
-                       jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+               jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
 
        nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
 
        nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
-                       ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
-       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+               ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
+       nesqp->nesqp_context->ird_ord_sizes |=
+               cpu_to_le32((u32)conn_param->ord);
 
        memset(&nes_quad, 0, sizeof(nes_quad));
-       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-       nes_quad.SrcIpadr      = cm_id->remote_addr.sin_addr.s_addr;
-       nes_quad.TcpPorts[0]   = cm_id->remote_addr.sin_port;
-       nes_quad.TcpPorts[1]   = cm_id->local_addr.sin_port;
+       nes_quad.DstIpAdrIndex =
+               cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nes_quad.SrcIpadr = nesvnic->local_ipaddr;
+       else
+               nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
+       nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
 
        /* Produce hash key */
        crc_value = get_crc_value(&nes_quad);
        nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
        nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
-                       nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
+               nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
 
        nesqp->hte_index &= adapter->hte_index_mask;
        nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
 
        cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
 
-       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X,"
-                       " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n",
-                       nesqp->hwqp.qp_id,
+       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = "
+                       "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + "
+                       "private data length=%zu.\n", nesqp->hwqp.qp_id,
                        ntohl(cm_id->remote_addr.sin_addr.s_addr),
                        ntohs(cm_id->remote_addr.sin_port),
                        ntohl(cm_id->local_addr.sin_addr.s_addr),
                        ntohs(cm_id->local_addr.sin_port),
                        le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
                        le32_to_cpu(nesqp->nesqp_context->snd_nxt),
-                       conn_param->private_data_len+sizeof(struct ietf_mpa_frame));
+                       conn_param->private_data_len +
+                       sizeof(struct ietf_mpa_frame));
 
-       attr.qp_state = IB_QPS_RTS;
-       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
 
-       /* notify OF layer that accept event was successfull */
+       /* notify OF layer that accept event was successful */
        cm_id->add_ref(cm_id);
+       nes_add_ref(&nesqp->ibqp);
 
        cm_event.event = IW_CM_EVENT_ESTABLISHED;
        cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
@@ -2488,17 +2969,23 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        cm_event.private_data = NULL;
        cm_event.private_data_len = 0;
        ret = cm_id->event_handler(cm_id, &cm_event);
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
        if (cm_node->loopbackpartner) {
-               cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len;
+               cm_node->loopbackpartner->mpa_frame_size =
+                       nesqp->private_data_len;
                /* copy entire MPA frame to our cm_node's frame */
-               memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data,
-                          nesqp->private_data_len);
+               memcpy(cm_node->loopbackpartner->mpa_frame_buf,
+                       nesqp->ietf_frame->priv_data, nesqp->private_data_len);
                create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
        }
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
 
+       passive_state = atomic_add_return(1, &cm_node->passive_state);
+       if (passive_state == NES_SEND_RESET_EVENT)
+               create_event(cm_node, NES_CM_EVENT_RESET);
        return 0;
 }
 
@@ -2509,23 +2996,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;
 
-       strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
-       memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+       if (cm_node->mpa_frame_size > MAX_CM_BUFFER)
+               return -EINVAL;
+
+       memcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
+       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);
 }
 
 
@@ -2541,6 +3040,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        struct nes_device *nesdev;
        struct nes_cm_node *cm_node;
        struct nes_cm_info cm_info;
+       int apbvt_set = 0;
 
        ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
        if (!ibqp)
@@ -2555,74 +3055,66 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (!nesdev)
                return -EINVAL;
 
-       atomic_inc(&cm_connects);
+       if (!(cm_id->local_addr.sin_port) || !(cm_id->remote_addr.sin_port))
+               return -EINVAL;
 
-       nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) +
-                       conn_param->private_data_len, GFP_KERNEL);
-       if (!nesqp->ietf_frame)
-               return -ENOMEM;
+       nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "
+               "0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,
+               ntohl(nesvnic->local_ipaddr),
+               ntohl(cm_id->remote_addr.sin_addr.s_addr),
+               ntohs(cm_id->remote_addr.sin_port),
+               ntohl(cm_id->local_addr.sin_addr.s_addr),
+               ntohs(cm_id->local_addr.sin_port));
 
-       /* set qp as having an active connection */
+       atomic_inc(&cm_connects);
        nesqp->active_conn = 1;
 
-       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
-                       nesqp->hwqp.qp_id,
-                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
-                       ntohs(cm_id->remote_addr.sin_port),
-                       ntohl(cm_id->local_addr.sin_addr.s_addr),
-                       ntohs(cm_id->local_addr.sin_port));
-
        /* cache the cm_id in the qp */
        nesqp->cm_id = cm_id;
 
        cm_id->provider_data = nesqp;
 
-       /* copy the private data */
-       if (conn_param->private_data_len) {
-               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
-                               conn_param->private_data_len);
-       }
-
        nesqp->private_data_len = conn_param->private_data_len;
        nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
        nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
-       nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len);
+       nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
+               conn_param->private_data_len);
 
-       strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
-       nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
-       nesqp->ietf_frame->rev = IETF_MPA_VERSION;
-       nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
-
-       if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+       if (cm_id->local_addr.sin_addr.s_addr !=
+               cm_id->remote_addr.sin_addr.s_addr) {
                nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                               PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+                       PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+               apbvt_set = 1;
+       }
 
        /* set up the connection params for the node */
-       cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr);
-       cm_info.loc_port = (cm_id->local_addr.sin_port);
-       cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr);
-       cm_info.rem_port = (cm_id->remote_addr.sin_port);
+       cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr);
+       cm_info.loc_port = htons(cm_id->local_addr.sin_port);
+       cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr);
+       cm_info.rem_port = htons(cm_id->remote_addr.sin_port);
        cm_info.cm_id = cm_id;
        cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
 
        cm_id->add_ref(cm_id);
-       nes_add_ref(&nesqp->ibqp);
 
        /* create a connect CM node connection */
-       cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info);
+       cm_node = g_cm_core->api->connect(g_cm_core, nesvnic,
+               conn_param->private_data_len, (void *)conn_param->private_data,
+               &cm_info);
        if (!cm_node) {
-               if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+               if (apbvt_set)
                        nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                                       PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
-               nes_rem_ref(&nesqp->ibqp);
-               kfree(nesqp->ietf_frame);
-               nesqp->ietf_frame = NULL;
+                               PCI_FUNC(nesdev->pcidev->devfn),
+                               NES_MANAGE_APBVT_DEL);
+
                cm_id->rem_ref(cm_id);
                return -ENOMEM;
        }
 
-       cm_node->apbvt_set = 1;
+       cm_node->apbvt_set = apbvt_set;
        nesqp->cm_node = cm_node;
+       cm_node->nesqp = nesqp;
+       nes_add_ref(&nesqp->ibqp);
 
        return 0;
 }
@@ -2664,7 +3156,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
 
        cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
        if (!cm_node) {
-               printk("%s[%u] Error returned from listen API call\n",
+               printk(KERN_ERR "%s[%u] Error returned from listen API call\n",
                                __func__, __LINE__);
                return -ENOMEM;
        }
@@ -2672,14 +3164,17 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
        cm_id->provider_data = cm_node;
 
        if (!cm_node->reused_node) {
-               err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
-                               PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+               err = nes_manage_apbvt(nesvnic,
+                       ntohs(cm_id->local_addr.sin_port),
+                       PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
+                       NES_MANAGE_APBVT_ADD);
                if (err) {
-                       printk("nes_manage_apbvt call returned %d.\n", err);
+                       printk(KERN_ERR "nes_manage_apbvt call returned %d.\n",
+                               err);
                        g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
                        return err;
                }
-               cm_listens_created++;
+               atomic_inc(&cm_listens_created);
        }
 
        cm_id->add_ref(cm_id);
@@ -2711,15 +3206,16 @@ int nes_destroy_listen(struct iw_cm_id *cm_id)
  */
 int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
 {
+       int rc = 0;
        cm_packets_received++;
        if ((g_cm_core) && (g_cm_core->api)) {
-               g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
+               rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
        } else {
                nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
                                " cm is not setup properly.\n");
        }
 
-       return 0;
+       return rc;
 }
 
 
@@ -2795,53 +3291,75 @@ static void cm_event_connected(struct nes_cm_event *event)
        nes_cm_init_tsa_conn(nesqp, cm_node);
 
        /* set the QP tsa context */
-       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
-       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
-       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+       nesqp->nesqp_context->tcpPorts[0] =
+               cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] =
+               cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(nesvnic->local_ipaddr));
+       else
+               nesqp->nesqp_context->ip0 =
+                       cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
 
        nesqp->nesqp_context->misc2 |= cpu_to_le32(
-                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+                       NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
        nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
-                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0),
+                       nes_arp_table(nesdev,
+                       le32_to_cpu(nesqp->nesqp_context->ip0),
                        NULL, NES_ARP_RESOLVE) << 16);
        nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
                        jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
        nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
        nesqp->nesqp_context->ird_ord_sizes |=
-                       cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+                       cpu_to_le32((u32)1 <<
+                       NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
 
        /* Adjust tail for not having a LSMM */
        nesqp->hwqp.sq_tail = 1;
 
 #if defined(NES_SEND_FIRST_WRITE)
-               if (cm_node->send_write0) {
-                       nes_debug(NES_DBG_CM, "Sending first write.\n");
-                       wqe = &nesqp->hwqp.sq_vbase[0];
-                       u64temp = (unsigned long)nesqp;
-                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
-                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
-                                           u64temp);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
-                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
-
-                       /* use the reserved spot on the WQ for the extra first WQE */
-                       nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
-                                       NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
-                       nesqp->skip_lsmm = 1;
-                       nesqp->hwqp.sq_tail = 0;
-                       nes_write32(nesdev->regs + NES_WQE_ALLOC,
-                                       (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+       if (cm_node->send_write0) {
+               nes_debug(NES_DBG_CM, "Sending first write.\n");
+               wqe = &nesqp->hwqp.sq_vbase[0];
+               u64temp = (unsigned long)nesqp;
+               u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+               set_wqe_64bit_value(wqe->wqe_words,
+                               NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+                       cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
+               wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
+               wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+               if (nesqp->sq_kmapped) {
+                       nesqp->sq_kmapped = 0;
+                       kunmap(nesqp->page);
                }
+
+               /* use the reserved spot on the WQ for the extra first WQE */
+               nesqp->nesqp_context->ird_ord_sizes &=
+                       cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                                               NES_QPCONTEXT_ORDIRD_WRPDU |
+                                               NES_QPCONTEXT_ORDIRD_ALSMM));
+               nesqp->skip_lsmm = 1;
+               nesqp->hwqp.sq_tail = 0;
+               nes_write32(nesdev->regs + NES_WQE_ALLOC,
+                               (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+       }
 #endif
 
        memset(&nes_quad, 0, sizeof(nes_quad));
 
-       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-       nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.DstIpAdrIndex =
+               cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
+               nes_quad.SrcIpadr = nesvnic->local_ipaddr;
+       else
+               nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
        nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
        nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
 
@@ -2858,10 +3376,6 @@ static void cm_event_connected(struct nes_cm_event *event)
        nesqp->private_data_len = (u8) cm_node->mpa_frame_size;
        cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
 
-       /* modify QP state to rts */
-       attr.qp_state = IB_QPS_RTS;
-       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
-
        /* notify OF layer we successfully created the requested connection */
        cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
        cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
@@ -2870,20 +3384,21 @@ static void cm_event_connected(struct nes_cm_event *event)
        cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
        cm_event.remote_addr = cm_id->remote_addr;
 
-               cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
-               cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
+       cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
+       cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
 
        cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;
        ret = cm_id->event_handler(cm_id, &cm_event);
        nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
 
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
-       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n",
-                       nesqp->hwqp.qp_id, jiffies );
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
 
-       nes_rem_ref(&nesqp->ibqp);
+       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = "
+               "%lu\n", nesqp->hwqp.qp_id, jiffies);
 
        return;
 }
@@ -2920,24 +3435,25 @@ static void cm_event_connect_error(struct nes_cm_event *event)
        nesqp->cm_id = NULL;
        cm_id->provider_data = NULL;
        cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
-       cm_event.status = IW_CM_EVENT_STATUS_REJECTED;
+       cm_event.status = -ECONNRESET;
        cm_event.provider_data = cm_id->provider_data;
        cm_event.local_addr = cm_id->local_addr;
        cm_event.remote_addr = cm_id->remote_addr;
        cm_event.private_data = NULL;
        cm_event.private_data_len = 0;
 
-       nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n",
-                       cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr);
+       nes_debug(NES_DBG_CM, "call CM_EVENT 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);
        nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
        if (ret)
-               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
-                               __func__, __LINE__, ret);
-       nes_rem_ref(&nesqp->ibqp);
-               cm_id->rem_ref(cm_id);
+               printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
+                       "ret=%d\n", __func__, __LINE__, ret);
+       cm_id->rem_ref(cm_id);
 
+       rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
        return;
 }
 
@@ -2963,6 +3479,8 @@ static void cm_event_reset(struct nes_cm_event *event)
 
        nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);
        nesqp = cm_id->provider_data;
+       if (!nesqp)
+               return;
 
        nesqp->cm_id = NULL;
        /* cm_id->provider_data = NULL; */
@@ -2974,7 +3492,19 @@ static void cm_event_reset(struct nes_cm_event *event)
        cm_event.private_data = NULL;
        cm_event.private_data_len = 0;
 
+       cm_id->add_ref(cm_id);
        ret = cm_id->event_handler(cm_id, &cm_event);
+       atomic_inc(&cm_closes);
+       cm_event.event = IW_CM_EVENT_CLOSE;
+       cm_event.status = IW_CM_EVENT_STATUS_OK;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr = cm_id->local_addr;
+       cm_event.remote_addr = cm_id->remote_addr;
+       cm_event.private_data = NULL;
+       cm_event.private_data_len = 0;
+       nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node);
+       ret = cm_id->event_handler(cm_id, &cm_event);
+
        nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
 
 
@@ -3015,13 +3545,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;
 
-               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;
+
+       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;
@@ -3040,7 +3613,8 @@ static int nes_cm_post_event(struct nes_cm_event *event)
        add_ref_cm_node(event->cm_node);
        event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
        INIT_WORK(&event->event_work, nes_cm_event_handler);
-       nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event);
+       nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n",
+               event->cm_node, event);
 
        queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
 
@@ -3056,46 +3630,56 @@ static int nes_cm_post_event(struct nes_cm_event *event)
  */
 static void nes_cm_event_handler(struct work_struct *work)
 {
-       struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work);
+       struct nes_cm_event *event = container_of(work, struct nes_cm_event,
+                       event_work);
        struct nes_cm_core *cm_core;
 
-       if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) {
+       if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core))
                return;
-       }
+
        cm_core = event->cm_node->cm_core;
        nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
-                       event, event->type, atomic_read(&cm_core->events_posted));
+               event, event->type, atomic_read(&cm_core->events_posted));
 
        switch (event->type) {
-               case NES_CM_EVENT_MPA_REQ:
-                       cm_event_mpa_req(event);
-                       nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n");
-                       break;
-               case NES_CM_EVENT_RESET:
-                       nes_debug(NES_DBG_CM, "CM Event: RESET\n");
-                       cm_event_reset(event);
-                       break;
-               case NES_CM_EVENT_CONNECTED:
-                       if ((!event->cm_node->cm_id) ||
-                               (event->cm_node->state != NES_CM_STATE_TSA)) {
-                               break;
-                       }
-                       cm_event_connected(event);
-                       nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
+       case NES_CM_EVENT_MPA_REQ:
+               cm_event_mpa_req(event);
+               nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n",
+                       event->cm_node);
+               break;
+       case NES_CM_EVENT_RESET:
+               nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n",
+                       event->cm_node);
+               cm_event_reset(event);
+               break;
+       case NES_CM_EVENT_CONNECTED:
+               if ((!event->cm_node->cm_id) ||
+                       (event->cm_node->state != NES_CM_STATE_TSA))
                        break;
-               case NES_CM_EVENT_ABORTED:
-                       if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) {
-                               break;
-                       }
-                       cm_event_connect_error(event);
-                       nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
-                       break;
-               case NES_CM_EVENT_DROPPED_PKT:
-                       nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
+               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;
-               default:
-                       nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+               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))
                        break;
+               cm_event_connect_error(event);
+               nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
+               break;
+       case NES_CM_EVENT_DROPPED_PKT:
+               nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
+               break;
+       default:
+               nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+               break;
        }
 
        atomic_dec(&cm_core->events_posted);