[openib-general] [PATCH 3/9] NetEffect 10Gb RNIC Driver: openfabrics connection manager c file

Glenn Grundstrom ggrundstrom at NetEffect.com
Thu Oct 26 16:58:48 PDT 2006


Kernel driver patch 3 of 9.

Signed-off-by: Glenn Grundstrom <glenng at neteffect.com>

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

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;
+}
+






More information about the general mailing list