Kernel driver patch 3 of 9.

Signed-off-by: Glenn Grundstrom <[EMAIL PROTECTED]>

======================================================

diff -ruNp old/drivers/infiniband/hw/nes/nes_cm.c
new/drivers/infiniband/hw/nes/nes_cm.c
--- old/drivers/infiniband/hw/nes/nes_cm.c      1969-12-31
18:00:00.000000000 -0600
+++ new/drivers/infiniband/hw/nes/nes_cm.c      2006-10-25
10:36:29.000000000 -0500
@@ -0,0 +1,1204 @@
+/*
+ * Copyright (c) 2006 NetEffect, Inc. 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
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define TCPOPT_TIMESTAMP 8
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/notifier.h>
+#include <linux/net.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/iw_cm.h>
+
+#include "nes.h"
+
+#define OS_LINUX
+#define OS_LINUX_26
+#include <nes.h>
+#include <nes_sockets.h>
+
+extern unsigned int send_first;
+
+struct nes_v4_quad
+{
+   UINT32   rsvd0;
+   UINT32   DstIpAdrIndex;  /* Only most significant 5 bits are valid
*/
+   UINT32   SrcIpadr;
+   UINT32   TcpPorts; /* src is low, dest is high */
+};
+
+enum ietf_mpa_flags {
+       IETF_MPA_FLAGS_MARKERS = 0x80,   /* receive Markers */
+    IETF_MPA_FLAGS_CRC = 0x40,  /* receive Markers */
+    IETF_MPA_FLAGS_REJECT = 0x20,       /* Reject */
+};
+
+#define IEFT_MPA_KEY_REQ "MPA ID Req Frame"
+#define IEFT_MPA_KEY_REP "MPA ID Rep Frame"
+
+struct ietf_mpa_req_resp_frame {
+       u8 key[16];
+       u8 flags;
+       u8 rev;
+       u16 private_data_size;
+       u8 private_data[0];
+};
+
+static void connect_worker(void *);
+static void listen_worker(void *);
+
+extern int NesAdapterAdd(struct net_device *netdev);
+extern int NesInitSockets(void);
+extern void set_interface(
+                                  UINT32    ip_addr,
+                                  UINT32    mask,
+                                  UINT32    bcastaddr,
+                                  UINT32    type
+                                 );
+#define ADD_ADDR     1
+#define SET_ADDR     2
+#define DELETE_ADDR  3
+
+extern void bdc_cleanup(void);
+extern int mpa_version;
+
+unsigned char   DriverNamePrefix[] = "iw_nes";
+
+int nes_if_count = 0;
+
+#define MAX_NES_IFS 4
+struct nes_dev *nes_ifs[MAX_NES_IFS]= { 0 };
+
+
+/**
+ * nes_start_cm
+ * 
+ * @param nesdev
+ * @param new_ifa
+ * 
+ * @return int
+ */
+int nes_start_cm(struct nes_dev *nesdev, struct in_ifaddr *new_ifa)
+{
+       int result = 0;
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+       nes_ifs[0] = nesdev;
+
+       stack_ops_p->dhcp_control(0x00);
+
+       // set ip and subnet mask
+       stack_ops_p->set_ip_info(ntohl(new_ifa->ifa_address),
+                           ntohl(new_ifa->ifa_mask));
+       stack_ops_p->set_dev_name(nesdev->netdev->name);
+
+       if (nesdev->nes_stack_start == 0) {
+               stack_ops_p->stack_init(nesdev->netdev);
+               /* TODO: Deal with multiple IP addresses */
+               nesdev->local_ipaddr = new_ifa->ifa_address;
+
+               nesdev->nes_stack_start = 1;
+       }
+
+       return result;
+}
+
+
+/**
+ * nes_stop_cm
+ * 
+ * @param nesdev
+ * 
+ * @return int
+ */
+int nes_stop_cm(struct nes_dev *nesdev)
+{
+       if (nesdev->nes_stack_start) 
+       {
+               nesdev->nes_stack_start = 0;
+    stack_ops_p->stack_exit(nesdev->netdev);
+       }
+       return 0;
+}
+
+
+/**
+ * nes_update_arp
+ * 
+ * @param pMacAddress
+ * @param u32IpAddress
+ * @param u32ArpTimeout
+ * @param u16Entry
+ * @param type
+ */
+void nes_update_arp(unsigned char *pMacAddress, u32 u32IpAddress, 
+                    u32 u32ArpTimeout, u16 u16Entry, u16 type)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_dev *nesdev;
+       unsigned long flags;
+       u32 cqp_head;
+       u16 arp_index;
+
+       if (nes_ifs[0] == NULL) {
+               return;
+       }
+
+       nesdev = nes_ifs[0];
+
+       dprintk("%s: pMacAddress = %p, type = %u.\n", __FUNCTION__,
pMacAddress, type );
+       if (NULL == pMacAddress) {
+               dprintk("%s: Received a Delete request for IP address
0x%08X, index %u).\n", 
+                               __FUNCTION__, u32IpAddress, u16Entry );
+               nes_arp_table_update(nesdev, u32IpAddress,
NES_ARP_INDEX_DELETE);
+               return;
+       } else {
+               dprintk("%s: Received an Update request for IP address
0x%08X, index %u, address %02X:%02X:%02X:%02X:%02X:%02X).\n", 
+                __FUNCTION__, u32IpAddress, u16Entry, pMacAddress[0], 
+                               pMacAddress[1], pMacAddress[2],
pMacAddress[3], pMacAddress[4],
+                               pMacAddress[5]);
+       }
+
+       /* Add the ARP Entry */
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM;
+       arp_index = nes_arp_table_update(nesdev, u32IpAddress,
NES_ARP_INDEX_ADD);
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
(u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT;
+//     cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=  ((u32)arp_index)
<< NES_CQP_ARP_AEQ_INDEX_SHIFT;
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =  (u32)arp_index;
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+       *((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
cqp_head;
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =  0;
+       if (1 == type) {
+               cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
NES_CQP_ARP_VALID;
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] =  
+                 (((u32)pMacAddress[2])<<24) +
(((u32)pMacAddress[3])<<16) +
+                 (((u32)pMacAddress[4])<<8) + (u32)pMacAddress[5];
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] =
(((u32)pMacAddress[0])<<16) + (u32)pMacAddress[1];
+       } else {
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] =
0;
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
+       }
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]);
+       cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] =
cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX]);
+       cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] =
cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX]);
+
+       barrier();
+       // Ring doorbell (1 WQEs)
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 |
nesdev->cqp.qp_id );
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+}
+
+
+/**
+ * connect_worker
+ * @param qp
+ */
+static void connect_worker(void *qp)
+{
+    unsigned long qplockflags;
+       UINTPTR socket;
+       struct socket *ksock;
+       struct nes_qp *nesqp = qp;
+       struct nes_dev *nesdev = to_nesdev(nesqp->ibqp.device);
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct iw_cm_id *cm_id = nesqp->cm_id;
+       struct nes_hw_qp_wqe *wqe;
+       struct iw_cm_event cm_event;
+       struct NES_sockaddr_in  inet_addr;
+       struct NES_sockaddr_in new_socket_name;
+       struct nes_v4_quad nes_quad;
+       struct ib_qp_attr attr;
+    struct ietf_mpa_req_resp_frame *req_frame = nesqp->ietf_frame;
+       int kaddr_length;
+    int socket_bytes;
+    int err;
+    u16 resp_private_data_length;
+
+       dprintk("Attempting to connect to  0x%08X:0x%04X on local port
0x%04X.\n", 
+          ntohl(cm_id->remote_addr.sin_addr.s_addr), 
+          ntohs(cm_id->remote_addr.sin_port), 
+          ntohs(cm_id->local_addr.sin_port) );
+
+       memset( &inet_addr, 0, sizeof(inet_addr) );
+       inet_addr.sin_len = sizeof( inet_addr );
+       inet_addr.sin_family = NES_AF_INET;
+       inet_addr.sin_port = cm_id->remote_addr.sin_port;
+       inet_addr.sin_addr.NES_s_addr =
cm_id->remote_addr.sin_addr.s_addr;
+
+       err = stack_ops_p->sock_ops_p->connect(
+                                               nesqp->socket, 
+                                               (struct NES_sockaddr
*)&inet_addr,
+                                               sizeof(inet_addr));
+
+       dprintk("%s: Connect request returned %d.\n", __FUNCTION__,
err);
+
+       if (err < 0) {
+               dprintk("nes connect call returned %d.\n", err );
+        goto conn_err0;
+       }
+
+    /* send the req */
+    strcpy(&req_frame->key[0], IEFT_MPA_KEY_REQ);
+    req_frame->flags = IETF_MPA_FLAGS_CRC;
+    /* TODO: allow configuration of the revision */
+    /* TODO: Set context and registers properly */
+    req_frame->rev = mpa_version;
+
+    /* TODO: add retry logic checking the number of bytes sent */
+    err = stack_ops_p->sock_ops_p->send(nesqp->socket, (char
*)req_frame, 
+
sizeof(*req_frame)+nesqp->private_data_len,0);
+
+    dprintk("%s: Send for MPA request returned %d.\n", __FUNCTION__,
err);
+
+    if (err < 0) {
+        dprintk("nes send call returned %d.\n", err);
+        goto conn_err0;
+    }
+
+    /* receive the reply */
+    socket_bytes = 0;
+    do
+    {
+        err = stack_ops_p->sock_ops_p->recv(nesqp->socket, (char
*)req_frame, sizeof(*req_frame),0);
+
+        dprintk("%s: Recv for MPA reply returned %d.\n", __FUNCTION__,
err);
+
+        if (err < 0) {
+            goto conn_err0;
+        }
+        socket_bytes += err;
+    } while ( socket_bytes < sizeof(*req_frame) );
+
+    if (req_frame->flags&IETF_MPA_FLAGS_MARKERS) {
+        dprintk("%s: Peer specified markers in MPA reply.  Aborting MPA
negotiation\n", 
+                __FUNCTION__ );
+               /* TODO: Should send a reject */
+        goto conn_err0;
+    }
+    if (req_frame->flags&IETF_MPA_FLAGS_CRC) {
+        dprintk("%s: Peer specified CRC in MPA reply.  MPA version =
%u.\n", 
+                __FUNCTION__, req_frame->rev );
+    } else {
+        dprintk("%s: Peer did not specified CRC in MPA reply.  MPA
version = %u.\n", 
+                __FUNCTION__, req_frame->rev );
+       }
+
+    resp_private_data_length =
be16_to_cpu(req_frame->private_data_size);
+    if (resp_private_data_length){
+        if (resp_private_data_length>nesqp->private_data_len)
+        {
+            nesqp->ietf_frame =
kzalloc(sizeof(*nesqp->ietf_frame)+resp_private_data_length, 
+                                        GFP_KERNEL);
+            if (!nesqp->ietf_frame)
+            {
+                dprintk("%s: Error allocating response private data
area.\n", 
+                        __FUNCTION__ );
+                goto conn_err0;
+            }
+            *nesqp->ietf_frame = *req_frame;
+            kfree(req_frame);
+            req_frame = nesqp->ietf_frame;
+        }
+               err = stack_ops_p->sock_ops_p->recv(nesqp->socket, (char
*)req_frame->private_data, resp_private_data_length,0);
+
+               dprintk("%s: Recv for MPA response private data returned
%d.\n", __FUNCTION__, err);
+               if (err < 0) {
+                       goto conn_err0;
+               }
+    }
+
+       stack_ops_p->accelerate_socket(nesqp->socket,
nesqp->nesqp_context);
+
+       nesqp->nesqp_context->tcpPorts =
ntohs(cm_id->remote_addr.sin_port) << 16;
+       nesqp->nesqp_context->tcpPorts +=
ntohs(cm_id->local_addr.sin_port);
+       nesqp->nesqp_context->ip0 =
ntohl(cm_id->remote_addr.sin_addr.s_addr);
+
+       nesqp->nesqp_context->misc2 |=
(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
NES_QPCONTEXT_MISC2_SRC_IP_SHIFT;
+       nesqp->nesqp_context->arp_index_vlan |=
((u32)nes_arp_table_update(nesdev, nesqp->nesqp_context->ip0,
NES_ARP_INDEX_RESOLVE))<<16;
+       nesqp->nesqp_context->ts_val_delta = jiffies -
nes_read_indexed(nesdev->index_reg, NES_IDX_TCP_NOW);
+       nesqp->nesqp_context->ird_index = nesqp->hwqp.qp_id;
+       nesqp->nesqp_context->ird_ord_sizes |= (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 (send_first) {
+               wqe = &nesqp->hwqp.sq_vbase[0];
+               *((struct nes_qp
**)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+               *((u64
*)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) |=
NES_SW_CONTEXT_ALIGN>>1;
+               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 &=
~(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 = (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
27;
+       nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; 
+       nes_quad.TcpPorts = cm_id->remote_addr.sin_port; 
+       nes_quad.TcpPorts |= (u32)cm_id->local_addr.sin_port << 16;
+   
+       // Produce hash key  
+       nesqp->hte_index = nes_crc32(  TRUE,
+
NES_HASH_CRC_INITAL_VALUE,
+
NES_HASH_CRC_FINAL_XOR,
+                                                  sizeof(nes_quad),
+                                                  (PUINT8)&nes_quad,
+                                                  ORDER,
+                                                  REFIN,
+                                                  REFOUT
+                                               );
+
+       dprintk("%s: HTE Index = 0x%08X, CRC = 0x%08X\n", __FUNCTION__,
+                                       nesqp->hte_index,
nesqp->hte_index & nesadapter->hte_index_mask);
+
+       nesqp->hte_index &= nesadapter->hte_index_mask;
+       nesqp->nesqp_context->hte_index = nesqp->hte_index;
+
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE);
+
+       kaddr_length = sizeof(new_socket_name);
+       stack_ops_p->sock_ops_p->getsockname( nesqp->socket,
+
(struct NES_sockaddr *)&new_socket_name,
+
&kaddr_length);
+
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr.sin_family = new_socket_name.sin_family;
+       cm_event.local_addr.sin_port = new_socket_name.sin_port;
+       cm_event.local_addr.sin_addr.s_addr =
new_socket_name.sin_addr.NES_s_addr;
+       cm_event.remote_addr = cm_id->remote_addr;
+       cm_event.private_data = &req_frame->private_data;
+       cm_event.private_data_len = resp_private_data_length;
+
+       cm_id->event_handler(cm_id, &cm_event);   
+       // kfree(req_frame);
+
+       dprintk("%s: Exiting connect thread for QP%u\n", 
+          __FUNCTION__,  nesqp->hwqp.qp_id );
+    return;
+
+conn_err0:
+    kfree(req_frame);
+       if (nesqp->cm_id)
+       {
+           spin_lock_irqsave(&nesqp->lock, qplockflags);
+               if (nesqp->ksock) {
+                       ksock = nesqp->ksock;
+                       socket = nesqp->socket;
+                   nesqp->ksock = 0;
+                   nesqp->socket = 0;
+                       spin_unlock_irqrestore(&nesqp->lock,
qplockflags);
+                   stack_ops_p->sock_ops_p->close( socket );
+                       sock_release(ksock);
+               } else {
+                       spin_unlock_irqrestore(&nesqp->lock,
qplockflags);
+               }
+           cm_id->rem_ref(cm_id);
+           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.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;
+
+           cm_id->event_handler(cm_id, &cm_event);   
+       }
+}
+
+
+/**
+ * nes_sock_release
+ * 
+ * @param nesqp
+ * @param qplockflags
+ */
+void nes_sock_release(struct nes_qp *nesqp, unsigned long *qplockflags)
{
+       UINTPTR socket;
+       struct socket *ksock;
+
+       ksock = nesqp->ksock;
+       socket = nesqp->socket;
+    nesqp->ksock = 0;
+    nesqp->socket = 0;
+       spin_unlock_irqrestore(&nesqp->lock, *qplockflags);
+       stack_ops_p->sock_ops_p->close( socket );
+       sock_release(ksock);
+    spin_lock_irqsave(&nesqp->lock, *qplockflags);
+}
+
+
+/**
+ * nes_connect
+ * 
+ * @param cm_id
+ * @param conn_param
+ * 
+ * @return int
+ */
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param
*conn_param)
+{
+       int err;
+       int int_socket_opt;
+       u8 u8temp;
+       UINTPTR socket;
+       struct socket *ksock;
+       struct NES_sockaddr_in  inet_addr;
+       struct sockaddr_in  kinet_addr;
+       int kaddr_length;
+       struct nes_qp *nesqp;
+       struct nes_dev *nesdev = to_nesdev(cm_id->device);
+       struct ib_qp *ibqp;
+
+       dprintk("%s:%s:%u: data len = %u, cm_id = %p, event handler =
%p.\n", __FILE__, 
+                       __FUNCTION__, __LINE__,
conn_param->private_data_len, cm_id, cm_id->event_handler);
+
+    // update the NES stack routing table
+    // Unfortunately, cannot be done in interface event handler.
Handler is called before routes are setup.
+    dprintk("call nes_update_rt\n");
+    // stack_ops_p->update_route(nesdev->netdev->name);
+    stack_ops_p->dump_rt_table();
+       
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+       nesqp = to_nesqp(ibqp);
+
+    nesqp->ietf_frame =
kzalloc(sizeof(*nesqp->ietf_frame)+conn_param->private_data_len,
GFP_KERNEL);
+    if (!nesqp->ietf_frame)
+        return -ENOMEM;
+
+    nesqp->active_conn = 1;
+       dprintk("%s: QP%u, Destination IP = 0x%08X, local = 0x%08X.\n", 
+               __FUNCTION__, nesqp->hwqp.qp_id, 
+               ntohl(cm_id->remote_addr.sin_addr.s_addr), 
+               ntohl(cm_id->local_addr.sin_addr.s_addr));
+
+       socket = stack_ops_p->sock_ops_p->socket(NES_AF_INET,
NES_SOCK_STREAM, 0);
+       dprintk("returned socket = %p.\n", (void *)socket);
+       nesqp->socket = socket;
+   
+       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP,
&ksock);
+       if (err < 0) {
+               dprintk("kernel socket call returned %d.\n", err );
+               stack_ops_p->sock_ops_p->close( socket );
+               return err;
+       }
+
+       dprintk("kernel socket =  %p.\n", ksock );
+       nesqp->ksock = ksock;
+
+       memset( &kinet_addr, 0, sizeof(kinet_addr) );
+       kinet_addr.sin_family = AF_INET;
+       kinet_addr.sin_port = cm_id->local_addr.sin_port;
+       kinet_addr.sin_addr.s_addr = cm_id->local_addr.sin_addr.s_addr;
+       err = ksock->ops->bind(ksock, (struct sockaddr *)&kinet_addr,
sizeof(kinet_addr));
+       if (err < 0) {
+               dprintk("kernel bind call returned %d.\n", err );
+               sock_release(ksock);
+               stack_ops_p->sock_ops_p->close( socket );
+               return err;
+       }
+
+       memset( &kinet_addr, 0, sizeof(kinet_addr) );
+       err = ksock->ops->getname(ksock, (struct sockaddr *)&kinet_addr,
&kaddr_length,0);
+       if (err < 0) {
+               dprintk("kernel getname call returned %d.\n", err );
+               sock_release(ksock);
+               stack_ops_p->sock_ops_p->close( socket );
+               return err;
+       }
+
+       dprintk("kernel getname call returned port =  0x%04X.\n",
ntohs(kinet_addr.sin_port) );
+       cm_id->local_addr.sin_port = kinet_addr.sin_port;
+       inet_addr.sin_len = sizeof( inet_addr );
+       inet_addr.sin_family = NES_AF_INET;
+       inet_addr.sin_port = cm_id->local_addr.sin_port;
+       inet_addr.sin_addr.NES_s_addr =
cm_id->local_addr.sin_addr.s_addr;
+       err = stack_ops_p->sock_ops_p->bind( 
+                       socket,
+                       (struct NES_sockaddr *)&inet_addr,
+                       sizeof(inet_addr));
+
+       if (err < 0) {
+               dprintk("nes bind call returned %d.\n", err );
+               sock_release(ksock);
+               stack_ops_p->sock_ops_p->close( socket );
+               return err;
+       }
+       
+       int_socket_opt = 1;
+       err = stack_ops_p->sock_ops_p->setsockopt( 
+                       socket, NES_SOL_SOCKET, NES_TCP_NODELAY, 
+                       (char *)&int_socket_opt,
sizeof(int_socket_opt));
+
+       if (err < 0) {
+               dprintk("nes setsockopt (TCP_NODELAY) call returned
%d.\n", err );
+       }
+
+       int_socket_opt = 0;
+       u8temp = 1 << (ntohs(cm_id->local_addr.sin_port)&7);
+       nesdev->apbv_table[ntohs(cm_id->local_addr.sin_port)>>3] |=
u8temp;
+
+       /* Cache the cm_id in the qp */
+       nesqp->cm_id = cm_id;
+       cm_id->provider_data = nesqp;
+       /* Associate QP <--> CM_ID */
+       cm_id->add_ref(cm_id);
+
+    /* Copy the private data */
+    if (conn_param->private_data_len) {
+        memcpy(nesqp->ietf_frame->private_data,
conn_param->private_data, 
+               conn_param->private_data_len);
+    }
+    nesqp->ietf_frame->private_data_size =
cpu_to_be16(conn_param->private_data_len);
+    nesqp->private_data_len = conn_param->private_data_len;
+    nesqp->nesqp_context->ird_ord_sizes |= (u32)conn_param->ord;
+       dprintk("%s:requested ord = 0x%08X.\n", __FUNCTION__,
(u32)conn_param->ord );
+
+    // start a worker thread
+       nesqp->wq = create_singlethread_workqueue("NesConnectWQ");
+       INIT_WORK(&nesqp->work, connect_worker, nesqp);
+       queue_work(nesqp->wq, &nesqp->work);
+
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+       return err;
+}
+
+
+/**
+ * nes_disconnect_worker
+ * 
+ * @param qp
+ */
+void nes_disconnect_worker(void *qp)
+{
+       struct nes_qp *nesqp = qp;
+       // struct nes_dev *nesdev = to_nesdev(nesqp->ibqp.device);
+       // struct iw_cm_id *cm_id = nesqp->cm_id;
+       // struct iw_cm_event cm_event;
+       struct ib_qp_attr attr;
+       // u8 u8temp;
+
+       dprintk("%s: Disconnecting qp%u after AE\n", __FUNCTION__,
nesqp->hwqp.qp_id );
+
+       switch (nesqp->ibqp_state) {
+               case IB_QPS_RTS:
+                       /* this should be a FIN received */
+                       attr.qp_state = IB_QPS_SQD;
+                       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE
);
+                       break;
+               case IB_QPS_SQD:
+                       /* this should be a Close complete */
+                       attr.qp_state = IB_QPS_SQD;
+                       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE
);
+                       break;
+               case IB_QPS_SQE:
+                       /* TODO: Add Terminate received processing */
+                       break;
+               default:
+                       dprintk("%s: Should not be here. QP%u state =
%u.\n", __FUNCTION__, nesqp->hwqp.qp_id, nesqp->ibqp_state );
+
+       }
+
+    return;
+}
+
+
+/**
+ * nes_disconnect
+ * 
+ * @param cm_id
+ * @param abrupt
+ * 
+ * @return int
+ */
+int nes_disconnect(struct iw_cm_id *cm_id, int abrupt)
+{
+       struct ib_qp_attr attr;
+       struct ib_qp *ibqp;
+       struct nes_qp *nesqp;
+       struct nes_dev *nesdev = to_nesdev(cm_id->device);
+       int err = 0;
+       u8 u8temp;
+
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+       dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
atomic_read(&nesdev->netdev->refcnt));
+
+       /* If the qp was already destroyed, then there's no QP */
+       if (cm_id->provider_data == 0)
+               return 0;
+
+       nesqp = (struct nes_qp *)cm_id->provider_data;
+       ibqp = &nesqp->ibqp;
+
+       /* Disassociate the QP from this cm_id */
+       cm_id->provider_data = 0;
+       cm_id->rem_ref(cm_id);
+       nesqp->cm_id = 0;
+
+       stack_ops_p->decelerate_socket(nesqp->socket, 
+                                (struct nes_uploaded_qp_context *)
+                                nesqp->nesqp_context);
+  
+       if (nesqp->active_conn) {
+         u8temp = 1 << (ntohs(cm_id->local_addr.sin_port)&7);
+         nesdev->apbv_table[ntohs(cm_id->local_addr.sin_port)>>3] &=
~(u8temp);
+       } else {
+               dev_put(nesdev->netdev);
+        /* Need to free the Last Streaming Mode Message */
+        pci_free_consistent(nesdev->pcidev, 
+
nesqp->private_data_len+sizeof(*nesqp->ietf_frame), 
+                            nesqp->ietf_frame,
+                            nesqp->ietf_frame_pbase);
+    }
+
+       if (nesqp->ksock) sock_release(nesqp->ksock);
+       stack_ops_p->sock_ops_p->close( nesqp->socket );
+       nesqp->ksock = 0;
+       nesqp->socket = 0;
+       if (nesqp->wq) {
+               destroy_workqueue(nesqp->wq);
+               nesqp->wq = NULL;
+       }
+
+       memset(&attr, 0, sizeof(struct ib_qp_attr));
+       if (abrupt)
+               attr.qp_state = IB_QPS_ERR;
+       else
+               attr.qp_state = IB_QPS_SQD;
+
+       return err;
+}
+
+
+/**
+ * nes_accept
+ * 
+ * @param cm_id
+ * @param conn_param
+ * 
+ * @return int
+ */
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param
*conn_param)
+{
+       struct nes_qp *nesqp;
+       struct nes_dev *nesdev;
+       struct nes_adapter *nesadapter;
+       struct ib_qp *ibqp;
+    struct nes_hw_qp_wqe *wqe;
+       struct nes_v4_quad nes_quad;
+       struct ib_qp_attr attr;
+    struct iw_cm_event cm_event;
+
+       dprintk("%s:%s:%u: data len = %u\n", 
+                       __FILE__, __FUNCTION__, __LINE__,
conn_param->private_data_len);
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+       nesqp = to_nesqp(ibqp);
+       nesdev = to_nesdev(nesqp->ibqp.device);
+       nesadapter = nesdev->nesadapter;
+       dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
atomic_read(&nesdev->netdev->refcnt));
+
+    nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev, 
+
sizeof(*nesqp->ietf_frame)+conn_param->private_data_len,
+                                             &nesqp->ietf_frame_pbase);
+    if (!nesqp->ietf_frame) {
+        dprintk(KERN_ERR PFX "%s: Unable to allocate memory for private
data\n", __FUNCTION__);
+        return -ENOMEM;
+    }
+    dprintk(PFX "%s: PCI consistent memory for "
+            "private data located @ %p (pa = 0x%08lX.) size = %u.\n", 
+            __FUNCTION__, nesqp->ietf_frame, (unsigned
long)nesqp->ietf_frame_pbase,
+            conn_param->private_data_len+sizeof(*nesqp->ietf_frame));
+    nesqp->private_data_len = conn_param->private_data_len;
+
+    strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REP);
+    memcpy(&nesqp->ietf_frame->private_data, conn_param->private_data,
conn_param->private_data_len);
+    nesqp->ietf_frame->private_data_size =
cpu_to_be16(conn_param->private_data_len);
+    nesqp->ietf_frame->rev = mpa_version;
+    nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+
+    wqe = &nesqp->hwqp.sq_vbase[0];
+    *((struct nes_qp
**)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+       *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) |=
NES_SW_CONTEXT_ALIGN>>1;
+    wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING); 
+    wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
cpu_to_le32(conn_param->private_data_len+sizeof(*nesqp->ietf_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(*nesqp->ietf_frame));
+    wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+       nesqp->nesqp_context->ird_ord_sizes |=
NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU;
+    nesqp->skip_lsmm = 1;
+
+       /* Cache the cm_id in the qp */
+       nesqp->cm_id = cm_id;
+       nesqp->socket = (u32)cm_id->provider_data;
+       nesqp->ksock = 0;
+       cm_id->provider_data = nesqp;
+       nesqp->active_conn = 0;
+    /* Just save the private data here and set context bits */
+       stack_ops_p->accelerate_socket(nesqp->socket,
nesqp->nesqp_context);
+       nesqp->nesqp_context->tcpPorts =
ntohs(cm_id->remote_addr.sin_port) << 16;
+       nesqp->nesqp_context->tcpPorts +=
ntohs(cm_id->local_addr.sin_port);
+       nesqp->nesqp_context->ip0 =
ntohl(cm_id->remote_addr.sin_addr.s_addr);
+       nesqp->nesqp_context->misc2 |=
(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
NES_QPCONTEXT_MISC2_SRC_IP_SHIFT;
+       nesqp->nesqp_context->arp_index_vlan |=
((u32)nes_arp_table_update(nesdev, nesqp->nesqp_context->ip0,
NES_ARP_INDEX_RESOLVE))<<16;
+       nesqp->nesqp_context->ts_val_delta = jiffies -
nes_read_indexed(nesdev->index_reg, NES_IDX_TCP_NOW);
+       nesqp->nesqp_context->ird_index = nesqp->hwqp.qp_id;
+       nesqp->nesqp_context->ird_ord_sizes |= (u32)1 <<
NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT; 
+       nesqp->nesqp_context->ird_ord_sizes |= (u32)conn_param->ord; 
+
+       memset ( &nes_quad, 0, sizeof(nes_quad));
+
+       nes_quad.DstIpAdrIndex = (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
27;
+       nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; 
+       nes_quad.TcpPorts = cm_id->remote_addr.sin_port; 
+       nes_quad.TcpPorts |= (u32)cm_id->local_addr.sin_port << 16;
+   
+       // Produce hash key  
+       nesqp->hte_index = nes_crc32(  TRUE,
+
NES_HASH_CRC_INITAL_VALUE,
+
NES_HASH_CRC_FINAL_XOR,
+                                                  sizeof(nes_quad),
+                                                  (PUINT8)&nes_quad,
+                                                  ORDER,
+                                                  REFIN,
+                                                  REFOUT
+                                               );
+
+       dprintk("%s: HTE Index = 0x%08X, CRC = 0x%08X\n", 
+                                       __FUNCTION__, nesqp->hte_index,
+                                       nesqp->hte_index &
nesadapter->hte_index_mask);
+
+       nesqp->hte_index &= nesadapter->hte_index_mask;
+       nesqp->nesqp_context->hte_index = nesqp->hte_index;
+
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE );
+       cm_id->add_ref(cm_id);
+
+    cm_event.event = IW_CM_EVENT_ESTABLISHED;
+    cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+    cm_event.provider_data = (void *)nesqp;
+    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;
+
+    cm_id->event_handler(cm_id, &cm_event);   
+
+       return 0;
+}
+
+
+/**
+ * nes_reject
+ * 
+ * @param cm_id
+ * @param pdata
+ * @param pdata_len
+ * 
+ * @return int
+ */
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+       
+    stack_ops_p->sock_ops_p->close( (UINTPTR)cm_id->provider_data );
+       return 0;
+}
+
+
+/**
+ * listen_worker
+ * 
+ * @param listener
+ */
+static void listen_worker( void *listener )
+{
+       struct nes_listener *nes_listener = listener;
+       struct nes_dev *nesdev = nes_listener->nesdev;
+       struct iw_cm_id *cm_id = nes_listener->cm_id;
+       struct iw_cm_event cm_event;
+       struct NES_sockaddr_in  inet_addr;
+       struct NES_sockaddr_in new_socket_name;
+    struct ietf_mpa_req_resp_frame req_frame;
+    char *private_data = NULL;
+       UINTPTR new_socket;
+       int kaddr_length;
+    int err;
+    int socket_bytes;
+    u16 req_private_data_length;
+
+    cm_id->add_ref(cm_id);
+       do {
+               dprintk("Issuing Accept on 0x%08X:0x%04X (socket
0x%0lX), netdev->refcnt = %u.\n", 
+
ntohl(cm_id->local_addr.sin_addr.s_addr), 
+                               ntohs(cm_id->local_addr.sin_port),
nes_listener->socket, atomic_read(&nesdev->netdev->refcnt));
+
+               kaddr_length = sizeof(inet_addr);
+               new_socket =
stack_ops_p->sock_ops_p->accept(nes_listener->socket,
+                                                               (struct
NES_sockaddr *)&inet_addr, &kaddr_length);
+
+               dprintk("%s: Accept request returned %d.\n",
__FUNCTION__, 
+                               (int)new_socket );
+               if ((int)new_socket < 0) {
+                       if (-NES_ECONNABORTED != (int)new_socket)
+                       {
+                               cm_event.event =
IW_CM_EVENT_CONNECT_REQUEST;
+                               cm_event.status =
IW_CM_EVENT_STATUS_EINVAL;
+                               cm_event.provider_data = (void
*)new_socket;
+                               cm_event.local_addr =
nes_listener->cm_id->local_addr;
+                               cm_event.remote_addr.sin_family =
AF_INET;
+                               cm_event.remote_addr.sin_port =
inet_addr.sin_port;
+                               cm_event.remote_addr.sin_addr.s_addr =
inet_addr.sin_addr.NES_s_addr;
+                               cm_event.private_data = NULL;
+                               cm_event.private_data_len = 0;
+                continue;
+                       }
+                       break; 
+               }
+
+               dprintk("Accept address info:
0x%08X:0x%04X.netdev->refcnt = %u\n", 
+               ntohl(inet_addr.sin_addr.NES_s_addr), 
+               ntohs(inet_addr.sin_port),
atomic_read(&nesdev->netdev->refcnt));
+               
+        /* Issue receive for IETF mode request */
+        socket_bytes = 0;
+        do
+        {
+            err = stack_ops_p->sock_ops_p->recv(new_socket, (char
*)&req_frame, sizeof(req_frame),0);
+
+            dprintk("%s: Recv for MPA request returned %d.\n",
__FUNCTION__, err );
+
+            if (err < 0) {
+                goto accept_err0;
+            }
+            socket_bytes += err;
+        } while (socket_bytes < sizeof(req_frame));
+
+        if (req_frame.flags&IETF_MPA_FLAGS_MARKERS)
+        {
+           dprintk("%s: Peer specified Markers in MPA request.
Aborting MPA negotiation \n", 
+                       __FUNCTION__ );
+            goto accept_err0;
+        }
+           if (req_frame.flags&IETF_MPA_FLAGS_CRC) {
+           dprintk("%s: Peer specified CRC in MPA reply.  MPA version =
%u.\n", 
+                       __FUNCTION__, req_frame.rev );
+           } else {
+           dprintk("%s: Peer did not specified CRC in MPA reply.  MPA
version = %u.\n", 
+                       __FUNCTION__, req_frame.rev );
+               }
+
+        req_private_data_length =
be16_to_cpu(req_frame.private_data_size);
+        if (req_private_data_length) {
+            private_data = kzalloc(req_private_data_length,
GFP_KERNEL);
+            if (!private_data)
+            {
+                dprintk("%s: Error allocating req private data
area.\n", __FUNCTION__ );
+                goto accept_err0;
+            }
+            err = stack_ops_p->sock_ops_p->recv(new_socket,
private_data, req_private_data_length,0);
+
+            dprintk("%s: Recv for MPA request private data returned
%d.\n", __FUNCTION__, err );
+            if (err < 0) {
+                goto accept_err0;
+            }
+        }
+
+               kaddr_length = sizeof(new_socket_name);
+               stack_ops_p->sock_ops_p->getsockname( new_socket,
+
(struct NES_sockaddr *)&new_socket_name,
+
&kaddr_length);
+
+               cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
+               cm_event.status = IW_CM_EVENT_STATUS_OK;
+               cm_event.provider_data = (void *)new_socket;
+               cm_event.local_addr.sin_family =
new_socket_name.sin_family;
+               cm_event.local_addr.sin_port = new_socket_name.sin_port;
+               cm_event.local_addr.sin_addr.s_addr =
new_socket_name.sin_addr.NES_s_addr;
+               cm_event.remote_addr.sin_family = AF_INET;
+               cm_event.remote_addr.sin_port = inet_addr.sin_port;
+               cm_event.remote_addr.sin_addr.s_addr =
inet_addr.sin_addr.NES_s_addr;
+               cm_event.private_data = private_data;
+               cm_event.private_data_len = req_private_data_length;
+
+               cm_id->event_handler(cm_id, &cm_event);
+
+               if (private_data)
+        {
+        }
+
+        private_data = NULL;
+        continue;
+
+accept_err0:
+        if (private_data)
+            kfree(private_data);
+        private_data = NULL;
+        stack_ops_p->sock_ops_p->close( new_socket );
+
+       } while (1);
+
+       dprintk("Exiting Listener worker thread \n" );
+       nes_listener->accept_failed = 1;
+    return;
+}
+
+
+/**
+ * nes_create_listen
+ * 
+ * @param cm_id
+ * @param backlog
+ * 
+ * @return int
+ */
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+       int err;
+       int int_socket_opt;
+       u8 u8temp;
+       UINTPTR socket;
+       struct socket *ksock;
+       struct nes_listener *nes_listener;
+       struct sockaddr_in  kinet_addr;
+       struct NES_sockaddr_in  inet_addr;
+       int kaddr_length;
+       struct nes_dev *nesdev = to_nesdev(cm_id->device);
+
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+       // Allocate a listener
+       nes_listener = kzalloc(sizeof *nes_listener, GFP_KERNEL);
+       if (NULL == nes_listener) {
+               dprintk("%s:%s: Error allocating listener.\n", __FILE__,
__FUNCTION__ );
+               return -ENOMEM;
+       }
+
+       dprintk("%s: socket function pointer = %p, listener = %p, cm_id
= %p, event_handler = %p, netdev->refcnt = %u.\n", 
+                       __FUNCTION__, stack_ops_p->sock_ops_p->socket,
nes_listener, cm_id, cm_id->event_handler, 
+                       atomic_read(&nesdev->netdev->refcnt) );
+       nes_listener->nesdev = nesdev;
+       socket =  stack_ops_p->sock_ops_p->socket( NES_AF_INET,
NES_SOCK_STREAM, 0 );
+       dprintk("returned socket = %p.\n", (void *)socket );
+       if ((long)socket < 0) {
+               dprintk("NES socket call returned %d.\n", (int)socket );
+               return (int)socket;
+       }
+       nes_listener->socket = socket;
+
+       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP,
&ksock);
+       if (err < 0) {
+               dprintk("kernel socket call returned %d.\n", err );
+               stack_ops_p->sock_ops_p->close( socket );
+               return err;
+       }
+
+       dprintk("kernel socket =  %p.\n", ksock );
+       nes_listener->ksock = ksock;
+
+       memset( &kinet_addr, 0, sizeof(kinet_addr) );
+       kinet_addr.sin_family = AF_INET;
+       kinet_addr.sin_port = cm_id->local_addr.sin_port;
+       kinet_addr.sin_addr.s_addr = cm_id->local_addr.sin_addr.s_addr;
+       err = ksock->ops->bind(ksock, (struct sockaddr *)&kinet_addr,
sizeof(kinet_addr));
+       if (err < 0) {
+               dprintk("kernel bind call returned %d.\n", err );
+               goto release_sockets0;
+       }
+
+       memset( &kinet_addr, 0, sizeof(kinet_addr) );
+       err = ksock->ops->getname(ksock, (struct sockaddr *)&kinet_addr,
&kaddr_length,0);
+       if (err < 0) {
+               dprintk("kernel getname call returned %d.\n", err );
+               goto release_sockets0;
+       }
+
+       dprintk("kernel getname call returned port =  0x%04X.\n",
kinet_addr.sin_port );
+       cm_id->local_addr.sin_port = kinet_addr.sin_port;
+       inet_addr.sin_len = sizeof( inet_addr );
+       inet_addr.sin_family = NES_AF_INET;
+       inet_addr.sin_port = cm_id->local_addr.sin_port;
+       inet_addr.sin_addr.NES_s_addr =
cm_id->local_addr.sin_addr.s_addr;
+       err = stack_ops_p->sock_ops_p->bind(socket, (struct NES_sockaddr
*)&inet_addr,
+
sizeof(inet_addr));
+       if (err < 0) {
+               dprintk("NES Socket bind call returned %d.\n", err );
+               goto release_sockets0;
+       }
+
+       int_socket_opt = 1;
+       err = stack_ops_p->sock_ops_p->setsockopt(socket,
NES_SOL_SOCKET, NES_TCP_NODELAY, 
+
(char *)&int_socket_opt, sizeof(int_socket_opt));
+
+       if (err < 0) {
+               dprintk("%s: nes setsockopt (TCP_NODELAY) call returned
%d.\n", __FUNCTION__, err );
+       }
+
+       int_socket_opt = 0;
+       err = stack_ops_p->sock_ops_p->setsockopt(socket,
NES_SOL_SOCKET, TCPOPT_TIMESTAMP, 
+
(char *)&int_socket_opt, sizeof(int_socket_opt));
+
+       if (err < 0) {
+               dprintk("%s: nes setsockopt (TCPOPT_TIMESTAMP) call
returned %d.\n", __FUNCTION__, err );
+       }
+
+       int_socket_opt = (496*1024)-8;
+       err = stack_ops_p->sock_ops_p->setsockopt(socket,
NES_SOL_SOCKET, NES_SO_RCVBUF, 
+
(char *)&int_socket_opt, sizeof(int_socket_opt));
+
+       if (err < 0) {
+               dprintk("%s: nes setsockopt (NES_SO_RECVBUF) call
returned %d.\n", __FUNCTION__, err);
+       }
+
+       u8temp = 1 << (ntohs(cm_id->local_addr.sin_port)&7);
+       nesdev->apbv_table[ntohs(cm_id->local_addr.sin_port)>>3] |=
u8temp;
+
+       dprintk("Attempting to listen on 0x%08X:0x%04X.\n", 
+          ntohl(cm_id->local_addr.sin_addr.s_addr), 
+          ntohs(cm_id->local_addr.sin_port) );
+
+       err = stack_ops_p->sock_ops_p->listen(socket, backlog );
+
+       dprintk("Listen request returned %X.\n", err );
+
+       if (err < 0) {
+               dprintk("NES Socket listen call returned %d.\n", err );
+               goto release_sockets0;
+       }
+
+       dprintk("Setting cm_id->provider_data for listen to %p.\n",
nes_listener );
+       nes_listener->cm_id = cm_id;
+       cm_id->provider_data = nes_listener;
+
+       // start a worker thread
+       nes_listener->wq =
create_singlethread_workqueue("NesListenerWQ");
+
+       INIT_WORK(&nes_listener->work, listen_worker, nes_listener);
+       queue_work(nes_listener->wq, &nes_listener->work);
+       dprintk("%s: Exiting create listen, netdev->refcnt = %u.\n",
__FUNCTION__, 
+                       atomic_read(&nesdev->netdev->refcnt) );
+       return 0;
+
+release_sockets0:
+       sock_release(ksock);
+       stack_ops_p->sock_ops_p->close( socket );
+       return err;
+}
+
+
+/**
+ * nes_destroy_listen
+ * 
+ * @param cm_id
+ * 
+ * @return int
+ */
+int nes_destroy_listen(struct iw_cm_id *cm_id)
+{
+       struct nes_listener *nes_listener = (struct nes_listener
*)(unsigned long)cm_id->provider_data;
+       struct nes_dev *nesdev = to_nesdev(cm_id->device);
+       int err;
+       u8 u8temp;
+
+       dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+       err = 0;
+
+       u8temp = 1 << (ntohs(cm_id->local_addr.sin_port)&7);
+       nesdev->apbv_table[ntohs(cm_id->local_addr.sin_port)>>3] &=
~(u8temp);
+
+       sock_release(nes_listener->ksock);
+       stack_ops_p->sock_ops_p->close( nes_listener->socket );
+
+       do {
+               msleep(1);
+       } while( 0 == nes_listener->accept_failed );
+
+       //      dprintk("%s: Accept failed.\n", __FUNCTION__ );
+       destroy_workqueue(nes_listener->wq);
+
+    cm_id->rem_ref(cm_id);
+       kfree(nes_listener);
+
+       return err;
+}
+


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to