Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
[safe/jmp/linux-2.6] / drivers / infiniband / hw / nes / nes_cm.c
index 2854a6f..a812db2 100644 (file)
@@ -86,15 +86,14 @@ static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,
        struct nes_cm_node *);
 static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
        struct nes_cm_node *);
-static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
+static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
        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 struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+static void 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 int add_ref_cm_node(struct nes_cm_node *);
 static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
 
@@ -251,7 +250,7 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
  * 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,
+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)
 {
@@ -339,7 +338,6 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb,
        skb_shinfo(skb)->nr_frags = 0;
        cm_packets_created++;
 
-       return skb;
 }
 
 
@@ -356,7 +354,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));
 
@@ -381,8 +378,6 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        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;
@@ -459,13 +454,23 @@ static void nes_cm_timer_tick(unsigned long pass)
        int ret = NETDEV_TX_OK;
        enum nes_cm_node_state last_state;
 
+       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) {
+                               &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);
+               if (!list_empty(&cm_node->recv_list) || (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);
                spin_lock_irqsave(&cm_node->recv_list_lock, flags);
                list_for_each_safe(list_core, list_node_temp,
                        &cm_node->recv_list) {
@@ -519,7 +524,7 @@ static void nes_cm_timer_tick(unsigned long pass)
                do {
                        send_entry = cm_node->send_entry;
                        if (!send_entry)
-                               continue;
+                               break;
                        if (time_after(send_entry->timetosend, jiffies)) {
                                if (cm_node->state != NES_CM_STATE_TSA) {
                                        if ((nexttimeout >
@@ -528,18 +533,18 @@ static void nes_cm_timer_tick(unsigned long pass)
                                                nexttimeout =
                                                        send_entry->timetosend;
                                                settimer = 1;
-                                               continue;
+                                               break;
                                        }
                                } else {
                                        free_retrans_entry(cm_node);
-                                       continue;
+                                       break;
                                }
                        }
 
                        if ((cm_node->state == NES_CM_STATE_TSA) ||
                                (cm_node->state == NES_CM_STATE_CLOSED)) {
                                free_retrans_entry(cm_node);
-                               continue;
+                               break;
                        }
 
                        if (!send_entry->retranscount ||
@@ -557,7 +562,7 @@ static void nes_cm_timer_tick(unsigned long pass)
                                                NES_CM_EVENT_ABORTED);
                                spin_lock_irqsave(&cm_node->retrans_list_lock,
                                        flags);
-                               continue;
+                               break;
                        }
                        atomic_inc(&send_entry->skb->users);
                        cm_packets_retrans++;
@@ -583,7 +588,7 @@ static void nes_cm_timer_tick(unsigned long pass)
                                send_entry->retrycount--;
                                nexttimeout = jiffies + NES_SHORT_TIME;
                                settimer = 1;
-                               continue;
+                               break;
                        } else {
                                cm_packets_sent++;
                        }
@@ -615,14 +620,12 @@ static void nes_cm_timer_tick(unsigned long pass)
 
                spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
                rem_ref_cm_node(cm_node->cm_core, cm_node);
-               spin_lock_irqsave(&cm_core->ht_lock, flags);
                if (ret != NETDEV_TX_OK) {
                        nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
                                cm_node);
                        break;
                }
        }
-       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 
        if (settimer) {
                if (!timer_pending(&cm_core->tcp_timer)) {
@@ -683,7 +686,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
        optionssize += 1;
 
        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");
                return -1;
@@ -708,7 +711,7 @@ static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
        int flags = SET_RST | SET_ACK;
 
        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");
                return -1;
@@ -729,7 +732,7 @@ static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
        int ret;
 
        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");
@@ -752,7 +755,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");
@@ -767,59 +770,15 @@ 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;
 
@@ -887,7 +846,6 @@ 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)
@@ -896,11 +854,6 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
        nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
                cm_node);
 
-       /* 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;
-
        spin_lock_irqsave(&cm_core->ht_lock, flags);
 
        /* get a handle on the hash table element (list head for this slot) */
@@ -925,28 +878,36 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
        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) {
+                                  &g_cm_core->connected_nodes) {
                        cm_node = container_of(list_pos, struct nes_cm_node,
                                list);
                        if ((cm_node->listener == listener) &&
-                               (!cm_node->accelerated)) {
-                               cleanup_retrans_entry(cm_node);
-                               spin_unlock_irqrestore(&cm_core->ht_lock,
-                                       flags);
-                               send_reset(cm_node, NULL);
-                               spin_lock_irqsave(&cm_core->ht_lock, flags);
+                           (!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);
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, NULL);
+               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);
@@ -1123,7 +1084,10 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
 
        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
+               arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
        if (arpindex < 0) {
                arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
                if (arpindex < 0) {
@@ -1303,7 +1267,6 @@ static void drop_packet(struct sk_buff *skb)
 static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        struct tcphdr *tcph)
 {
-       atomic_inc(&cm_resets_recvd);
        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));
@@ -1341,6 +1304,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
 {
 
        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,
@@ -1354,7 +1318,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                        cm_node->listener, cm_node->state);
                active_open_err(cm_node, skb, reset);
                break;
-       /* For PASSIVE open states, remove the cm_node event */
+       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);
+               cleanup_retrans_entry(cm_node);
+               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:
@@ -1362,7 +1333,14 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                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:
+               cleanup_retrans_entry(cm_node);
+               drop_packet(skb);
+               break;
        default:
+               drop_packet(skb);
                break;
        }
 }
@@ -1391,6 +1369,9 @@ static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
                dev_kfree_skb_any(skb);
                if (type == NES_CM_EVENT_CONNECTED)
                        cm_node->state = NES_CM_STATE_TSA;
+               else
+                       atomic_set(&cm_node->passive_state,
+                                       NES_PASSIVE_STATE_INDICATED);
                create_event(cm_node, type);
 
        }
@@ -1471,7 +1452,7 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        int optionsize;
 
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-       skb_pull(skb, tcph->doff << 2);
+       skb_trim(skb, 0);
        inc_sequence = ntohl(tcph->seq);
 
        switch (cm_node->state) {
@@ -1504,6 +1485,10 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                cm_node->state = NES_CM_STATE_SYN_RCVD;
                send_syn(cm_node, 1, skb);
                break;
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_TSA:
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_FIN_WAIT1:
@@ -1512,7 +1497,6 @@ static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_LAST_ACK:
        case NES_CM_STATE_CLOSING:
        case NES_CM_STATE_UNKNOWN:
-       case NES_CM_STATE_CLOSED:
        default:
                drop_packet(skb);
                break;
@@ -1528,7 +1512,7 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        int optionsize;
 
        optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
-       skb_pull(skb, tcph->doff << 2);
+       skb_trim(skb, 0);
        inc_sequence = ntohl(tcph->seq);
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_SENT:
@@ -1552,6 +1536,12 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                /* passive open, so should not be here */
                passive_open_err(cm_node, skb, 1);
                break;
+       case NES_CM_STATE_LISTENING:
+       case NES_CM_STATE_CLOSED:
+               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_ESTABLISHED:
        case NES_CM_STATE_FIN_WAIT1:
        case NES_CM_STATE_FIN_WAIT2:
@@ -1559,7 +1549,6 @@ static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        case NES_CM_STATE_TSA:
        case NES_CM_STATE_CLOSING:
        case NES_CM_STATE_UNKNOWN:
-       case NES_CM_STATE_CLOSED:
        case NES_CM_STATE_MPAREQ_SENT:
        default:
                drop_packet(skb);
@@ -1574,6 +1563,13 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        u32 inc_sequence;
        u32 rem_seq_ack;
        u32 rem_seq;
+       int ret;
+       int optionsize;
+       u32 temp_seq = cm_node->tcp_cntxt.loc_seq_num;
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+       cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+
        if (check_seq(cm_node, tcph, skb))
                return;
 
@@ -1586,7 +1582,18 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
        switch (cm_node->state) {
        case NES_CM_STATE_SYN_RCVD:
                /* Passive OPEN */
+               ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);
+               if (ret)
+                       break;
                cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               cm_node->tcp_cntxt.loc_seq_num = temp_seq;
+               if (cm_node->tcp_cntxt.rem_ack_num !=
+                   cm_node->tcp_cntxt.loc_seq_num) {
+                       nes_debug(NES_DBG_CM, "rem_ack_num != loc_seq_num\n");
+                       cleanup_retrans_entry(cm_node);
+                       send_reset(cm_node, skb);
+                       return;
+               }
                cm_node->state = NES_CM_STATE_ESTABLISHED;
                if (datasize) {
                        cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
@@ -1618,11 +1625,15 @@ static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
                        dev_kfree_skb_any(skb);
                }
                break;
+       case NES_CM_STATE_LISTENING:
+       case NES_CM_STATE_CLOSED:
+               cleanup_retrans_entry(cm_node);
+               send_reset(cm_node, skb);
+               break;
        case NES_CM_STATE_FIN_WAIT1:
        case NES_CM_STATE_SYN_SENT:
        case NES_CM_STATE_FIN_WAIT2:
        case NES_CM_STATE_TSA:
-       case NES_CM_STATE_CLOSED:
        case NES_CM_STATE_MPAREQ_RCVD:
        case NES_CM_STATE_LAST_ACK:
        case NES_CM_STATE_CLOSING:
@@ -1645,9 +1656,9 @@ static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
                        nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
                                __func__, cm_node);
                        if (passive)
-                               passive_open_err(cm_node, skb, 0);
+                               passive_open_err(cm_node, skb, 1);
                        else
-                               active_open_err(cm_node, skb, 0);
+                               active_open_err(cm_node, skb, 1);
                        return 1;
                }
        }
@@ -1967,6 +1978,7 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
        struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
 {
        int ret = 0;
+       int passive_state;
 
        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);
@@ -1974,9 +1986,13 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
        if (cm_node->tcp_cntxt.client)
                return ret;
        cleanup_retrans_entry(cm_node);
-       cm_node->state = NES_CM_STATE_CLOSED;
 
-       ret = send_reset(cm_node, NULL);
+       passive_state = atomic_add_return(1, &cm_node->passive_state);
+       cm_node->state = NES_CM_STATE_CLOSED;
+       if (passive_state == NES_SEND_RESET_EVENT)
+               rem_ref_cm_node(cm_core, cm_node);
+       else
+               ret = send_reset(cm_node, NULL);
        return ret;
 }
 
@@ -2034,7 +2050,7 @@ 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 void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
+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;
@@ -2042,23 +2058,16 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
        struct iphdr *iph;
        struct tcphdr *tcph;
        struct nes_cm_info nfo;
+       int skb_handled = 1;
 
        if (!skb)
-               return;
+               return 0;
        if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
-               dev_kfree_skb_any(skb);
-               return;
+               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));
-       if (!tcph) {
-               dev_kfree_skb_any(skb);
-               return;
-       }
-       skb->len = ntohs(iph->tot_len);
 
        nfo.loc_addr = ntohl(iph->daddr);
        nfo.loc_port = ntohs(tcph->dest);
@@ -2077,23 +2086,21 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
                        /* Only type of packet accepted are for */
                        /* the PASSIVE open (syn only) */
                        if ((!tcph->syn) || (tcph->ack)) {
-                               cm_packets_dropped++;
+                               skb_handled = 0;
                                break;
                        }
                        listener = find_listener(cm_core, nfo.loc_addr,
                                nfo.loc_port,
                                NES_CM_LISTENER_ACTIVE_STATE);
-                       if (listener) {
-                               nfo.cm_id = listener->cm_id;
-                               nfo.conn_type = listener->conn_type;
-                       } else {
-                               nes_debug(NES_DBG_CM, "Unable to find listener "
-                                       "for the pkt\n");
-                               cm_packets_dropped++;
-                               dev_kfree_skb_any(skb);
+                       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;
                        cm_node = make_cm_node(cm_core, nesvnic, &nfo,
                                listener);
                        if (!cm_node) {
@@ -2119,9 +2126,13 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
                        dev_kfree_skb_any(skb);
                        break;
                }
+               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;
 }
 
 
@@ -2130,10 +2141,7 @@ static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
  */
 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 */
@@ -2151,19 +2159,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);
@@ -2392,7 +2387,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
                        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 "
@@ -2542,6 +2536,7 @@ 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;
 
        ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
        if (!ibqp)
@@ -2709,8 +2704,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                        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 */
        cm_id->add_ref(cm_id);
@@ -2723,6 +2716,8 @@ 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;
@@ -2735,6 +2730,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                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;
 }
 
@@ -2938,15 +2936,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;
 }
 
 
@@ -3217,6 +3216,18 @@ static void cm_event_reset(struct nes_cm_event *event)
        cm_event.private_data_len = 0;
 
        ret = cm_id->event_handler(cm_id, &cm_event);
+       cm_id->add_ref(cm_id);
+       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);