diff mbox

[2/4] RDMA/nes: Add support for iWARP Port Mapper user space service

Message ID 20130831194415.GA27632@TENIKOLO-MOBL1 (mailing list archive)
State Rejected
Headers show

Commit Message

Nikolova, Tatyana E Aug. 31, 2013, 7:44 p.m. UTC
Add support for iWARP Port Mapper (IWPM) user space service

Signed-off-by: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
Reviewed-by: Robert Sharp <robert.o.sharp@intel.com>
Reviewed-by: Donald Wood <donald.e.wood@intel.com>
Reviewed-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>

---
 drivers/infiniband/hw/nes/Makefile      |    2 +-
 drivers/infiniband/hw/nes/nes.c         |   16 +-
 drivers/infiniband/hw/nes/nes.h         |    2 +
 drivers/infiniband/hw/nes/nes_cm.c      |  189 ++++--
 drivers/infiniband/hw/nes/nes_cm.h      |   12 +-
 drivers/infiniband/hw/nes/nes_netlink.c | 1223 +++++++++++++++++++++++++++++++
 drivers/infiniband/hw/nes/nes_netlink.h |  108 +++
 drivers/infiniband/hw/nes/nes_nic.c     |    5 +
 8 files changed, 1502 insertions(+), 55 deletions(-)
 create mode 100644 drivers/infiniband/hw/nes/nes_netlink.c
 create mode 100644 drivers/infiniband/hw/nes/nes_netlink.h

Comments

Steve Wise Sept. 3, 2013, 4:16 p.m. UTC | #1
On 8/31/2013 2:44 PM, Tatyana Nikolova wrote:
> Add support for iWARP Port Mapper (IWPM) user space service
>
> Signed-off-by: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
> Reviewed-by: Robert Sharp <robert.o.sharp@intel.com>
> Reviewed-by: Donald Wood <donald.e.wood@intel.com>
> Reviewed-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
>
> ---
>   drivers/infiniband/hw/nes/Makefile      |    2 +-
>   drivers/infiniband/hw/nes/nes.c         |   16 +-
>   drivers/infiniband/hw/nes/nes.h         |    2 +
>   drivers/infiniband/hw/nes/nes_cm.c      |  189 ++++--
>   drivers/infiniband/hw/nes/nes_cm.h      |   12 +-
>   drivers/infiniband/hw/nes/nes_netlink.c | 1223 +++++++++++++++++++++++++++++++
>   drivers/infiniband/hw/nes/nes_netlink.h |  108 +++
>   drivers/infiniband/hw/nes/nes_nic.c     |    5 +
>   8 files changed, 1502 insertions(+), 55 deletions(-)
>   create mode 100644 drivers/infiniband/hw/nes/nes_netlink.c
>   create mode 100644 drivers/infiniband/hw/nes/nes_netlink.h
>
> diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
> index 97820c2..5b6cec2 100644
> --- a/drivers/infiniband/hw/nes/Makefile
> +++ b/drivers/infiniband/hw/nes/Makefile
> @@ -1,3 +1,3 @@
>   obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
>   
> -iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o
> +iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o nes_netlink.o
> diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
> index 4291410..9be43b3 100644
> --- a/drivers/infiniband/hw/nes/nes.c
> +++ b/drivers/infiniband/hw/nes/nes.c
> @@ -68,7 +68,6 @@ MODULE_VERSION(DRV_VERSION);
>   int max_mtu = 9000;
>   int interrupt_mod_interval = 0;
>   
> -
>   /* Interoperability */
>   int mpa_version = 1;
>   module_param(mpa_version, int, 0644);
> @@ -672,6 +671,18 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
>   	}
>   	nes_notifiers_registered++;
>   
> +	spin_lock_init(&nes_nlmsg_lock);
> +	spin_lock_init(&nes_mapping_lock);
> +
> +	/* List of submitted requests, searched for completions */
> +	INIT_LIST_HEAD(&nes_nlmsg_request_list);
> +	/* List of iwpm mappings in use */
> +	INIT_LIST_HEAD(&nes_mapping_info_list);
> +
> +	if (ibnl_add_client(RDMA_NL_NES, RDMA_NL_IWPM_NUM_OPS, nes_nl_cb_table))
> +		printk(KERN_ERR PFX "%s[%u]: Failed to add netlink callback\n",
> +			__func__, __LINE__);
> +
>   	INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
>   
>   	/* Initialize network devices */
> @@ -707,6 +718,7 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
>   
>   	nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
>   			nesdev->netdev_count, nesdev->nesadapter->netdev_count);
> +	ibnl_remove_client(RDMA_NL_NES);
>   
>   	nes_notifiers_registered--;
>   	if (nes_notifiers_registered == 0) {
> @@ -770,6 +782,8 @@ static void nes_remove(struct pci_dev *pcidev)
>   				nesdev->nesadapter->netdev_count--;
>   			}
>   		}
> +	ibnl_remove_client(RDMA_NL_NES);
> +	nes_destroy_mapinfo_list();
>   
>   	nes_notifiers_registered--;
>   	if (nes_notifiers_registered == 0) {
> diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
> index 33cc589..21b8a86 100644
> --- a/drivers/infiniband/hw/nes/nes.h
> +++ b/drivers/infiniband/hw/nes/nes.h
> @@ -130,6 +130,7 @@
>   #define NES_DBG_IW_TX       0x00040000
>   #define NES_DBG_SHUTDOWN    0x00080000
>   #define NES_DBG_PAU         0x00100000
> +#define NES_DBG_NLMSG       0x00200000
>   #define NES_DBG_RSVD1       0x10000000
>   #define NES_DBG_RSVD2       0x20000000
>   #define NES_DBG_RSVD3       0x40000000
> @@ -165,6 +166,7 @@ do { \
>   #include "nes_user.h"
>   #include "nes_cm.h"
>   #include "nes_mgt.h"
> +#include "nes_netlink.h"
>   
>   extern int max_mtu;
>   #define max_frame_len (max_mtu+ETH_HLEN)
> diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
> index 6b29249..ec14466 100644
> --- a/drivers/infiniband/hw/nes/nes_cm.c
> +++ b/drivers/infiniband/hw/nes/nes_cm.c
> @@ -59,6 +59,7 @@
>   #include <net/route.h>
>   #include <net/ip_fib.h>
>   #include <net/tcp.h>
> +#include <linux/fcntl.h>
>   
>   #include "nes.h"
>   
> @@ -450,11 +451,11 @@ static void form_cm_frame(struct sk_buff *skb,
>   	iph->ttl = 0x40;
>   	iph->protocol = 0x06;   /* IPPROTO_TCP */
>   
> -	iph->saddr = htonl(cm_node->loc_addr);
> -	iph->daddr = htonl(cm_node->rem_addr);
> +	iph->saddr = htonl(cm_node->mapped_loc_addr);
> +	iph->daddr = htonl(cm_node->mapped_rem_addr);
>   
> -	tcph->source = htons(cm_node->loc_port);
> -	tcph->dest = htons(cm_node->rem_port);
> +	tcph->source = htons(cm_node->mapped_loc_port);
> +	tcph->dest = htons(cm_node->mapped_rem_port);
>   	tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
>   
>   	if (flags & SET_ACK) {
> @@ -1100,8 +1101,11 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
>   			  loc_addr, loc_port,
>   			  cm_node->rem_addr, cm_node->rem_port,
>   			  rem_addr, rem_port);
> -		if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&
> -		    (cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {
> +		if ((cm_node->mapped_loc_addr == loc_addr) &&
> +			(cm_node->mapped_loc_port == loc_port) &&
> +			(cm_node->mapped_rem_addr == rem_addr) &&
> +			(cm_node->mapped_rem_port == rem_port)) {
> +
>   			add_ref_cm_node(cm_node);
>   			spin_unlock_irqrestore(&cm_core->ht_lock, flags);
>   			return cm_node;
> @@ -1118,18 +1122,28 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
>    * find_listener - find a cm node listening on this addr-port pair
>    */
>   static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
> -					     nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)
> +					nes_addr_t dst_addr, u16 dst_port,
> +					enum nes_cm_listener_state listener_state, int local)
>   {
>   	unsigned long flags;
>   	struct nes_cm_listener *listen_node;
> +	nes_addr_t listen_addr;
> +	u16 listen_port;
>   
>   	/* walk list and find cm_node associated with this session ID */
>   	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
>   	list_for_each_entry(listen_node, &cm_core->listen_list.list, list) {
> +		if (local) {
> +			listen_addr = listen_node->loc_addr;
> +			listen_port = listen_node->loc_port;
> +		} else {
> +			listen_addr = listen_node->mapped_loc_addr;
> +			listen_port = listen_node->mapped_loc_port;
> +		}
>   		/* compare node pair, return node handle if a match */
> -		if (((listen_node->loc_addr == dst_addr) ||
> -		     listen_node->loc_addr == 0x00000000) &&
> -		    (listen_node->loc_port == dst_port) &&
> +		if (((listen_addr == dst_addr) ||
> +		     listen_addr == 0x00000000) &&
> +		    (listen_port == dst_port) &&
>   		    (listener_state & listen_node->listener_state)) {
>   			atomic_inc(&listen_node->ref_count);
>   			spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
> @@ -1142,7 +1156,6 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
>   	return NULL;
>   }
>   
> -
>   /**
>    * add_hte_node - add a cm node to the hash table
>    */
> @@ -1263,9 +1276,12 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
>   
>   		spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
>   
> -		if (listener->nesvnic)
> -			nes_manage_apbvt(listener->nesvnic, listener->loc_port,
> +		if (listener->nesvnic) {
> +			nes_manage_apbvt(listener->nesvnic, listener->mapped_loc_port,
>   					 PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
> +			nes_remove_mapping(listener->mapped_loc_addr, listener->mapped_loc_port);
> +			nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n", listener->mapped_loc_port);
> +		}
>   
>   		nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
>   
> @@ -1408,6 +1424,11 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
>   	cm_node->loc_port = cm_info->loc_port;
>   	cm_node->rem_port = cm_info->rem_port;
>   
> +	cm_node->mapped_loc_addr = cm_info->mapped_loc_addr;
> +	cm_node->mapped_rem_addr = cm_info->mapped_rem_addr;
> +	cm_node->mapped_loc_port = cm_info->mapped_loc_port;
> +	cm_node->mapped_rem_port = cm_info->mapped_rem_port;
> +
>   	cm_node->mpa_frame_rev = mpa_version;
>   	cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
>   	cm_node->ird_size = IETF_NO_IRD_ORD;
> @@ -1453,8 +1474,8 @@ 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 */
> -	oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
> -	arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex);
> +	oldarpindex = nes_arp_table(nesdev, cm_node->mapped_rem_addr, NULL, NES_ARP_RESOLVE);
> +	arpindex = nes_addr_resolve_neigh(nesvnic, cm_node->mapped_rem_addr, oldarpindex);
>   	if (arpindex < 0) {
>   		kfree(cm_node);
>   		return NULL;
> @@ -1516,11 +1537,13 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
>   		mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
>   	} else {
>   		if (cm_node->apbvt_set && cm_node->nesvnic) {
> -			nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
> -					 PCI_FUNC(
> -						 cm_node->nesvnic->nesdev->pcidev->devfn),
> +			nes_manage_apbvt(cm_node->nesvnic, cm_node->mapped_loc_port,
> +					 PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
>   					 NES_MANAGE_APBVT_DEL);
>   		}
> +		nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n",
> +					cm_node->mapped_loc_port);
> +		nes_remove_mapping(cm_node->mapped_loc_addr, cm_node->mapped_loc_port);
>   	}
>   
>   	atomic_dec(&cm_core->node_cnt);
> @@ -2192,13 +2215,15 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
>   {
>   	struct nes_cm_listener *listener;
>   	unsigned long flags;
> +	int async = 0;
> +	int iwpm_err = 0;
>   
>   	nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
>   		  cm_info->loc_addr, cm_info->loc_port);
>   
>   	/* cannot have multiple matching listeners */
>   	listener = find_listener(cm_core, htonl(cm_info->loc_addr),
> -				 htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);
> +				 htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE, 1);
>   	if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
>   		/* find automatically incs ref count ??? */
>   		atomic_dec(&listener->ref_count);
> @@ -2207,6 +2232,21 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
>   	}
>   
>   	if (!listener) {
> +		if (nes_iwpm_pid == NES_IWPM_PID_UNDEFINED) {
> +			iwpm_err = nes_register_iwpm_pid(nesvnic->netdev->name,
> +						nesvnic->nesibdev->ibdev.name, async, NULL);
> +			if (iwpm_err) {
> +				nes_iwpm_pid = NES_IWPM_PID_ERROR;
> +				nes_debug(NES_DBG_NLMSG, "Port Mapper register pid failure (err = %d).\n", iwpm_err);
> +			}
> +		}
> +		if (nes_iwpm_pid > 0) { /* valid iwpm pid */
> +			iwpm_err = nes_add_mapping(cm_info);
> +			if (iwpm_err)
> +				nes_debug(NES_DBG_NLMSG, "Port Mapper query failure (err = %d).\n", iwpm_err);
> +		}
> +		print_iwpm_available(nes_iwpm_pid);
> +
>   		/* create a CM listen node (1/2 node to compare incoming traffic to) */
>   		listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
>   		if (!listener) {
> @@ -2216,6 +2256,8 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
>   
>   		listener->loc_addr = htonl(cm_info->loc_addr);
>   		listener->loc_port = htons(cm_info->loc_port);
> +		listener->mapped_loc_addr = htonl(cm_info->mapped_loc_addr);
> +		listener->mapped_loc_port = htons(cm_info->mapped_loc_port);
>   		listener->reused_node = 0;
>   
>   		atomic_set(&listener->ref_count, 1);
> @@ -2277,14 +2319,16 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
>   
>   	if (cm_info->loc_addr == cm_info->rem_addr) {
>   		loopbackremotelistener = find_listener(cm_core,
> -						       ntohl(nesvnic->local_ipaddr), cm_node->rem_port,
> -						       NES_CM_LISTENER_ACTIVE_STATE);
> +						cm_node->mapped_loc_addr, cm_node->mapped_rem_port,
> +						NES_CM_LISTENER_ACTIVE_STATE, 0);
>   		if (loopbackremotelistener == NULL) {
>   			create_event(cm_node, NES_CM_EVENT_ABORTED);
>   		} else {
>   			loopback_cm_info = *cm_info;
>   			loopback_cm_info.loc_port = cm_info->rem_port;
>   			loopback_cm_info.rem_port = cm_info->loc_port;
> +			loopback_cm_info.mapped_loc_port = cm_info->mapped_rem_port;
> +			loopback_cm_info.mapped_rem_port = cm_info->mapped_loc_port;
>   			loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
>   			loopbackremotenode = make_cm_node(cm_core, nesvnic,
>   							  &loopback_cm_info, loopbackremotelistener);
> @@ -2513,6 +2557,12 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
>   	nfo.rem_addr = ntohl(iph->saddr);
>   	nfo.rem_port = ntohs(tcph->source);
>   
> +	/* If port mapper is available these should be mapped address info */
> +	nfo.mapped_loc_addr = ntohl(iph->daddr);
> +	nfo.mapped_loc_port = ntohs(tcph->dest);
> +	nfo.mapped_rem_addr = ntohl(iph->saddr);
> +	nfo.mapped_rem_port = ntohs(tcph->source);
> +
>   	tmp_daddr = cpu_to_be32(iph->daddr);
>   	tmp_saddr = cpu_to_be32(iph->saddr);
>   
> @@ -2521,8 +2571,8 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
>   
>   	do {
>   		cm_node = find_node(cm_core,
> -				    nfo.rem_port, nfo.rem_addr,
> -				    nfo.loc_port, nfo.loc_addr);
> +				    nfo.mapped_rem_port, nfo.mapped_rem_addr,
> +				    nfo.mapped_loc_port, nfo.mapped_loc_addr);
>   
>   		if (!cm_node) {
>   			/* Only type of packet accepted are for */
> @@ -2531,9 +2581,9 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
>   				skb_handled = 0;
>   				break;
>   			}
> -			listener = find_listener(cm_core, nfo.loc_addr,
> -						 nfo.loc_port,
> -						 NES_CM_LISTENER_ACTIVE_STATE);
> +			listener = find_listener(cm_core, nfo.mapped_loc_addr,
> +						 nfo.mapped_loc_port,
> +						 NES_CM_LISTENER_ACTIVE_STATE, 0);
>   			if (!listener) {
>   				nfo.cm_id = NULL;
>   				nfo.conn_type = 0;
> @@ -3133,10 +3183,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   
>   	nes_cm_init_tsa_conn(nesqp, cm_node);
>   
> -	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port));
> -	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port));
> +	nesqp->nesqp_context->tcpPorts[0] =
> +				cpu_to_le16(cm_node->mapped_loc_port);
> +	nesqp->nesqp_context->tcpPorts[1] =
> +				cpu_to_le16(cm_node->mapped_rem_port);
>   
> -	nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr));
> +	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
>   
>   	nesqp->nesqp_context->misc2 |= cpu_to_le32(
>   		(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
> @@ -3160,9 +3212,9 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	memset(&nes_quad, 0, sizeof(nes_quad));
>   	nes_quad.DstIpAdrIndex =
>   		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
> -	nes_quad.SrcIpadr = raddr->sin_addr.s_addr;
> -	nes_quad.TcpPorts[0] = raddr->sin_port;
> -	nes_quad.TcpPorts[1] = laddr->sin_port;
> +	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
> +	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
> +	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
>   
>   	/* Produce hash key */
>   	crc_value = get_crc_value(&nes_quad);
> @@ -3261,6 +3313,9 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	int apbvt_set = 0;
>   	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
>   	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
> +	struct sockaddr_in local_sockaddr, mapped_sockaddr;
> +	int async = 0;
> +	int iwpm_err = 0;
>   
>   	if (cm_id->remote_addr.ss_family != AF_INET)
>   		return -ENOSYS;
> @@ -3304,13 +3359,6 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
>   		  conn_param->private_data_len);
>   
> -	if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
> -		nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
> -				 PCI_FUNC(nesdev->pcidev->devfn),
> -				 NES_MANAGE_APBVT_ADD);
> -		apbvt_set = 1;
> -	}
> -
>   	/* set up the connection params for the node */
>   	cm_info.loc_addr = htonl(laddr->sin_addr.s_addr);
>   	cm_info.loc_port = htons(laddr->sin_port);
> @@ -3319,6 +3367,40 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	cm_info.cm_id = cm_id;
>   	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
>   
> +	/* No port mapper available, go with the specified peer information */
> +	cm_info.mapped_loc_addr = cm_info.loc_addr;
> +	cm_info.mapped_loc_port = cm_info.loc_port;
> +	cm_info.mapped_rem_addr = cm_info.rem_addr;
> +	cm_info.mapped_rem_port = cm_info.rem_port;
> +
> +	if (nes_iwpm_pid == NES_IWPM_PID_UNDEFINED) {
> +		iwpm_err = nes_register_iwpm_pid(nesvnic->netdev->name,
> +					nesvnic->nesibdev->ibdev.name, async, NULL);
> +		if (iwpm_err) {
> +			nes_iwpm_pid = NES_IWPM_PID_ERROR;
> +			nes_debug(NES_DBG_NLMSG, "Port Mapper register pid failure (err = %d).\n", iwpm_err);
> +		}
> +	}
> +	if (nes_iwpm_pid > 0) { /* valid iwpm pid */
> +		iwpm_err = nes_add_and_query_mapping(&cm_info);
> +		if (iwpm_err)
> +			nes_debug(NES_DBG_NLMSG, "Port Mapper query failure (err = %d).\n", iwpm_err);
> +	}
> +	print_iwpm_available(nes_iwpm_pid);
> +
> +	if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
> +		nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
> +			PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
> +		apbvt_set = 1;
> +	}
> +
> +	nes_create_sockaddr(htonl(cm_info.loc_addr),
> +				htons(cm_info.loc_port), &local_sockaddr);
> +	nes_create_sockaddr(htonl(cm_info.mapped_loc_addr),
> +				htons(cm_info.mapped_loc_port), &mapped_sockaddr);
> +	if (nes_create_mapinfo(&local_sockaddr, &mapped_sockaddr))
> +		return -ENOMEM;
> +
>   	cm_id->add_ref(cm_id);
>   
>   	/* create a connect CM node connection */
> @@ -3327,10 +3409,13 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   					  &cm_info);
>   	if (!cm_node) {
>   		if (apbvt_set)
> -			nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
> +			nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
>   					 PCI_FUNC(nesdev->pcidev->devfn),
>   					 NES_MANAGE_APBVT_DEL);
>   
> +		nes_debug(NES_DBG_NLMSG, "Delete mapped_loc_port = %04X\n",
> +				cm_info.mapped_loc_port);
> +		nes_remove_mapping(cm_info.mapped_loc_addr, cm_info.mapped_loc_port);
>   		cm_id->rem_ref(cm_id);
>   		return -ENOMEM;
>   	}
> @@ -3354,6 +3439,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
>   	struct nes_cm_info cm_info;
>   	int err;
>   	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
> +	struct sockaddr_in local_sockaddr, mapped_sockaddr;
>   
>   	nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
>   		  cm_id, ntohs(laddr->sin_port));
> @@ -3378,6 +3464,9 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
>   
>   	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
>   
> +	/* No port mapper available, go with the specified info */
> +	cm_info.mapped_loc_addr = cm_info.loc_addr;
> +	cm_info.mapped_loc_port = cm_info.loc_port;
>   
>   	cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
>   	if (!cm_node) {
> @@ -3389,7 +3478,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
>   	cm_id->provider_data = cm_node;
>   
>   	if (!cm_node->reused_node) {
> -		err = nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
> +		nes_create_sockaddr(cm_info.loc_addr, cm_info.loc_port, &local_sockaddr);
> +		nes_create_sockaddr(cm_info.mapped_loc_addr, cm_info.mapped_loc_port,
> +					&mapped_sockaddr);
> +		if (nes_create_mapinfo(&local_sockaddr, &mapped_sockaddr))
> +			return -ENOMEM;
> +
> +		err = nes_manage_apbvt(nesvnic, cm_node->mapped_loc_port,
>   				       PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
>   				       NES_MANAGE_APBVT_ADD);
>   		if (err) {
> @@ -3514,9 +3609,9 @@ static void cm_event_connected(struct nes_cm_event *event)
>   	nes_cm_init_tsa_conn(nesqp, cm_node);
>   
>   	/* set the QP tsa context */
> -	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port));
> -	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port));
> -	nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr));
> +	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(cm_node->mapped_loc_port);
> +	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(cm_node->mapped_rem_port);
> +	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
>   
>   	nesqp->nesqp_context->misc2 |= cpu_to_le32(
>   			(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
> @@ -3544,9 +3639,9 @@ static void cm_event_connected(struct nes_cm_event *event)
>   
>   	nes_quad.DstIpAdrIndex =
>   		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
> -	nes_quad.SrcIpadr = raddr->sin_addr.s_addr;
> -	nes_quad.TcpPorts[0] = raddr->sin_port;
> -	nes_quad.TcpPorts[1] = laddr->sin_port;
> +	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
> +	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
> +	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
>   
>   	/* Produce hash key */
>   	crc_value = get_crc_value(&nes_quad);
> diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
> index 4646e66..331a573 100644
> --- a/drivers/infiniband/hw/nes/nes_cm.h
> +++ b/drivers/infiniband/hw/nes/nes_cm.h
> @@ -291,8 +291,8 @@ struct nes_cm_listener {
>   	struct list_head           list;
>   	struct nes_cm_core         *cm_core;
>   	u8                         loc_mac[ETH_ALEN];
> -	nes_addr_t                 loc_addr;
> -	u16                        loc_port;
> +	nes_addr_t                 loc_addr, mapped_loc_addr;
> +	u16                        loc_port, mapped_loc_port;
>   	struct iw_cm_id            *cm_id;
>   	enum nes_cm_conn_type      conn_type;
>   	atomic_t                   ref_count;
> @@ -306,7 +306,9 @@ struct nes_cm_listener {
>   /* per connection node and node state information */
>   struct nes_cm_node {
>   	nes_addr_t                loc_addr, rem_addr;
> +	nes_addr_t                mapped_loc_addr, mapped_rem_addr;
>   	u16                       loc_port, rem_port;
> +	u16                       mapped_loc_port, mapped_rem_port;
>   
>   	u8                        loc_mac[ETH_ALEN];
>   	u8                        rem_mac[ETH_ALEN];
> @@ -357,10 +359,8 @@ struct nes_cm_info {
>   		struct net_device *netdev;
>   	};
>   
> -	u16 loc_port;
> -	u16 rem_port;
> -	nes_addr_t loc_addr;
> -	nes_addr_t rem_addr;
> +	u16 loc_port, rem_port, mapped_loc_port, mapped_rem_port;
> +	nes_addr_t loc_addr, rem_addr, mapped_loc_addr, mapped_rem_addr;
>   
>   	enum nes_cm_conn_type  conn_type;
>   	int backlog;
> diff --git a/drivers/infiniband/hw/nes/nes_netlink.c b/drivers/infiniband/hw/nes/nes_netlink.c
> new file mode 100644
> index 0000000..6408089
> --- /dev/null
> +++ b/drivers/infiniband/hw/nes/nes_netlink.c
> @@ -0,0 +1,1223 @@
> +/*
> + * Copyright (c) 2013 Intel Corporation.  All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * 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 pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
> +
> +#include "nes.h"
> +#include "nes_netlink.h"
> +
> +spinlock_t nes_nlmsg_lock;
> +struct list_head nes_nlmsg_request_list;
> +struct list_head nes_mapping_info_list;
> +spinlock_t nes_mapping_lock;
> +atomic_t nes_nlmsg_seq;
> +atomic_t echo_nlmsg_seq;
> +
> +int nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +static const char iwpm_ulib_name[] = "iWarpPortMapperUser";
> +static int iwpm_ulib_version = 3;
> +
> +static struct nes_nlmsg_request *nes_get_nlmsg_request(void);
> +static int nes_send_mapping_info(void);
> +static int nes_send_mapping_count(u32);
> +static int nes_parse_nlmsg(struct netlink_callback *, int, const struct nla_policy *,
> +				struct nlattr *[], const char *);
> +
> +/* nes netlink callbacks */
> +static int nes_register_iwpm_pid_cb(struct sk_buff *, struct netlink_callback *);
> +static int nes_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
> +static int nes_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
> +static int nes_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
> +static int nes_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
> +static int nes_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
> +
> +/*
> + * nes_get_nlmsg_request - Allocate and initialize a netlink request tracking object
> + */
> +static struct nes_nlmsg_request *nes_get_nlmsg_request(void)
> +{
> +	unsigned long flags;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +
> +	nlmsg_request = kzalloc(sizeof(struct nes_nlmsg_request), GFP_ATOMIC);
> +	if (!nlmsg_request) {
> +		pr_err("%s: Unable to allocate a nlmsg_request\n", __func__);
> +		return NULL;
> +	}
> +	spin_lock_irqsave(&nes_nlmsg_lock, flags);
> +	list_add_tail(&nlmsg_request->inprocess_list, &nes_nlmsg_request_list);
> +	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
> +

Same comment as for cxgb4:  I think you can use GFP_KERNEL for this 
alloc, and a mutex for this msg lock.

> +	atomic_set(&nlmsg_request->refcount, 1);
> +	nlmsg_request->nlmsg_seq = atomic_inc_return(&nes_nlmsg_seq);
> +	nlmsg_request->request_done = 0;
> +	nlmsg_request->async = 0;
> +	nlmsg_request->err_code = 0;
> +	return nlmsg_request;
> +}
> +
> +/*
> + * free_nlmsg_request - Free netlink request tracking object
> + */
> +static void free_nlmsg_request(struct nes_nlmsg_request *nlmsg_request)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&nes_nlmsg_lock, flags);
> +	list_del_init(&nlmsg_request->inprocess_list);
> +	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
> +
> +	if (nlmsg_request->async)
> +		del_timer(&nlmsg_request->service_timer);
> +
> +	if (!nlmsg_request->request_done)
> +		nes_debug(NES_DBG_NLMSG, "Freeing incomplete nlmsg request (seq = %u)\n",
> +			nlmsg_request->nlmsg_seq);
> +	kfree(nlmsg_request);
> +}
> +
> +/*
> + * rem_ref_nlmsg_request - Decrement the refcount and free the request
> + *			   object if the refcount is zero
> + */
> +static void rem_ref_nlmsg_request(struct nes_nlmsg_request *nlmsg_request)
> +{
> +	if (atomic_dec_and_test(&nlmsg_request->refcount))
> +		free_nlmsg_request(nlmsg_request);
> +}
> +

Could use krefs here for ref tracking/freeing.

> +/*
> + * nes_nlmsg_req_timer_free - Free expired request object
> + */
> +static void nes_nlmsg_req_timer_free(unsigned long data)
> +{
> +	struct nes_nlmsg_request *nlmsg_request = (struct nes_nlmsg_request *) data;
> +
> +	if (!nlmsg_request->request_done && !nlmsg_request->err_code)
> +		nes_iwpm_pid = NES_IWPM_PID_UNAVAILABLE;
> +
> +	if (nes_iwpm_pid < 0)
> +		nes_debug(NES_DBG_NLMSG, "Port Mapper isn't available (err code = %d)\n",
> +				 nlmsg_request->err_code);
> +	rem_ref_nlmsg_request(nlmsg_request);
> +}
> +
> +/*
> + * nes_mapinfo_timer_send - Send mapping info to the userspace port mapper
> + */
> +static void nes_mapinfo_timer_send(unsigned long data)
> +{
> +	int mapping_num;
> +
> +	nes_nlmsg_req_timer_free(data);
> +	if (nes_iwpm_pid < 0)
> +		return;
> +	mapping_num = nes_send_mapping_info();
> +	if (mapping_num < 0) {
> +		nes_debug(NES_DBG_NLMSG, "Unable to send mapping info\n");
> +		return;
> +	}
> +	nes_debug(NES_DBG_NLMSG, "Sending Mapping count msg (num = %d)\n", mapping_num);
> +	nes_send_mapping_count(mapping_num);
> +}
> +
> +/*
> + * nes_start_nlmsg_req_timer - Start a timer on a netlink request object
> + */
> +static void nes_start_nlmsg_req_timer(struct nes_nlmsg_request *nlmsg_request,
> +					void (*timer_func)(unsigned long), u32 delay)
> +{
> +	init_timer(&nlmsg_request->service_timer);
> +	setup_timer(&nlmsg_request->service_timer, timer_func,
> +			(unsigned long) nlmsg_request);
> +	mod_timer(&nlmsg_request->service_timer, jiffies + delay);
> +}
> +
> +/*
> + * nes_validate_nlmsg_attr - Check for NULL netlink attributes
> + */
> +static int nes_validate_nlmsg_attr(struct nlattr *nltb[], int nla_count)
> +{
> +	int i;
> +	for (i = 1; i < nla_count; i++) {
> +		if (!nltb[i])
> +			return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * nes_create_nlmsg - Allocate skb and form a netlink message
> + */
> +static struct sk_buff *nes_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh)
> +{
> +	struct sk_buff *skb = NULL;
> +
> +	skb = dev_alloc_skb(NLMSG_GOODSIZE);
> +	if (!skb) {
> +		pr_err("%s: Unable to allocate skb\n", __func__);
> +		goto create_nlmsg_exit;
> +	}
> +	if (!(ibnl_put_msg(skb, nlh, 0, 0, RDMA_NL_NES, nl_op, NLM_F_REQUEST))) {
> +		pr_info("%s: Unable to put the nlmsg header\n", __func__);
> +		dev_kfree_skb(skb);
> +		skb = NULL;
> +	}
> +create_nlmsg_exit:
> +	return skb;
> +}
> +
> +/*
> + * nes_parse_nlmsg - Validate and parse the received netlink message
> + */
> +static int nes_parse_nlmsg(struct netlink_callback *cb, int policy_max,
> +			const struct nla_policy *nlmsg_policy,
> +			struct nlattr *nltb[], const char *msg_type)
> +{
> +	int nlh_len = 0;
> +	int ret;
> +	const char *err_str = "";
> +
> +	ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy);
> +	if (ret) {
> +		err_str = "Invalid attribute";
> +		goto parse_nlmsg_error;
> +	}
> +	ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy);
> +	if (ret) {
> +		err_str = "Unable to parse the nlmsg";
> +		goto parse_nlmsg_error;
> +	}
> +	ret = nes_validate_nlmsg_attr(nltb, policy_max);
> +	if (ret) {
> +		err_str = "Invalid NULL attribute";
> +		goto parse_nlmsg_error;
> +	}
> +	return 0;
> +parse_nlmsg_error:
> +	pr_info("%s: %s (msg type %s ret = %d)\n", __func__, err_str, msg_type, ret);
> +	return ret;
> +}
> +
> +/*
> + * wait_complete_nlmsg_req - Block while servicing the netlink request
> + *
> + * Wake up, after the request is completed or expired
> + */
> +static int wait_complete_nlmsg_req(struct nes_nlmsg_request *nlmsg_request, int iwpm_pid)
> +{
> +	int ret;
> +	init_waitqueue_head(&nlmsg_request->waitq);
> +
> +	ret = wait_event_timeout(nlmsg_request->waitq, (nlmsg_request->request_done != 0),
> +					NES_IWPM_NL_TIMEOUT);
> +	if (!ret) {
> +		nes_iwpm_pid = iwpm_pid;
> +		pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
> +			__func__, (NES_IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
> +	} else
> +		ret = nlmsg_request->err_code;
> +
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * nes_find_nlmsg_request - Find a request object using its sequence number
> + */
> +static struct nes_nlmsg_request *nes_find_nlmsg_request(__u32 echo_seq)
> +{
> +	struct nes_nlmsg_request *nlmsg_request;
> +	struct nes_nlmsg_request *found_request = NULL;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&nes_nlmsg_lock, flags);
> +	list_for_each_entry(nlmsg_request, &nes_nlmsg_request_list, inprocess_list) {
> +		nes_debug(NES_DBG_NLMSG, "Looking at a request with seq = %u\n",
> +				nlmsg_request->nlmsg_seq);
> +		if (nlmsg_request->nlmsg_seq == echo_seq) {
> +			found_request = nlmsg_request;
> +			atomic_inc(&nlmsg_request->refcount);
> +			break;
> +		}
> +	}
> +	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
> +	return found_request;
> +}
> +
> +/*
> + * nes_create_sockaddr - Record ip addr and tcp port in a sockaddr struct
> + */
> +void nes_create_sockaddr(__be32 s_addr, __be16 s_port, struct sockaddr_in *cm_sockaddr)
> +{
> +	cm_sockaddr->sin_family = AF_INET;
> +	memcpy(&cm_sockaddr->sin_addr.s_addr, &s_addr, sizeof(__be32));
> +	cm_sockaddr->sin_port = s_port;
> +}
> +
> +/*
> + * nes_create_mapinfo - Create mapping info record
> + */
> +int nes_create_mapinfo(struct sockaddr_in *local_sockaddr,
> +				struct sockaddr_in *mapped_sockaddr)
> +{
> +	struct nes_mapping_info *map_info;
> +	unsigned long flags;
> +
> +	map_info = kzalloc(sizeof(struct nes_mapping_info), GFP_KERNEL);
> +	if (!map_info) {
> +		pr_err("%s: Unable to allocate a mapping info\n", __func__);
> +		return -ENOMEM;
> +	}
> +	memcpy(&map_info->local_sockaddr, local_sockaddr, sizeof(struct sockaddr_in));
> +	memcpy(&map_info->mapped_sockaddr, mapped_sockaddr, sizeof(struct sockaddr_in));
> +
> +	spin_lock_irqsave(&nes_mapping_lock, flags);
> +	list_add_tail(&map_info->mapping_list, &nes_mapping_info_list);
> +	spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +	return 0;
> +}
> +
> +/*
> + * nes_remove_mapinfo - Remove mapping info record
> + */
> +int nes_remove_mapinfo(struct sockaddr_in *mapped_sockaddr)
> +{
> +	struct nes_mapping_info *map_info = NULL;
> +	unsigned long flags;
> +	int ret = -EINVAL;
> +
> +	nes_debug(NES_DBG_NLMSG, "Remove mapped addr %pI4 [0x%04X]\n",
> +			&mapped_sockaddr->sin_addr.s_addr, mapped_sockaddr->sin_port);
> +
> +	spin_lock_irqsave(&nes_mapping_lock, flags);
> +	list_for_each_entry(map_info, &nes_mapping_info_list, mapping_list) {
> +		if (!memcmp(&map_info->mapped_sockaddr.sin_addr,
> +			&mapped_sockaddr->sin_addr, sizeof(__be32)) &&
> +			map_info->mapped_sockaddr.sin_port == mapped_sockaddr->sin_port) {
> +
> +			list_del_init(&map_info->mapping_list);
> +			kfree(map_info);
> +			ret = 0;
> +			break;
> +		}
> +	}
> +	spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +	return ret;
> +}
> +
> +/*
> + * nes_destroy_mapinfo_list - Delete all mapping info records
> + */
> +void nes_destroy_mapinfo_list(void)
> +{
> +	struct nes_mapping_info *map_info, *map_info_tmp;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&nes_mapping_lock, flags);
> +	list_for_each_entry_safe(map_info, map_info_tmp,
> +					&nes_mapping_info_list, mapping_list) {
> +
> +		nes_debug(NES_DBG_NLMSG, "Delete mapped addr %pI4 [0x%04X]\n",
> +			&map_info->mapped_sockaddr.sin_addr.s_addr,
> +			map_info->mapped_sockaddr.sin_port);
> +
> +		list_del(&map_info->mapping_list);
> +		kfree(map_info);
> +	}
> +	spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +}
> +
> +/*
> + * print_iwpm_available - Print a message if the port mapper isn't available
> + */
> +void print_iwpm_available(int iwpm_pid)
> +{
> +	static int one_time;
> +
> +	if (iwpm_pid < 0 && !one_time) {
> +		pr_info("iWarp Port Mapper (pid = %d) is not available.\n", nes_iwpm_pid);
> +		one_time++;
> +	}
> +	if (iwpm_pid > 0)
> +		one_time = 0;
> +}
> +
> +/*
> + * nes_register_iwpm_pid - Send a netlink query for the iwarp port mapper pid
> + *				to the userspace
> + * nlmsg attributes:
> + *	[IWPM_NLA_REG_PID_SEQ]
> + *	[IWPM_NLA_REG_IF_NAME]
> + *	[IWPM_NLA_REG_IBDEV_NAME]
> + *	[IWPM_NLA_REG_ULIB_NAME]
> + */
> +int nes_register_iwpm_pid(char *netdev_name, char *dev_name, int async,
> +				void (*req_timer_func)(unsigned long))
> +{
> +	struct sk_buff *skb = NULL;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = nes_create_nlmsg(RDMA_NL_IWPM_REG_PID, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto pid_query_error;
> +	}
> +	nlmsg_request = nes_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto pid_query_error;
> +	}
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +
> +	/* fill in the pid request message */
> +	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
> +	err_str = "Unable to put attribute of the nlmsg";
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
> +	if (ret)
> +		goto pid_query_error;
> +	ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE,
> +				netdev_name, IWPM_NLA_REG_IF_NAME);
> +	if (ret)
> +		goto pid_query_error;
> +	ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE,
> +				dev_name, IWPM_NLA_REG_IBDEV_NAME);
> +	if (ret)
> +		goto pid_query_error;
> +	ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE,
> +				(char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME);
> +	if (ret)
> +		goto pid_query_error;
> +
> +	nes_debug(NES_DBG_NLMSG, "Multicasting a nlmsg (ibdev = %s ifname = %s iwpm = %s msglen = %d)\n",
> +			dev_name, netdev_name, iwpm_ulib_name, nlh->nlmsg_len);
> +
> +	ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
> +	if (ret) {
> +		/* skb is already freed in the netlink send-op handling */
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +		goto pid_query_error_exit;
> +	}
> +	nlmsg_request->async = async;
> +	if (async)
> +		nes_start_nlmsg_req_timer(nlmsg_request, req_timer_func, NES_IWPM_NL_TIMEOUT);
> +	else
> +		ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNAVAILABLE);
> +	return ret;
> +pid_query_error:
> +	pr_info("%s: %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +pid_query_error_exit:
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * nes_add_mapping - Send a netlink add mapping message
> + *
> + * Send a message to the userspace port mapper to get the
> + * mapping info for a listener local ip/tcp address
> + *
> + * nlmsg attributes:
> + *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
> + *	[IWPM_NLA_MANAGE_ADDR]
> + */
> +int nes_add_mapping(struct nes_cm_info *cm_info)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in local_sockaddr;
> +	__be32 local_addr = cm_info->loc_addr;
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = nes_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto add_mapping_error;
> +	}
> +	nlmsg_request = nes_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto add_mapping_error;
> +	}
> +	local_sockaddr.sin_family = AF_INET;
> +	memcpy(&local_sockaddr.sin_addr.s_addr, &local_addr, sizeof(__be32));
> +	local_sockaddr.sin_port = cm_info->loc_port;
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +
> +	/* fill in the add mapping message */
> +	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
> +	err_str = "Unable to put attribute of the nlmsg";
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
> +				IWPM_NLA_MANAGE_MAPPING_SEQ);
> +	if (ret)
> +		goto add_mapping_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&local_sockaddr, IWPM_NLA_MANAGE_ADDR);
> +	if (ret)
> +		goto add_mapping_error;
> +
> +	nlmsg_request->request_buffer = cm_info;
> +	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (local addr %pI4 [0x%04X])\n",
> +		&local_sockaddr.sin_addr.s_addr, local_sockaddr.sin_port);
> +
> +	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
> +	if (ret) {
> +		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +		/* skb is already freed in the netlink send-op handling */
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +		goto add_mapping_error_exit;
> +	}
> +	ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNDEFINED);
> +	return ret;
> +add_mapping_error:
> +	pr_info("%s: %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +add_mapping_error_exit:
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * nes_add_and_query_mapping - Send a netlink query mapping message
> + *
> + * Send both a netlink add mapping message to get
> + * the connecting side local ip/tcp address mapping info and
> + * a query for the accepting side mapped (remote)
> + * ip/tcp address to the userspace port mapper
> +
> + * nlmsg attributes:
> + *	[IWPM_NLA_QUERY_MAPPING_SEQ]
> + *	[IWPM_NLA_QUERY_LOCAL_ADDR]
> + *	[IWPM_NLA_QUERY_REMOTE_ADDR]
> + */
> +int nes_add_and_query_mapping(struct nes_cm_info *cm_info)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in local_sockaddr;
> +	struct sockaddr_in remote_sockaddr;
> +	__be32 local_addr = htonl(cm_info->loc_addr);
> +	__be32 remote_addr = htonl(cm_info->rem_addr);
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = nes_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto query_mapping_error;
> +	}
> +	nlmsg_request = nes_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto query_mapping_error;
> +	}
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +	local_sockaddr.sin_family = AF_INET;
> +	memcpy(&local_sockaddr.sin_addr.s_addr, &local_addr, sizeof(__be32));
> +	local_sockaddr.sin_port = htons(cm_info->loc_port);
> +
> +	remote_sockaddr.sin_family = AF_INET;
> +	memcpy(&remote_sockaddr.sin_addr.s_addr, &remote_addr, sizeof(__be32));
> +	remote_sockaddr.sin_port = htons(cm_info->rem_port);
> +
> +	/* fill in the query message */
> +	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
> +	err_str = "Unable to put attribute of the nlmsg";
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
> +				IWPM_NLA_QUERY_MAPPING_SEQ);
> +	if (ret)
> +		goto query_mapping_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&local_sockaddr, IWPM_NLA_QUERY_LOCAL_ADDR);
> +	if (ret)
> +		goto query_mapping_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&remote_sockaddr, IWPM_NLA_QUERY_REMOTE_ADDR);
> +	if (ret)
> +		goto query_mapping_error;
> +
> +	nlmsg_request->request_buffer = cm_info;
> +	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (laddr %pI4 [0x%04X], raddr %pI4 [0x%04X])\n",
> +		&local_sockaddr.sin_addr.s_addr, local_sockaddr.sin_port,
> +		&remote_sockaddr.sin_addr.s_addr, remote_sockaddr.sin_port);
> +
> +	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
> +	if (ret) {
> +		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +		/* skb is already freed in the netlink send-op handling */
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +		goto query_mapping_error_exit;
> +	}
> +	ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNDEFINED);
> +	return ret;
> +query_mapping_error:
> +	pr_info("%s: %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +query_mapping_error_exit:
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * nes_remove_mapping - Send a netlink remove mapping message
> + *
> + * nlmsg attributes:
> + *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
> + *	[IWPM_NLA_MANAGE_ADDR]
> + */
> +int nes_remove_mapping(nes_addr_t mapped_local_addr, u16 mapped_local_port)
> +{
> +	struct sk_buff *skb;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in mapped_sockaddr;
> +	__be32 mapped_addr = htonl(mapped_local_addr);
> +	const char *err_str = "";
> +	int ret;
> +
> +	mapped_sockaddr.sin_family = AF_INET;
> +	memcpy(&mapped_sockaddr.sin_addr.s_addr, &mapped_addr, sizeof(__be32));
> +	mapped_sockaddr.sin_port = htons(mapped_local_port);
> +
> +	if (nes_remove_mapinfo(&mapped_sockaddr)) {
> +		pr_info("%s: Fail to remove mapinfo (port = 0x%04X)\n",
> +				__func__, mapped_local_port);
> +		return -EINVAL;
> +	}
> +	/* the routine is always called when terminating a connection,
> +	* if the userspace port mapper isn't available, can't send a msg */
> +	if (nes_iwpm_pid < 0)
> +		return 0;
> +
> +	skb = nes_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, nlh_next);
> +	if (!skb) {
> +		ret = -ENOMEM;
> +		err_str = "Unable to create a nlmsg";
> +		goto remove_mapping_error;
> +	}
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +
> +	nlh->nlmsg_seq = atomic_inc_return(&nes_nlmsg_seq);
> +	err_str = "Unable to put attribute of the nlmsg";
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
> +				IWPM_NLA_MANAGE_MAPPING_SEQ);
> +	if (ret)
> +		goto remove_mapping_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&mapped_sockaddr, IWPM_NLA_MANAGE_ADDR);
> +	if (ret)
> +		goto remove_mapping_error;
> +
> +	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (mapped laddr %pI4 [0x%04X])\n",
> +		&mapped_sockaddr.sin_addr.s_addr, mapped_sockaddr.sin_port);
> +
> +	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
> +	if (ret) {
> +		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +		/* skb is already freed in the netlink send-op handling */
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +	}
> +	return ret;
> +remove_mapping_error:
> +	pr_info("%s: %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	return ret;
> +}
> +
> +/* registered nes netlink callbacks */
> +struct ibnl_client_cbs nes_nl_cb_table[] = {
> +	[RDMA_NL_IWPM_REG_PID] = {.dump = nes_register_iwpm_pid_cb},
> +	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = nes_add_mapping_cb},
> +	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = nes_add_and_query_mapping_cb},
> +	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = nes_mapping_error_cb},
> +	[RDMA_NL_IWPM_MAP_INFO] = {.dump = nes_mapping_info_cb},
> +	[RDMA_NL_IWPM_MAP_INFO_NUM] = {.dump = nes_ack_mapping_info_cb}
> +};
> +
> +/* netlink attribute policy for the received response to nes register */
> +static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
> +	[IWPM_NLA_RREG_PID_SEQ]     = { .type = NLA_U32 },
> +	[IWPM_NLA_RREG_IBDEV_NAME]  = { .type = NLA_STRING,
> +					.len = IWPM_DEVNAME_SIZE - 1 },
> +	[IWPM_NLA_RREG_ULIB_NAME]   = { .type = NLA_STRING,
> +					.len = IWPM_ULIBNAME_SIZE - 1 },
> +	[IWPM_NLA_RREG_ULIB_VER]    = { .type = NLA_U16 },
> +	[IWPM_NLA_RREG_PID_ERR]     = { .type = NLA_U16 }
> +};
> +
> +/*
> + * nes_register_iwpm_pid_cb - Process response to register_iwpm_pid
> + *
> + * The port mapper pid (part of the response message) is used
> + * in the future communication with the port mapper
> + */
> +static int nes_register_iwpm_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX];
> +	char *dev_name, *iwpm_name;
> +	u32 msg_seq;
> +	u16 iwpm_version;
> +	const char *msg_type = "Register Pid response";
> +
> +	nes_iwpm_pid = NES_IWPM_PID_ERROR;
> +
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX,
> +				resp_reg_policy, nltb, msg_type))
> +		return -EINVAL;
> +
> +	msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]);
> +	nlmsg_request = nes_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_info("%s: Could not find a matching request (seq = %u)\n",
> +				 __func__, msg_seq);
> +		return -EINVAL;
> +	}
> +	dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]);
> +	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]);
> +	iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]);
> +
> +	/* check device name, ulib name and version */
> +	if (strcmp(nes_ibdev, dev_name) || strcmp(iwpm_ulib_name, iwpm_name) ||
> +			iwpm_version != iwpm_ulib_version) {
> +
> +		pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n",
> +				__func__, dev_name, iwpm_name, iwpm_version);
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto register_pid_response_exit;
> +	}
> +	nes_debug(NES_DBG_NLMSG, "Received info (dev = %s iwpm = %s version = %d)\n",
> +				dev_name, iwpm_name, iwpm_version);
> +
> +	nes_iwpm_pid = cb->nlh->nlmsg_pid;
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	pr_info("%s: iWarp Port Mapper (pid = %d) is successfully registered.\n",
> +			__func__, nes_iwpm_pid);
> +register_pid_response_exit:
> +	nlmsg_request->request_done = 1;
> +	rem_ref_nlmsg_request(nlmsg_request); /* always for found nlmsg_request */
> +	barrier();
> +	if (!nlmsg_request->async)
> +		wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +/* netlink attribute policy for the received response to nes add mapping */
> +static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
> +	[IWPM_NLA_MANAGE_MAPPING_SEQ]     = { .type = NLA_U32 },
> +	[IWPM_NLA_MANAGE_ADDR]            = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_RMANAGE_MAPPING_ERR]	  = { .type = NLA_U16 }
> +};
> +
> +/*
> + * nes_add_mapping_cb - Callback routine when response to add_mapping
> + *			is received from the userspace port mapper
> + *
> + * The response message contains the mapping info for the requested
> + * listener local ip/tcp address
> + */
> +static int nes_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nes_cm_info *cm_info;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
> +	u32 msg_seq;
> +	struct sockaddr_in *local_sockaddr, *mapped_sockaddr;
> +	__be32 loc_addr, mapped_addr;
> +	const char *msg_type;
> +
> +	msg_type = "Add Mapping response";
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX,
> +				resp_add_policy, nltb, msg_type))
> +		return -EINVAL;
> +
> +	msg_seq = nla_get_u32(nltb[IWPM_NLA_MANAGE_MAPPING_SEQ]);
> +	nlmsg_request = nes_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_info("%s: Could not find a matching request (seq = %u)\n",
> +				 __func__, msg_seq);
> +		return -EINVAL;
> +	}
> +	cm_info = nlmsg_request->request_buffer;
> +	local_sockaddr = (struct sockaddr_in *)nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
> +	mapped_sockaddr = (struct sockaddr_in *)nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
> +
> +	loc_addr = *(__be32 *)&local_sockaddr->sin_addr.s_addr;
> +	if (cm_info->loc_addr != loc_addr ||
> +		cm_info->loc_port != local_sockaddr->sin_port) {
> +
> +		pr_info("%s: Invalid ip/tcp address (Expected %pI4(%04X) Received: %pI4(%04X)\n",
> +			__func__, (char *)&cm_info->loc_addr, cm_info->loc_port,
> +			(char *)&loc_addr, local_sockaddr->sin_port);
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto add_mapping_response_exit;
> +	}
> +	if (mapped_sockaddr->sin_family != AF_INET) {
> +		pr_info("%s: Invalid sockaddr family = %04X\n",
> +				__func__, mapped_sockaddr->sin_family);
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto add_mapping_response_exit;
> +	}
> +
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	mapped_addr = *(__be32 *)&mapped_sockaddr->sin_addr.s_addr;
> +	cm_info->mapped_loc_addr = mapped_addr;
> +	cm_info->mapped_loc_port = mapped_sockaddr->sin_port;
> +add_mapping_response_exit:
> +	nes_debug(NES_DBG_NLMSG, "Received new mapped laddr %pI4 [0x%04X]\n",
> +		&mapped_sockaddr->sin_addr.s_addr, mapped_sockaddr->sin_port);
> +	nlmsg_request->request_done = 1;
> +	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
> +	barrier();
> +	wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +/* netlink attribute policy for the add_and_query_mapping response */
> +static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
> +	[IWPM_NLA_QUERY_MAPPING_SEQ]      = { .type = NLA_U32 },
> +	[IWPM_NLA_QUERY_LOCAL_ADDR]       = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_QUERY_REMOTE_ADDR]      = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { .len = sizeof(struct sockaddr_storage) },
> +	[IWPM_NLA_RQUERY_MAPPING_ERR]	  = { .type = NLA_U16 }
> +};
> +
> +/*
> + * nes_add_and_query_mapping_cb - Process response to add_and_query_mapping
> + *
> + * The response message contains mapping info for the requested
> + * connecting side local ip/tcp address and accepting side (remote) ip/tcp address
> + */
> +static int nes_add_and_query_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nes_cm_info *cm_info;
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
> +	u32 msg_seq;
> +	struct sockaddr_in *local_sockaddr, *remote_sockaddr;
> +	struct sockaddr_in *mapped_loc_sockaddr, *mapped_rem_sockaddr;
> +	__be32 loc_addr, mapped_loc_addr, rem_addr, mapped_rem_addr;
> +	const char *msg_type;
> +	u16 err_code;
> +
> +	msg_type = "Query Mapping response";
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
> +				resp_query_policy, nltb, msg_type))
> +		return -EINVAL;
> +	msg_seq = nla_get_u32(nltb[IWPM_NLA_QUERY_MAPPING_SEQ]);
> +	nlmsg_request = nes_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_info("%s: Could not find a matching request (seq = %u)\n",
> +				 __func__, msg_seq);
> +			return -EINVAL;
> +	}
> +	cm_info = nlmsg_request->request_buffer;
> +	local_sockaddr =
> +		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
> +	remote_sockaddr =
> +		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
> +	mapped_loc_sockaddr =
> +		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
> +	mapped_rem_sockaddr =
> +		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
> +
> +	err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
> +	if (err_code == IWPM_REMOTE_QUERY_REJECT) {
> +		pr_info("%s: Received a Reject nlmsg (pid = %u, echo seq = %u)\n",
> +			__func__, cb->nlh->nlmsg_pid, msg_seq);
> +		nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
> +	}
> +	loc_addr = *(__be32 *)&local_sockaddr->sin_addr.s_addr;
> +	rem_addr = *(__be32 *)&remote_sockaddr->sin_addr.s_addr;
> +	if (cm_info->loc_addr != ntohl(loc_addr) ||
> +			cm_info->loc_port != ntohs(local_sockaddr->sin_port) ||
> +			cm_info->rem_addr != ntohl(rem_addr) ||
> +			cm_info->rem_port != ntohs(remote_sockaddr->sin_port)) {
> +
> +		pr_info("%s: Expected laddr %pI4 [%04X] Received laddr %pI4 [%04X] "
> +			"Expected raddr %pI4 [%04X] Received raddr %pI4 [%04X]\n", __func__,
> +			(char *)&cm_info->loc_addr, cm_info->loc_port,
> +			(char *)&loc_addr, ntohs(local_sockaddr->sin_port),
> +			(char *)&cm_info->rem_addr, cm_info->rem_port,
> +			(char *)&rem_addr, ntohs(remote_sockaddr->sin_port));
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto query_mapping_response_exit;
> +	}
> +	if (mapped_loc_sockaddr->sin_family != AF_INET ||
> +			mapped_rem_sockaddr->sin_family != AF_INET) {
> +		pr_info("%s: Invalid sockaddr family\n", __func__);
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto query_mapping_response_exit;
> +	}
> +
> +	mapped_loc_addr = *(__be32 *)&mapped_loc_sockaddr->sin_addr.s_addr;
> +	mapped_rem_addr = *(__be32 *)&mapped_rem_sockaddr->sin_addr.s_addr;
> +
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	cm_info->mapped_loc_addr = ntohl(mapped_loc_addr);
> +	cm_info->mapped_loc_port = ntohs(mapped_loc_sockaddr->sin_port);
> +	cm_info->mapped_rem_addr = ntohl(mapped_rem_addr);
> +	cm_info->mapped_rem_port = ntohs(mapped_rem_sockaddr->sin_port);
> +
> +query_mapping_response_exit:
> +	nes_debug(NES_DBG_NLMSG, "Received mapped laddr %pI4 [0x%04X] raddr %pI4 [0x%04X]\n",
> +		&mapped_loc_sockaddr->sin_addr.s_addr, mapped_loc_sockaddr->sin_port,
> +		&mapped_rem_sockaddr->sin_addr.s_addr, mapped_rem_sockaddr->sin_port);
> +	nlmsg_request->request_done = 1;
> +	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
> +	barrier();
> +	wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +/* netlink attribute policy for the received request for mapping info */
> +static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
> +	[IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
> +					.len = IWPM_ULIBNAME_SIZE - 1 },
> +	[IWPM_NLA_MAPINFO_ULIB_VER]  = { .type = NLA_U16 }
> +};
> +
> +/*
> + * nes_mapping_info_cb - Callback routine when message from the port mapper
> + *				is received, to notify that the port mapper is available
> + *				and request the nes records of mapping info
> + */
> +static int nes_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
> +	char *iwpm_name;
> +	u16 iwpm_version;
> +	const char *msg_type = "Mapping Info response";
> +	void (*req_timer_func)(unsigned long) = NULL;
> +	int async = 1;
> +
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX,
> +				resp_mapinfo_policy, nltb, msg_type))
> +		return -EINVAL;
> +
> +	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]);
> +	iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
> +	if (strcmp(iwpm_ulib_name, iwpm_name) || iwpm_version != iwpm_ulib_version) {
> +		pr_info("%s: Invalid iWarpPortMapper info (name = %s version = %d)\n",
> +				__func__, iwpm_name, iwpm_version);
> +		return -EINVAL;
> +	}
> +	if (list_empty(&nes_mapping_info_list))
> +		req_timer_func = &nes_nlmsg_req_timer_free;
> +	else
> +		req_timer_func = &nes_mapinfo_timer_send;
> +
> +	nes_register_iwpm_pid(nes_ifname, nes_ibdev, async, req_timer_func);
> +	return 0;
> +}
> +
> +/*
> + * nes_send_mapping_count - Send a netlink message with the number of mapping
> + *				info records to the userspace port mapper
> + */
> +static int nes_send_mapping_count(u32 mapping_num)
> +{
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct sk_buff *skb = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	const char *err_str = "";
> +	int ret = -EINVAL;
> +
> +	skb = nes_create_nlmsg(RDMA_NL_IWPM_MAP_INFO_NUM, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto map_count_error;
> +	}
> +	nlmsg_request = nes_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto map_count_error;
> +	}
> +
> +	/* fill in the pid request message */
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
> +	err_str = "Unable to put attribute of map count nlmsg";
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
> +	if (ret)
> +		goto map_count_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32),
> +				&mapping_num, IWPM_NLA_MAPINFO_NUMBER);
> +	if (ret)
> +		goto map_count_error;
> +
> +	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
> +	if (ret) {
> +		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +		goto map_count_error_exit;
> +	}
> +	nlmsg_request->mapcount = mapping_num;
> +	nlmsg_request->async = 1;
> +	nes_start_nlmsg_req_timer(nlmsg_request, nes_nlmsg_req_timer_free,
> +					NES_IWPM_NL_TIMEOUT);
> +	return 0;
> +map_count_error:
> +	pr_info("%s: %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +map_count_error_exit:
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * nes_send_nlmsg_done - Send a mapping info message
> + *
> + * Send to the port mapper an skb containing multi netlink messages,
> + * after appending a NLMSG_DONE message to the skb
> + */
> +static int nes_send_nlmsg_done(struct sk_buff *skb)
> +{
> +	struct nlmsghdr *nlh = NULL;
> +	int ret;
> +	if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_NES,
> +				RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
> +		pr_info("%s: Unable to put NLMSG_DONE\n", __func__);
> +		return -ENOMEM;
> +	}
> +	nlh->nlmsg_type = NLMSG_DONE;
> +	ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, nes_iwpm_pid);
> +	if (ret) {
> +		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
> +		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
> +	}
> +	return ret;
> +}
> +
> +/*
> + * nes_send_mapping_info - Send mapping info records to the iwarp port mapper
> + *
> + * Mapping info message is used for synchronization,
> + * after the port mapper is restarted and doesn't have any mapping info records
> + */
> +static int nes_send_mapping_info(void)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct nes_mapping_info *map_info;
> +	struct nlmsghdr *nlh;
> +	unsigned long flags;
> +	int mapping_num = 0;
> +	int nlmsg_bytes = 0;
> +	int skb_num = 0;
> +	const char *err_str = "";
> +	int ret;
> +
> +	skb = dev_alloc_skb(NLMSG_GOODSIZE);
> +	if (!skb) {
> +		ret = -ENOMEM;
> +		err_str = "Unable to allocate skb";
> +		goto send_mapping_info_exit;
> +	}
> +	skb_num++;
> +	spin_lock_irqsave(&nes_mapping_lock, flags);
> +	list_for_each_entry(map_info, &nes_mapping_info_list, mapping_list) {
> +		nlh = NULL;
> +		if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_NES,
> +				RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
> +			ret = -ENOMEM;
> +			err_str = "Unable to put the nlmsg header";
> +			spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +			goto send_mapping_info_exit;
> +		}
> +		err_str = "Unable to put attribute of the nlmsg";
> +		ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&map_info->local_sockaddr, IWPM_NLA_MAPINFO_LOCAL_ADDR);
> +		if (ret) {
> +			spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +			goto send_mapping_info_exit;
> +		}
> +		ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +				&map_info->mapped_sockaddr, IWPM_NLA_MAPINFO_MAPPED_ADDR);
> +		if (ret) {
> +			spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +			goto send_mapping_info_exit;
> +		}
> +		mapping_num++;
> +		nlmsg_bytes += nlh->nlmsg_len;
> +
> +		/* check if all mappings can fit in one skb */
> +		/* and leave room for NLMSG_DONE */
> +		if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len*2) {
> +			nlmsg_bytes = 0;
> +			skb_num++;
> +			nes_debug(NES_DBG_NLMSG, "Allocating skb #%d (mappings = %d nlmsg len = %d)\n",
> +					skb_num, mapping_num, nlh->nlmsg_len);
> +			spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +			/* send the skb */
> +			ret = nes_send_nlmsg_done(skb);
> +			skb = NULL;
> +			if (ret) {
> +				err_str = "Unable to send map info";
> +				goto send_mapping_info_exit;
> +			}
> +			if (skb_num == NES_MAP_INFO_SKB_COUNT) {
> +				ret = -ENOMEM;
> +				err_str = "Insufficient skbs for map info";
> +				goto send_mapping_info_exit;
> +			}
> +			skb = dev_alloc_skb(NLMSG_GOODSIZE);
> +			if (!skb) {
> +				ret = -ENOMEM;
> +				err_str = "Unable to allocate skb";
> +				goto send_mapping_info_exit;
> +			}
> +			spin_lock_irqsave(&nes_mapping_lock, flags);
> +		}
> +	}
> +	spin_unlock_irqrestore(&nes_mapping_lock, flags);
> +	if (skb)
> +		nes_send_nlmsg_done(skb);
> +	return mapping_num;
> +send_mapping_info_exit:
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (ret > 0)
> +		ret = -ret;
> +	pr_info("%s: %s (ret = %d)\n", __func__, err_str, ret);
> +	return ret;
> +}
> +
> +/* netlink attribute policy for the received ack of mapping info */
> +static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_COUNT_MAX] = {
> +	[IWPM_NLA_MAPINFO_SEQ]    = { .type = NLA_U32 },
> +	[IWPM_NLA_MAPINFO_NUMBER] = { .type = NLA_U32 }
> +};
> +
> +/*
> + * nes_ack_mapping_info_cb - Callback routine when acknowledgement is received
> + *			     from the userspace port mapper
> + *
> + * The received netlink message contains the number of mappings the port mapper
> + * has processed
> + */
> +static int nes_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_MAPINFO_COUNT_MAX];
> +	u32 msg_seq, mapping_num;
> +	const char *msg_type = "Mapping Info Ack";
> +
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_MAPINFO_COUNT_MAX,
> +				ack_mapinfo_policy, nltb, msg_type))
> +		return -EINVAL;
> +	msg_seq = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEQ]);
> +	nlmsg_request = nes_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_info("%s: Could not find matching request (seq = %u)\n",
> +				 __func__, msg_seq);
> +		return -EINVAL;
> +	}
> +	mapping_num = nla_get_u32(nltb[IWPM_NLA_MAPINFO_NUMBER]);
> +	if (nlmsg_request->mapcount != mapping_num)
> +		pr_info("%s: Invalid mapinfo count (sent = %u ack-ed = %u)\n",
> +				__func__, nlmsg_request->mapcount, mapping_num);
> +
> +	nes_debug(NES_DBG_NLMSG, "Received ack for mapping count = %u\n", mapping_num);
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	nlmsg_request->request_done = 1;
> +	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
> +	return 0;
> +}
> +
> +/* netlink attribute policy for the received port mapper error message */
> +static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
> +	[IWPM_NLA_ERR_SEQ]        = { .type = NLA_U32 },
> +	[IWPM_NLA_ERR_CODE]       = { .type = NLA_U16 },
> +};
> +
> +/*
> + * nes_mapping_error_cb - Callback routine when error message is received
> + *			  from the port mapper
> + */
> +static int nes_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct nes_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_ERR_MAX];
> +	u32 msg_seq;
> +	u16 err_code;
> +	const char *msg_type = "Mapping Error Msg";
> +
> +	if (nes_parse_nlmsg(cb, IWPM_NLA_ERR_MAX,
> +				map_error_policy, nltb, msg_type))
> +		return -EINVAL;
> +
> +	msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]);
> +	err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]);
> +	pr_info("%s: Received msg seq = %u err code = %u\n", __func__, msg_seq, err_code);
> +	/* look for nlmsg_request */
> +	nlmsg_request = nes_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		/* not all errors have associated requests */
> +		nes_debug(NES_DBG_NLMSG, "Could not find matching request (seq = %u)\n", msg_seq);
> +		return -EINVAL;
> +	}
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	nlmsg_request->err_code = err_code;
> +	nlmsg_request->request_done = 1;
> +	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
> +	barrier();
> +	if (!nlmsg_request->async)
> +		wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> diff --git a/drivers/infiniband/hw/nes/nes_netlink.h b/drivers/infiniband/hw/nes/nes_netlink.h
> new file mode 100644
> index 0000000..8fde524
> --- /dev/null
> +++ b/drivers/infiniband/hw/nes/nes_netlink.h
> @@ -0,0 +1,108 @@
> +/*
> +* Copyright (c) 2013 Intel Corporation. All rights reserved.
> +*
> +* This software is available to you under a choice of one of two
> +* licenses.  You may choose to be licensed under the terms of the GNU
> +* 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.
> +*/
> +
> +#ifndef __NES_NETLINK_H
> +#define __NES_NETLINK_H
> +
> +#include <rdma/rdma_netlink.h>
> +#include <linux/errno.h>
> +
> +#define NES_IWPM_PID_UNDEFINED    -1
> +#define NES_IWPM_PID_UNAVAILABLE  -2
> +#define NES_IWPM_PID_ERROR        -3
> +
> +#define NES_IWPM_NL_TIMEOUT     (10*HZ)
> +#define NES_MAP_INFO_SKB_COUNT  100
> +
> +#define IWPM_ULIBNAME_SIZE 32
> +#define IWPM_DEVNAME_SIZE  32
> +#define IWPM_IFNAME_SIZE   16
> +
> +extern struct list_head nes_nlmsg_request_list;
> +extern struct list_head nes_mapping_info_list;
> +extern spinlock_t nes_nlmsg_lock;
> +extern spinlock_t nes_mapping_lock;
> +extern atomic_t nes_nlmsg_seq;
> +extern atomic_t echo_nlmsg_seq;
> +extern char nes_ifname[IWPM_IFNAME_SIZE];
> +extern char nes_ibdev[IWPM_DEVNAME_SIZE];
> +
> +extern struct ibnl_client_cbs nes_nl_cb_table[];
> +extern int nes_iwpm_pid;
> +
> +struct nes_nlmsg_request {
> +	struct list_head inprocess_list;
> +	__u32            nlmsg_seq;
> +	void             *request_buffer;
> +	u8               request_done;
> +	u8               async;
> +	union {
> +		wait_queue_head_t  waitq;
> +		struct timer_list  service_timer;
> +	};
> +
> +	atomic_t  refcount;
> +	u16       err_code;
> +	int       mapcount;
> +
> +};
> +
> +struct nes_mapping_info {
> +	struct list_head mapping_list;
> +	struct sockaddr_in local_sockaddr;
> +	struct sockaddr_in mapped_sockaddr;
> +};
> +
> +enum {
> +	IWPM_INVALID_NLMSG_ERR = 10,
> +	IWPM_CREATE_MAPPING_ERR,
> +	IWPM_DUPLICATE_MAPPING_ERR,
> +	IWPM_UNKNOWN_MAPPING_ERR,
> +	IWPM_CLIENT_DEV_INFO_ERR,
> +	IWPM_USER_LIB_INFO_ERR,
> +	IWPM_REMOTE_QUERY_REJECT
> +};
> +
> +struct nes_cm_info;
> +struct nes_vnic;
> +
> +int nes_register_iwpm_pid(char *, char *, int, void (*req_timer_func)(unsigned long));
> +int nes_add_mapping(struct nes_cm_info *);
> +int nes_add_and_query_mapping(struct nes_cm_info *);
> +int nes_remove_mapping(u32, u16);
> +void nes_create_sockaddr(__be32, __be16, struct sockaddr_in *);
> +int nes_create_mapinfo(struct sockaddr_in *, struct sockaddr_in *);
> +int nes_remove_mapinfo(struct sockaddr_in *);
> +void nes_destroy_mapinfo_list(void);
> +void print_iwpm_available(int);
> +
> +#endif /* __NES_NETLINK_H */
> diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
> index 49eb511..e140c5b 100644
> --- a/drivers/infiniband/hw/nes/nes_nic.c
> +++ b/drivers/infiniband/hw/nes/nes_nic.c
> @@ -94,6 +94,9 @@ static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
>   static int debug = -1;
>   static int nics_per_function = 1;
>   
> +char nes_ifname[IWPM_IFNAME_SIZE];
> +char nes_ibdev[IWPM_DEVNAME_SIZE];
> +
>   /**
>    * nes_netdev_poll
>    */
> @@ -266,6 +269,8 @@ static int nes_netdev_open(struct net_device *netdev)
>   	napi_enable(&nesvnic->napi);
>   	nesvnic->netdev_open = 1;
>   
> +	memcpy(nes_ifname, nesvnic->netdev->name, IWPM_IFNAME_SIZE);
> +	memcpy(nes_ibdev, nesvnic->nesibdev->ibdev.name, IWPM_DEVNAME_SIZE);
>   	return 0;
>   }
>   

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
index 97820c2..5b6cec2 100644
--- a/drivers/infiniband/hw/nes/Makefile
+++ b/drivers/infiniband/hw/nes/Makefile
@@ -1,3 +1,3 @@ 
 obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
 
-iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o
+iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o nes_netlink.o
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 4291410..9be43b3 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -68,7 +68,6 @@  MODULE_VERSION(DRV_VERSION);
 int max_mtu = 9000;
 int interrupt_mod_interval = 0;
 
-
 /* Interoperability */
 int mpa_version = 1;
 module_param(mpa_version, int, 0644);
@@ -672,6 +671,18 @@  static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 	}
 	nes_notifiers_registered++;
 
+	spin_lock_init(&nes_nlmsg_lock);
+	spin_lock_init(&nes_mapping_lock);
+
+	/* List of submitted requests, searched for completions */
+	INIT_LIST_HEAD(&nes_nlmsg_request_list);
+	/* List of iwpm mappings in use */
+	INIT_LIST_HEAD(&nes_mapping_info_list);
+
+	if (ibnl_add_client(RDMA_NL_NES, RDMA_NL_IWPM_NUM_OPS, nes_nl_cb_table))
+		printk(KERN_ERR PFX "%s[%u]: Failed to add netlink callback\n",
+			__func__, __LINE__);
+
 	INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
 
 	/* Initialize network devices */
@@ -707,6 +718,7 @@  static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 
 	nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
 			nesdev->netdev_count, nesdev->nesadapter->netdev_count);
+	ibnl_remove_client(RDMA_NL_NES);
 
 	nes_notifiers_registered--;
 	if (nes_notifiers_registered == 0) {
@@ -770,6 +782,8 @@  static void nes_remove(struct pci_dev *pcidev)
 				nesdev->nesadapter->netdev_count--;
 			}
 		}
+	ibnl_remove_client(RDMA_NL_NES);
+	nes_destroy_mapinfo_list();
 
 	nes_notifiers_registered--;
 	if (nes_notifiers_registered == 0) {
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 33cc589..21b8a86 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -130,6 +130,7 @@ 
 #define NES_DBG_IW_TX       0x00040000
 #define NES_DBG_SHUTDOWN    0x00080000
 #define NES_DBG_PAU         0x00100000
+#define NES_DBG_NLMSG       0x00200000
 #define NES_DBG_RSVD1       0x10000000
 #define NES_DBG_RSVD2       0x20000000
 #define NES_DBG_RSVD3       0x40000000
@@ -165,6 +166,7 @@  do { \
 #include "nes_user.h"
 #include "nes_cm.h"
 #include "nes_mgt.h"
+#include "nes_netlink.h"
 
 extern int max_mtu;
 #define max_frame_len (max_mtu+ETH_HLEN)
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 6b29249..ec14466 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -59,6 +59,7 @@ 
 #include <net/route.h>
 #include <net/ip_fib.h>
 #include <net/tcp.h>
+#include <linux/fcntl.h>
 
 #include "nes.h"
 
@@ -450,11 +451,11 @@  static void form_cm_frame(struct sk_buff *skb,
 	iph->ttl = 0x40;
 	iph->protocol = 0x06;   /* IPPROTO_TCP */
 
-	iph->saddr = htonl(cm_node->loc_addr);
-	iph->daddr = htonl(cm_node->rem_addr);
+	iph->saddr = htonl(cm_node->mapped_loc_addr);
+	iph->daddr = htonl(cm_node->mapped_rem_addr);
 
-	tcph->source = htons(cm_node->loc_port);
-	tcph->dest = htons(cm_node->rem_port);
+	tcph->source = htons(cm_node->mapped_loc_port);
+	tcph->dest = htons(cm_node->mapped_rem_port);
 	tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
 
 	if (flags & SET_ACK) {
@@ -1100,8 +1101,11 @@  static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
 			  loc_addr, loc_port,
 			  cm_node->rem_addr, cm_node->rem_port,
 			  rem_addr, rem_port);
-		if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&
-		    (cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {
+		if ((cm_node->mapped_loc_addr == loc_addr) &&
+			(cm_node->mapped_loc_port == loc_port) &&
+			(cm_node->mapped_rem_addr == rem_addr) &&
+			(cm_node->mapped_rem_port == rem_port)) {
+
 			add_ref_cm_node(cm_node);
 			spin_unlock_irqrestore(&cm_core->ht_lock, flags);
 			return cm_node;
@@ -1118,18 +1122,28 @@  static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
  * find_listener - find a cm node listening on this addr-port pair
  */
 static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
-					     nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)
+					nes_addr_t dst_addr, u16 dst_port,
+					enum nes_cm_listener_state listener_state, int local)
 {
 	unsigned long flags;
 	struct nes_cm_listener *listen_node;
+	nes_addr_t listen_addr;
+	u16 listen_port;
 
 	/* walk list and find cm_node associated with this session ID */
 	spin_lock_irqsave(&cm_core->listen_list_lock, flags);
 	list_for_each_entry(listen_node, &cm_core->listen_list.list, list) {
+		if (local) {
+			listen_addr = listen_node->loc_addr;
+			listen_port = listen_node->loc_port;
+		} else {
+			listen_addr = listen_node->mapped_loc_addr;
+			listen_port = listen_node->mapped_loc_port;
+		}
 		/* compare node pair, return node handle if a match */
-		if (((listen_node->loc_addr == dst_addr) ||
-		     listen_node->loc_addr == 0x00000000) &&
-		    (listen_node->loc_port == dst_port) &&
+		if (((listen_addr == dst_addr) ||
+		     listen_addr == 0x00000000) &&
+		    (listen_port == dst_port) &&
 		    (listener_state & listen_node->listener_state)) {
 			atomic_inc(&listen_node->ref_count);
 			spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
@@ -1142,7 +1156,6 @@  static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
 	return NULL;
 }
 
-
 /**
  * add_hte_node - add a cm node to the hash table
  */
@@ -1263,9 +1276,12 @@  static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
 
 		spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
 
-		if (listener->nesvnic)
-			nes_manage_apbvt(listener->nesvnic, listener->loc_port,
+		if (listener->nesvnic) {
+			nes_manage_apbvt(listener->nesvnic, listener->mapped_loc_port,
 					 PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+			nes_remove_mapping(listener->mapped_loc_addr, listener->mapped_loc_port);
+			nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n", listener->mapped_loc_port);
+		}
 
 		nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
 
@@ -1408,6 +1424,11 @@  static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
 	cm_node->loc_port = cm_info->loc_port;
 	cm_node->rem_port = cm_info->rem_port;
 
+	cm_node->mapped_loc_addr = cm_info->mapped_loc_addr;
+	cm_node->mapped_rem_addr = cm_info->mapped_rem_addr;
+	cm_node->mapped_loc_port = cm_info->mapped_loc_port;
+	cm_node->mapped_rem_port = cm_info->mapped_rem_port;
+
 	cm_node->mpa_frame_rev = mpa_version;
 	cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO;
 	cm_node->ird_size = IETF_NO_IRD_ORD;
@@ -1453,8 +1474,8 @@  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 */
-	oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
-	arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex);
+	oldarpindex = nes_arp_table(nesdev, cm_node->mapped_rem_addr, NULL, NES_ARP_RESOLVE);
+	arpindex = nes_addr_resolve_neigh(nesvnic, cm_node->mapped_rem_addr, oldarpindex);
 	if (arpindex < 0) {
 		kfree(cm_node);
 		return NULL;
@@ -1516,11 +1537,13 @@  static int rem_ref_cm_node(struct nes_cm_core *cm_core,
 		mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
 	} else {
 		if (cm_node->apbvt_set && cm_node->nesvnic) {
-			nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
-					 PCI_FUNC(
-						 cm_node->nesvnic->nesdev->pcidev->devfn),
+			nes_manage_apbvt(cm_node->nesvnic, cm_node->mapped_loc_port,
+					 PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
 					 NES_MANAGE_APBVT_DEL);
 		}
+		nes_debug(NES_DBG_NLMSG, "Delete APBVT mapped_loc_port = %04X\n",
+					cm_node->mapped_loc_port);
+		nes_remove_mapping(cm_node->mapped_loc_addr, cm_node->mapped_loc_port);
 	}
 
 	atomic_dec(&cm_core->node_cnt);
@@ -2192,13 +2215,15 @@  static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
 {
 	struct nes_cm_listener *listener;
 	unsigned long flags;
+	int async = 0;
+	int iwpm_err = 0;
 
 	nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
 		  cm_info->loc_addr, cm_info->loc_port);
 
 	/* cannot have multiple matching listeners */
 	listener = find_listener(cm_core, htonl(cm_info->loc_addr),
-				 htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);
+				 htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE, 1);
 	if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
 		/* find automatically incs ref count ??? */
 		atomic_dec(&listener->ref_count);
@@ -2207,6 +2232,21 @@  static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
 	}
 
 	if (!listener) {
+		if (nes_iwpm_pid == NES_IWPM_PID_UNDEFINED) {
+			iwpm_err = nes_register_iwpm_pid(nesvnic->netdev->name,
+						nesvnic->nesibdev->ibdev.name, async, NULL);
+			if (iwpm_err) {
+				nes_iwpm_pid = NES_IWPM_PID_ERROR;
+				nes_debug(NES_DBG_NLMSG, "Port Mapper register pid failure (err = %d).\n", iwpm_err);
+			}
+		}
+		if (nes_iwpm_pid > 0) { /* valid iwpm pid */
+			iwpm_err = nes_add_mapping(cm_info);
+			if (iwpm_err)
+				nes_debug(NES_DBG_NLMSG, "Port Mapper query failure (err = %d).\n", iwpm_err);
+		}
+		print_iwpm_available(nes_iwpm_pid);
+
 		/* create a CM listen node (1/2 node to compare incoming traffic to) */
 		listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
 		if (!listener) {
@@ -2216,6 +2256,8 @@  static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
 
 		listener->loc_addr = htonl(cm_info->loc_addr);
 		listener->loc_port = htons(cm_info->loc_port);
+		listener->mapped_loc_addr = htonl(cm_info->mapped_loc_addr);
+		listener->mapped_loc_port = htons(cm_info->mapped_loc_port);
 		listener->reused_node = 0;
 
 		atomic_set(&listener->ref_count, 1);
@@ -2277,14 +2319,16 @@  static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
 
 	if (cm_info->loc_addr == cm_info->rem_addr) {
 		loopbackremotelistener = find_listener(cm_core,
-						       ntohl(nesvnic->local_ipaddr), cm_node->rem_port,
-						       NES_CM_LISTENER_ACTIVE_STATE);
+						cm_node->mapped_loc_addr, cm_node->mapped_rem_port,
+						NES_CM_LISTENER_ACTIVE_STATE, 0);
 		if (loopbackremotelistener == NULL) {
 			create_event(cm_node, NES_CM_EVENT_ABORTED);
 		} else {
 			loopback_cm_info = *cm_info;
 			loopback_cm_info.loc_port = cm_info->rem_port;
 			loopback_cm_info.rem_port = cm_info->loc_port;
+			loopback_cm_info.mapped_loc_port = cm_info->mapped_rem_port;
+			loopback_cm_info.mapped_rem_port = cm_info->mapped_loc_port;
 			loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
 			loopbackremotenode = make_cm_node(cm_core, nesvnic,
 							  &loopback_cm_info, loopbackremotelistener);
@@ -2513,6 +2557,12 @@  static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
 	nfo.rem_addr = ntohl(iph->saddr);
 	nfo.rem_port = ntohs(tcph->source);
 
+	/* If port mapper is available these should be mapped address info */
+	nfo.mapped_loc_addr = ntohl(iph->daddr);
+	nfo.mapped_loc_port = ntohs(tcph->dest);
+	nfo.mapped_rem_addr = ntohl(iph->saddr);
+	nfo.mapped_rem_port = ntohs(tcph->source);
+
 	tmp_daddr = cpu_to_be32(iph->daddr);
 	tmp_saddr = cpu_to_be32(iph->saddr);
 
@@ -2521,8 +2571,8 @@  static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
 
 	do {
 		cm_node = find_node(cm_core,
-				    nfo.rem_port, nfo.rem_addr,
-				    nfo.loc_port, nfo.loc_addr);
+				    nfo.mapped_rem_port, nfo.mapped_rem_addr,
+				    nfo.mapped_loc_port, nfo.mapped_loc_addr);
 
 		if (!cm_node) {
 			/* Only type of packet accepted are for */
@@ -2531,9 +2581,9 @@  static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
 				skb_handled = 0;
 				break;
 			}
-			listener = find_listener(cm_core, nfo.loc_addr,
-						 nfo.loc_port,
-						 NES_CM_LISTENER_ACTIVE_STATE);
+			listener = find_listener(cm_core, nfo.mapped_loc_addr,
+						 nfo.mapped_loc_port,
+						 NES_CM_LISTENER_ACTIVE_STATE, 0);
 			if (!listener) {
 				nfo.cm_id = NULL;
 				nfo.conn_type = 0;
@@ -3133,10 +3183,12 @@  int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 
 	nes_cm_init_tsa_conn(nesqp, cm_node);
 
-	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port));
-	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port));
+	nesqp->nesqp_context->tcpPorts[0] =
+				cpu_to_le16(cm_node->mapped_loc_port);
+	nesqp->nesqp_context->tcpPorts[1] =
+				cpu_to_le16(cm_node->mapped_rem_port);
 
-	nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr));
+	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
 
 	nesqp->nesqp_context->misc2 |= cpu_to_le32(
 		(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
@@ -3160,9 +3212,9 @@  int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	memset(&nes_quad, 0, sizeof(nes_quad));
 	nes_quad.DstIpAdrIndex =
 		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-	nes_quad.SrcIpadr = raddr->sin_addr.s_addr;
-	nes_quad.TcpPorts[0] = raddr->sin_port;
-	nes_quad.TcpPorts[1] = laddr->sin_port;
+	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
+	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
+	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
 
 	/* Produce hash key */
 	crc_value = get_crc_value(&nes_quad);
@@ -3261,6 +3313,9 @@  int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	int apbvt_set = 0;
 	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
 	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
+	struct sockaddr_in local_sockaddr, mapped_sockaddr;
+	int async = 0;
+	int iwpm_err = 0;
 
 	if (cm_id->remote_addr.ss_family != AF_INET)
 		return -ENOSYS;
@@ -3304,13 +3359,6 @@  int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
 		  conn_param->private_data_len);
 
-	if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
-		nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
-				 PCI_FUNC(nesdev->pcidev->devfn),
-				 NES_MANAGE_APBVT_ADD);
-		apbvt_set = 1;
-	}
-
 	/* set up the connection params for the node */
 	cm_info.loc_addr = htonl(laddr->sin_addr.s_addr);
 	cm_info.loc_port = htons(laddr->sin_port);
@@ -3319,6 +3367,40 @@  int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	cm_info.cm_id = cm_id;
 	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
 
+	/* No port mapper available, go with the specified peer information */
+	cm_info.mapped_loc_addr = cm_info.loc_addr;
+	cm_info.mapped_loc_port = cm_info.loc_port;
+	cm_info.mapped_rem_addr = cm_info.rem_addr;
+	cm_info.mapped_rem_port = cm_info.rem_port;
+
+	if (nes_iwpm_pid == NES_IWPM_PID_UNDEFINED) {
+		iwpm_err = nes_register_iwpm_pid(nesvnic->netdev->name,
+					nesvnic->nesibdev->ibdev.name, async, NULL);
+		if (iwpm_err) {
+			nes_iwpm_pid = NES_IWPM_PID_ERROR;
+			nes_debug(NES_DBG_NLMSG, "Port Mapper register pid failure (err = %d).\n", iwpm_err);
+		}
+	}
+	if (nes_iwpm_pid > 0) { /* valid iwpm pid */
+		iwpm_err = nes_add_and_query_mapping(&cm_info);
+		if (iwpm_err)
+			nes_debug(NES_DBG_NLMSG, "Port Mapper query failure (err = %d).\n", iwpm_err);
+	}
+	print_iwpm_available(nes_iwpm_pid);
+
+	if (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr) {
+		nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
+			PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+		apbvt_set = 1;
+	}
+
+	nes_create_sockaddr(htonl(cm_info.loc_addr),
+				htons(cm_info.loc_port), &local_sockaddr);
+	nes_create_sockaddr(htonl(cm_info.mapped_loc_addr),
+				htons(cm_info.mapped_loc_port), &mapped_sockaddr);
+	if (nes_create_mapinfo(&local_sockaddr, &mapped_sockaddr))
+		return -ENOMEM;
+
 	cm_id->add_ref(cm_id);
 
 	/* create a connect CM node connection */
@@ -3327,10 +3409,13 @@  int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 					  &cm_info);
 	if (!cm_node) {
 		if (apbvt_set)
-			nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
+			nes_manage_apbvt(nesvnic, cm_info.mapped_loc_port,
 					 PCI_FUNC(nesdev->pcidev->devfn),
 					 NES_MANAGE_APBVT_DEL);
 
+		nes_debug(NES_DBG_NLMSG, "Delete mapped_loc_port = %04X\n",
+				cm_info.mapped_loc_port);
+		nes_remove_mapping(cm_info.mapped_loc_addr, cm_info.mapped_loc_port);
 		cm_id->rem_ref(cm_id);
 		return -ENOMEM;
 	}
@@ -3354,6 +3439,7 @@  int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
 	struct nes_cm_info cm_info;
 	int err;
 	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
+	struct sockaddr_in local_sockaddr, mapped_sockaddr;
 
 	nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
 		  cm_id, ntohs(laddr->sin_port));
@@ -3378,6 +3464,9 @@  int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
 
 	cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
 
+	/* No port mapper available, go with the specified info */
+	cm_info.mapped_loc_addr = cm_info.loc_addr;
+	cm_info.mapped_loc_port = cm_info.loc_port;
 
 	cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
 	if (!cm_node) {
@@ -3389,7 +3478,13 @@  int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
 	cm_id->provider_data = cm_node;
 
 	if (!cm_node->reused_node) {
-		err = nes_manage_apbvt(nesvnic, ntohs(laddr->sin_port),
+		nes_create_sockaddr(cm_info.loc_addr, cm_info.loc_port, &local_sockaddr);
+		nes_create_sockaddr(cm_info.mapped_loc_addr, cm_info.mapped_loc_port,
+					&mapped_sockaddr);
+		if (nes_create_mapinfo(&local_sockaddr, &mapped_sockaddr))
+			return -ENOMEM;
+
+		err = nes_manage_apbvt(nesvnic, cm_node->mapped_loc_port,
 				       PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
 				       NES_MANAGE_APBVT_ADD);
 		if (err) {
@@ -3514,9 +3609,9 @@  static void cm_event_connected(struct nes_cm_event *event)
 	nes_cm_init_tsa_conn(nesqp, cm_node);
 
 	/* set the QP tsa context */
-	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(laddr->sin_port));
-	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(raddr->sin_port));
-	nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(raddr->sin_addr.s_addr));
+	nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(cm_node->mapped_loc_port);
+	nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(cm_node->mapped_rem_port);
+	nesqp->nesqp_context->ip0 = cpu_to_le32(cm_node->mapped_rem_addr);
 
 	nesqp->nesqp_context->misc2 |= cpu_to_le32(
 			(u32)PCI_FUNC(nesdev->pcidev->devfn) <<
@@ -3544,9 +3639,9 @@  static void cm_event_connected(struct nes_cm_event *event)
 
 	nes_quad.DstIpAdrIndex =
 		cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
-	nes_quad.SrcIpadr = raddr->sin_addr.s_addr;
-	nes_quad.TcpPorts[0] = raddr->sin_port;
-	nes_quad.TcpPorts[1] = laddr->sin_port;
+	nes_quad.SrcIpadr = htonl(cm_node->mapped_rem_addr);
+	nes_quad.TcpPorts[0] = htons(cm_node->mapped_rem_port);
+	nes_quad.TcpPorts[1] = htons(cm_node->mapped_loc_port);
 
 	/* Produce hash key */
 	crc_value = get_crc_value(&nes_quad);
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
index 4646e66..331a573 100644
--- a/drivers/infiniband/hw/nes/nes_cm.h
+++ b/drivers/infiniband/hw/nes/nes_cm.h
@@ -291,8 +291,8 @@  struct nes_cm_listener {
 	struct list_head           list;
 	struct nes_cm_core         *cm_core;
 	u8                         loc_mac[ETH_ALEN];
-	nes_addr_t                 loc_addr;
-	u16                        loc_port;
+	nes_addr_t                 loc_addr, mapped_loc_addr;
+	u16                        loc_port, mapped_loc_port;
 	struct iw_cm_id            *cm_id;
 	enum nes_cm_conn_type      conn_type;
 	atomic_t                   ref_count;
@@ -306,7 +306,9 @@  struct nes_cm_listener {
 /* per connection node and node state information */
 struct nes_cm_node {
 	nes_addr_t                loc_addr, rem_addr;
+	nes_addr_t                mapped_loc_addr, mapped_rem_addr;
 	u16                       loc_port, rem_port;
+	u16                       mapped_loc_port, mapped_rem_port;
 
 	u8                        loc_mac[ETH_ALEN];
 	u8                        rem_mac[ETH_ALEN];
@@ -357,10 +359,8 @@  struct nes_cm_info {
 		struct net_device *netdev;
 	};
 
-	u16 loc_port;
-	u16 rem_port;
-	nes_addr_t loc_addr;
-	nes_addr_t rem_addr;
+	u16 loc_port, rem_port, mapped_loc_port, mapped_rem_port;
+	nes_addr_t loc_addr, rem_addr, mapped_loc_addr, mapped_rem_addr;
 
 	enum nes_cm_conn_type  conn_type;
 	int backlog;
diff --git a/drivers/infiniband/hw/nes/nes_netlink.c b/drivers/infiniband/hw/nes/nes_netlink.c
new file mode 100644
index 0000000..6408089
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_netlink.c
@@ -0,0 +1,1223 @@ 
+/*
+ * Copyright (c) 2013 Intel Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * 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 pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
+
+#include "nes.h"
+#include "nes_netlink.h"
+
+spinlock_t nes_nlmsg_lock;
+struct list_head nes_nlmsg_request_list;
+struct list_head nes_mapping_info_list;
+spinlock_t nes_mapping_lock;
+atomic_t nes_nlmsg_seq;
+atomic_t echo_nlmsg_seq;
+
+int nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+static const char iwpm_ulib_name[] = "iWarpPortMapperUser";
+static int iwpm_ulib_version = 3;
+
+static struct nes_nlmsg_request *nes_get_nlmsg_request(void);
+static int nes_send_mapping_info(void);
+static int nes_send_mapping_count(u32);
+static int nes_parse_nlmsg(struct netlink_callback *, int, const struct nla_policy *,
+				struct nlattr *[], const char *);
+
+/* nes netlink callbacks */
+static int nes_register_iwpm_pid_cb(struct sk_buff *, struct netlink_callback *);
+static int nes_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
+static int nes_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
+static int nes_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
+static int nes_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
+static int nes_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
+
+/*
+ * nes_get_nlmsg_request - Allocate and initialize a netlink request tracking object
+ */
+static struct nes_nlmsg_request *nes_get_nlmsg_request(void)
+{
+	unsigned long flags;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+
+	nlmsg_request = kzalloc(sizeof(struct nes_nlmsg_request), GFP_ATOMIC);
+	if (!nlmsg_request) {
+		pr_err("%s: Unable to allocate a nlmsg_request\n", __func__);
+		return NULL;
+	}
+	spin_lock_irqsave(&nes_nlmsg_lock, flags);
+	list_add_tail(&nlmsg_request->inprocess_list, &nes_nlmsg_request_list);
+	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
+
+	atomic_set(&nlmsg_request->refcount, 1);
+	nlmsg_request->nlmsg_seq = atomic_inc_return(&nes_nlmsg_seq);
+	nlmsg_request->request_done = 0;
+	nlmsg_request->async = 0;
+	nlmsg_request->err_code = 0;
+	return nlmsg_request;
+}
+
+/*
+ * free_nlmsg_request - Free netlink request tracking object
+ */
+static void free_nlmsg_request(struct nes_nlmsg_request *nlmsg_request)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&nes_nlmsg_lock, flags);
+	list_del_init(&nlmsg_request->inprocess_list);
+	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
+
+	if (nlmsg_request->async)
+		del_timer(&nlmsg_request->service_timer);
+
+	if (!nlmsg_request->request_done)
+		nes_debug(NES_DBG_NLMSG, "Freeing incomplete nlmsg request (seq = %u)\n",
+			nlmsg_request->nlmsg_seq);
+	kfree(nlmsg_request);
+}
+
+/*
+ * rem_ref_nlmsg_request - Decrement the refcount and free the request
+ *			   object if the refcount is zero
+ */
+static void rem_ref_nlmsg_request(struct nes_nlmsg_request *nlmsg_request)
+{
+	if (atomic_dec_and_test(&nlmsg_request->refcount))
+		free_nlmsg_request(nlmsg_request);
+}
+
+/*
+ * nes_nlmsg_req_timer_free - Free expired request object
+ */
+static void nes_nlmsg_req_timer_free(unsigned long data)
+{
+	struct nes_nlmsg_request *nlmsg_request = (struct nes_nlmsg_request *) data;
+
+	if (!nlmsg_request->request_done && !nlmsg_request->err_code)
+		nes_iwpm_pid = NES_IWPM_PID_UNAVAILABLE;
+
+	if (nes_iwpm_pid < 0)
+		nes_debug(NES_DBG_NLMSG, "Port Mapper isn't available (err code = %d)\n",
+				 nlmsg_request->err_code);
+	rem_ref_nlmsg_request(nlmsg_request);
+}
+
+/*
+ * nes_mapinfo_timer_send - Send mapping info to the userspace port mapper
+ */
+static void nes_mapinfo_timer_send(unsigned long data)
+{
+	int mapping_num;
+
+	nes_nlmsg_req_timer_free(data);
+	if (nes_iwpm_pid < 0)
+		return;
+	mapping_num = nes_send_mapping_info();
+	if (mapping_num < 0) {
+		nes_debug(NES_DBG_NLMSG, "Unable to send mapping info\n");
+		return;
+	}
+	nes_debug(NES_DBG_NLMSG, "Sending Mapping count msg (num = %d)\n", mapping_num);
+	nes_send_mapping_count(mapping_num);
+}
+
+/*
+ * nes_start_nlmsg_req_timer - Start a timer on a netlink request object
+ */
+static void nes_start_nlmsg_req_timer(struct nes_nlmsg_request *nlmsg_request,
+					void (*timer_func)(unsigned long), u32 delay)
+{
+	init_timer(&nlmsg_request->service_timer);
+	setup_timer(&nlmsg_request->service_timer, timer_func,
+			(unsigned long) nlmsg_request);
+	mod_timer(&nlmsg_request->service_timer, jiffies + delay);
+}
+
+/*
+ * nes_validate_nlmsg_attr - Check for NULL netlink attributes
+ */
+static int nes_validate_nlmsg_attr(struct nlattr *nltb[], int nla_count)
+{
+	int i;
+	for (i = 1; i < nla_count; i++) {
+		if (!nltb[i])
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * nes_create_nlmsg - Allocate skb and form a netlink message
+ */
+static struct sk_buff *nes_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh)
+{
+	struct sk_buff *skb = NULL;
+
+	skb = dev_alloc_skb(NLMSG_GOODSIZE);
+	if (!skb) {
+		pr_err("%s: Unable to allocate skb\n", __func__);
+		goto create_nlmsg_exit;
+	}
+	if (!(ibnl_put_msg(skb, nlh, 0, 0, RDMA_NL_NES, nl_op, NLM_F_REQUEST))) {
+		pr_info("%s: Unable to put the nlmsg header\n", __func__);
+		dev_kfree_skb(skb);
+		skb = NULL;
+	}
+create_nlmsg_exit:
+	return skb;
+}
+
+/*
+ * nes_parse_nlmsg - Validate and parse the received netlink message
+ */
+static int nes_parse_nlmsg(struct netlink_callback *cb, int policy_max,
+			const struct nla_policy *nlmsg_policy,
+			struct nlattr *nltb[], const char *msg_type)
+{
+	int nlh_len = 0;
+	int ret;
+	const char *err_str = "";
+
+	ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy);
+	if (ret) {
+		err_str = "Invalid attribute";
+		goto parse_nlmsg_error;
+	}
+	ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy);
+	if (ret) {
+		err_str = "Unable to parse the nlmsg";
+		goto parse_nlmsg_error;
+	}
+	ret = nes_validate_nlmsg_attr(nltb, policy_max);
+	if (ret) {
+		err_str = "Invalid NULL attribute";
+		goto parse_nlmsg_error;
+	}
+	return 0;
+parse_nlmsg_error:
+	pr_info("%s: %s (msg type %s ret = %d)\n", __func__, err_str, msg_type, ret);
+	return ret;
+}
+
+/*
+ * wait_complete_nlmsg_req - Block while servicing the netlink request
+ *
+ * Wake up, after the request is completed or expired
+ */
+static int wait_complete_nlmsg_req(struct nes_nlmsg_request *nlmsg_request, int iwpm_pid)
+{
+	int ret;
+	init_waitqueue_head(&nlmsg_request->waitq);
+
+	ret = wait_event_timeout(nlmsg_request->waitq, (nlmsg_request->request_done != 0),
+					NES_IWPM_NL_TIMEOUT);
+	if (!ret) {
+		nes_iwpm_pid = iwpm_pid;
+		pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
+			__func__, (NES_IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
+	} else
+		ret = nlmsg_request->err_code;
+
+	rem_ref_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * nes_find_nlmsg_request - Find a request object using its sequence number
+ */
+static struct nes_nlmsg_request *nes_find_nlmsg_request(__u32 echo_seq)
+{
+	struct nes_nlmsg_request *nlmsg_request;
+	struct nes_nlmsg_request *found_request = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nes_nlmsg_lock, flags);
+	list_for_each_entry(nlmsg_request, &nes_nlmsg_request_list, inprocess_list) {
+		nes_debug(NES_DBG_NLMSG, "Looking at a request with seq = %u\n",
+				nlmsg_request->nlmsg_seq);
+		if (nlmsg_request->nlmsg_seq == echo_seq) {
+			found_request = nlmsg_request;
+			atomic_inc(&nlmsg_request->refcount);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&nes_nlmsg_lock, flags);
+	return found_request;
+}
+
+/*
+ * nes_create_sockaddr - Record ip addr and tcp port in a sockaddr struct
+ */
+void nes_create_sockaddr(__be32 s_addr, __be16 s_port, struct sockaddr_in *cm_sockaddr)
+{
+	cm_sockaddr->sin_family = AF_INET;
+	memcpy(&cm_sockaddr->sin_addr.s_addr, &s_addr, sizeof(__be32));
+	cm_sockaddr->sin_port = s_port;
+}
+
+/*
+ * nes_create_mapinfo - Create mapping info record
+ */
+int nes_create_mapinfo(struct sockaddr_in *local_sockaddr,
+				struct sockaddr_in *mapped_sockaddr)
+{
+	struct nes_mapping_info *map_info;
+	unsigned long flags;
+
+	map_info = kzalloc(sizeof(struct nes_mapping_info), GFP_KERNEL);
+	if (!map_info) {
+		pr_err("%s: Unable to allocate a mapping info\n", __func__);
+		return -ENOMEM;
+	}
+	memcpy(&map_info->local_sockaddr, local_sockaddr, sizeof(struct sockaddr_in));
+	memcpy(&map_info->mapped_sockaddr, mapped_sockaddr, sizeof(struct sockaddr_in));
+
+	spin_lock_irqsave(&nes_mapping_lock, flags);
+	list_add_tail(&map_info->mapping_list, &nes_mapping_info_list);
+	spin_unlock_irqrestore(&nes_mapping_lock, flags);
+	return 0;
+}
+
+/*
+ * nes_remove_mapinfo - Remove mapping info record
+ */
+int nes_remove_mapinfo(struct sockaddr_in *mapped_sockaddr)
+{
+	struct nes_mapping_info *map_info = NULL;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	nes_debug(NES_DBG_NLMSG, "Remove mapped addr %pI4 [0x%04X]\n",
+			&mapped_sockaddr->sin_addr.s_addr, mapped_sockaddr->sin_port);
+
+	spin_lock_irqsave(&nes_mapping_lock, flags);
+	list_for_each_entry(map_info, &nes_mapping_info_list, mapping_list) {
+		if (!memcmp(&map_info->mapped_sockaddr.sin_addr,
+			&mapped_sockaddr->sin_addr, sizeof(__be32)) &&
+			map_info->mapped_sockaddr.sin_port == mapped_sockaddr->sin_port) {
+
+			list_del_init(&map_info->mapping_list);
+			kfree(map_info);
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&nes_mapping_lock, flags);
+	return ret;
+}
+
+/*
+ * nes_destroy_mapinfo_list - Delete all mapping info records
+ */
+void nes_destroy_mapinfo_list(void)
+{
+	struct nes_mapping_info *map_info, *map_info_tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nes_mapping_lock, flags);
+	list_for_each_entry_safe(map_info, map_info_tmp,
+					&nes_mapping_info_list, mapping_list) {
+
+		nes_debug(NES_DBG_NLMSG, "Delete mapped addr %pI4 [0x%04X]\n",
+			&map_info->mapped_sockaddr.sin_addr.s_addr,
+			map_info->mapped_sockaddr.sin_port);
+
+		list_del(&map_info->mapping_list);
+		kfree(map_info);
+	}
+	spin_unlock_irqrestore(&nes_mapping_lock, flags);
+}
+
+/*
+ * print_iwpm_available - Print a message if the port mapper isn't available
+ */
+void print_iwpm_available(int iwpm_pid)
+{
+	static int one_time;
+
+	if (iwpm_pid < 0 && !one_time) {
+		pr_info("iWarp Port Mapper (pid = %d) is not available.\n", nes_iwpm_pid);
+		one_time++;
+	}
+	if (iwpm_pid > 0)
+		one_time = 0;
+}
+
+/*
+ * nes_register_iwpm_pid - Send a netlink query for the iwarp port mapper pid
+ *				to the userspace
+ * nlmsg attributes:
+ *	[IWPM_NLA_REG_PID_SEQ]
+ *	[IWPM_NLA_REG_IF_NAME]
+ *	[IWPM_NLA_REG_IBDEV_NAME]
+ *	[IWPM_NLA_REG_ULIB_NAME]
+ */
+int nes_register_iwpm_pid(char *netdev_name, char *dev_name, int async,
+				void (*req_timer_func)(unsigned long))
+{
+	struct sk_buff *skb = NULL;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = nes_create_nlmsg(RDMA_NL_IWPM_REG_PID, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto pid_query_error;
+	}
+	nlmsg_request = nes_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto pid_query_error;
+	}
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+
+	/* fill in the pid request message */
+	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
+	err_str = "Unable to put attribute of the nlmsg";
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
+	if (ret)
+		goto pid_query_error;
+	ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE,
+				netdev_name, IWPM_NLA_REG_IF_NAME);
+	if (ret)
+		goto pid_query_error;
+	ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE,
+				dev_name, IWPM_NLA_REG_IBDEV_NAME);
+	if (ret)
+		goto pid_query_error;
+	ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE,
+				(char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME);
+	if (ret)
+		goto pid_query_error;
+
+	nes_debug(NES_DBG_NLMSG, "Multicasting a nlmsg (ibdev = %s ifname = %s iwpm = %s msglen = %d)\n",
+			dev_name, netdev_name, iwpm_ulib_name, nlh->nlmsg_len);
+
+	ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
+	if (ret) {
+		/* skb is already freed in the netlink send-op handling */
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+		goto pid_query_error_exit;
+	}
+	nlmsg_request->async = async;
+	if (async)
+		nes_start_nlmsg_req_timer(nlmsg_request, req_timer_func, NES_IWPM_NL_TIMEOUT);
+	else
+		ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNAVAILABLE);
+	return ret;
+pid_query_error:
+	pr_info("%s: %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+pid_query_error_exit:
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * nes_add_mapping - Send a netlink add mapping message
+ *
+ * Send a message to the userspace port mapper to get the
+ * mapping info for a listener local ip/tcp address
+ *
+ * nlmsg attributes:
+ *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
+ *	[IWPM_NLA_MANAGE_ADDR]
+ */
+int nes_add_mapping(struct nes_cm_info *cm_info)
+{
+	struct sk_buff *skb = NULL;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in local_sockaddr;
+	__be32 local_addr = cm_info->loc_addr;
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = nes_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto add_mapping_error;
+	}
+	nlmsg_request = nes_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto add_mapping_error;
+	}
+	local_sockaddr.sin_family = AF_INET;
+	memcpy(&local_sockaddr.sin_addr.s_addr, &local_addr, sizeof(__be32));
+	local_sockaddr.sin_port = cm_info->loc_port;
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+
+	/* fill in the add mapping message */
+	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
+	err_str = "Unable to put attribute of the nlmsg";
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
+				IWPM_NLA_MANAGE_MAPPING_SEQ);
+	if (ret)
+		goto add_mapping_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&local_sockaddr, IWPM_NLA_MANAGE_ADDR);
+	if (ret)
+		goto add_mapping_error;
+
+	nlmsg_request->request_buffer = cm_info;
+	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (local addr %pI4 [0x%04X])\n",
+		&local_sockaddr.sin_addr.s_addr, local_sockaddr.sin_port);
+
+	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
+	if (ret) {
+		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+		/* skb is already freed in the netlink send-op handling */
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+		goto add_mapping_error_exit;
+	}
+	ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNDEFINED);
+	return ret;
+add_mapping_error:
+	pr_info("%s: %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+add_mapping_error_exit:
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * nes_add_and_query_mapping - Send a netlink query mapping message
+ *
+ * Send both a netlink add mapping message to get
+ * the connecting side local ip/tcp address mapping info and
+ * a query for the accepting side mapped (remote)
+ * ip/tcp address to the userspace port mapper
+
+ * nlmsg attributes:
+ *	[IWPM_NLA_QUERY_MAPPING_SEQ]
+ *	[IWPM_NLA_QUERY_LOCAL_ADDR]
+ *	[IWPM_NLA_QUERY_REMOTE_ADDR]
+ */
+int nes_add_and_query_mapping(struct nes_cm_info *cm_info)
+{
+	struct sk_buff *skb = NULL;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in local_sockaddr;
+	struct sockaddr_in remote_sockaddr;
+	__be32 local_addr = htonl(cm_info->loc_addr);
+	__be32 remote_addr = htonl(cm_info->rem_addr);
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = nes_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto query_mapping_error;
+	}
+	nlmsg_request = nes_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto query_mapping_error;
+	}
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+	local_sockaddr.sin_family = AF_INET;
+	memcpy(&local_sockaddr.sin_addr.s_addr, &local_addr, sizeof(__be32));
+	local_sockaddr.sin_port = htons(cm_info->loc_port);
+
+	remote_sockaddr.sin_family = AF_INET;
+	memcpy(&remote_sockaddr.sin_addr.s_addr, &remote_addr, sizeof(__be32));
+	remote_sockaddr.sin_port = htons(cm_info->rem_port);
+
+	/* fill in the query message */
+	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
+	err_str = "Unable to put attribute of the nlmsg";
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
+				IWPM_NLA_QUERY_MAPPING_SEQ);
+	if (ret)
+		goto query_mapping_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&local_sockaddr, IWPM_NLA_QUERY_LOCAL_ADDR);
+	if (ret)
+		goto query_mapping_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&remote_sockaddr, IWPM_NLA_QUERY_REMOTE_ADDR);
+	if (ret)
+		goto query_mapping_error;
+
+	nlmsg_request->request_buffer = cm_info;
+	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (laddr %pI4 [0x%04X], raddr %pI4 [0x%04X])\n",
+		&local_sockaddr.sin_addr.s_addr, local_sockaddr.sin_port,
+		&remote_sockaddr.sin_addr.s_addr, remote_sockaddr.sin_port);
+
+	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
+	if (ret) {
+		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+		/* skb is already freed in the netlink send-op handling */
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+		goto query_mapping_error_exit;
+	}
+	ret = wait_complete_nlmsg_req(nlmsg_request, NES_IWPM_PID_UNDEFINED);
+	return ret;
+query_mapping_error:
+	pr_info("%s: %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+query_mapping_error_exit:
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * nes_remove_mapping - Send a netlink remove mapping message
+ *
+ * nlmsg attributes:
+ *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
+ *	[IWPM_NLA_MANAGE_ADDR]
+ */
+int nes_remove_mapping(nes_addr_t mapped_local_addr, u16 mapped_local_port)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in mapped_sockaddr;
+	__be32 mapped_addr = htonl(mapped_local_addr);
+	const char *err_str = "";
+	int ret;
+
+	mapped_sockaddr.sin_family = AF_INET;
+	memcpy(&mapped_sockaddr.sin_addr.s_addr, &mapped_addr, sizeof(__be32));
+	mapped_sockaddr.sin_port = htons(mapped_local_port);
+
+	if (nes_remove_mapinfo(&mapped_sockaddr)) {
+		pr_info("%s: Fail to remove mapinfo (port = 0x%04X)\n",
+				__func__, mapped_local_port);
+		return -EINVAL;
+	}
+	/* the routine is always called when terminating a connection,
+	* if the userspace port mapper isn't available, can't send a msg */
+	if (nes_iwpm_pid < 0)
+		return 0;
+
+	skb = nes_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, nlh_next);
+	if (!skb) {
+		ret = -ENOMEM;
+		err_str = "Unable to create a nlmsg";
+		goto remove_mapping_error;
+	}
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+
+	nlh->nlmsg_seq = atomic_inc_return(&nes_nlmsg_seq);
+	err_str = "Unable to put attribute of the nlmsg";
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
+				IWPM_NLA_MANAGE_MAPPING_SEQ);
+	if (ret)
+		goto remove_mapping_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&mapped_sockaddr, IWPM_NLA_MANAGE_ADDR);
+	if (ret)
+		goto remove_mapping_error;
+
+	nes_debug(NES_DBG_NLMSG, "Send a nlmsg (mapped laddr %pI4 [0x%04X])\n",
+		&mapped_sockaddr.sin_addr.s_addr, mapped_sockaddr.sin_port);
+
+	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
+	if (ret) {
+		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+		/* skb is already freed in the netlink send-op handling */
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+	}
+	return ret;
+remove_mapping_error:
+	pr_info("%s: %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+	return ret;
+}
+
+/* registered nes netlink callbacks */
+struct ibnl_client_cbs nes_nl_cb_table[] = {
+	[RDMA_NL_IWPM_REG_PID] = {.dump = nes_register_iwpm_pid_cb},
+	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = nes_add_mapping_cb},
+	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = nes_add_and_query_mapping_cb},
+	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = nes_mapping_error_cb},
+	[RDMA_NL_IWPM_MAP_INFO] = {.dump = nes_mapping_info_cb},
+	[RDMA_NL_IWPM_MAP_INFO_NUM] = {.dump = nes_ack_mapping_info_cb}
+};
+
+/* netlink attribute policy for the received response to nes register */
+static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
+	[IWPM_NLA_RREG_PID_SEQ]     = { .type = NLA_U32 },
+	[IWPM_NLA_RREG_IBDEV_NAME]  = { .type = NLA_STRING,
+					.len = IWPM_DEVNAME_SIZE - 1 },
+	[IWPM_NLA_RREG_ULIB_NAME]   = { .type = NLA_STRING,
+					.len = IWPM_ULIBNAME_SIZE - 1 },
+	[IWPM_NLA_RREG_ULIB_VER]    = { .type = NLA_U16 },
+	[IWPM_NLA_RREG_PID_ERR]     = { .type = NLA_U16 }
+};
+
+/*
+ * nes_register_iwpm_pid_cb - Process response to register_iwpm_pid
+ *
+ * The port mapper pid (part of the response message) is used
+ * in the future communication with the port mapper
+ */
+static int nes_register_iwpm_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX];
+	char *dev_name, *iwpm_name;
+	u32 msg_seq;
+	u16 iwpm_version;
+	const char *msg_type = "Register Pid response";
+
+	nes_iwpm_pid = NES_IWPM_PID_ERROR;
+
+	if (nes_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX,
+				resp_reg_policy, nltb, msg_type))
+		return -EINVAL;
+
+	msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]);
+	nlmsg_request = nes_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_info("%s: Could not find a matching request (seq = %u)\n",
+				 __func__, msg_seq);
+		return -EINVAL;
+	}
+	dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]);
+	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]);
+	iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]);
+
+	/* check device name, ulib name and version */
+	if (strcmp(nes_ibdev, dev_name) || strcmp(iwpm_ulib_name, iwpm_name) ||
+			iwpm_version != iwpm_ulib_version) {
+
+		pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n",
+				__func__, dev_name, iwpm_name, iwpm_version);
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto register_pid_response_exit;
+	}
+	nes_debug(NES_DBG_NLMSG, "Received info (dev = %s iwpm = %s version = %d)\n",
+				dev_name, iwpm_name, iwpm_version);
+
+	nes_iwpm_pid = cb->nlh->nlmsg_pid;
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	pr_info("%s: iWarp Port Mapper (pid = %d) is successfully registered.\n",
+			__func__, nes_iwpm_pid);
+register_pid_response_exit:
+	nlmsg_request->request_done = 1;
+	rem_ref_nlmsg_request(nlmsg_request); /* always for found nlmsg_request */
+	barrier();
+	if (!nlmsg_request->async)
+		wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+/* netlink attribute policy for the received response to nes add mapping */
+static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
+	[IWPM_NLA_MANAGE_MAPPING_SEQ]     = { .type = NLA_U32 },
+	[IWPM_NLA_MANAGE_ADDR]            = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_RMANAGE_MAPPING_ERR]	  = { .type = NLA_U16 }
+};
+
+/*
+ * nes_add_mapping_cb - Callback routine when response to add_mapping
+ *			is received from the userspace port mapper
+ *
+ * The response message contains the mapping info for the requested
+ * listener local ip/tcp address
+ */
+static int nes_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nes_cm_info *cm_info;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
+	u32 msg_seq;
+	struct sockaddr_in *local_sockaddr, *mapped_sockaddr;
+	__be32 loc_addr, mapped_addr;
+	const char *msg_type;
+
+	msg_type = "Add Mapping response";
+	if (nes_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX,
+				resp_add_policy, nltb, msg_type))
+		return -EINVAL;
+
+	msg_seq = nla_get_u32(nltb[IWPM_NLA_MANAGE_MAPPING_SEQ]);
+	nlmsg_request = nes_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_info("%s: Could not find a matching request (seq = %u)\n",
+				 __func__, msg_seq);
+		return -EINVAL;
+	}
+	cm_info = nlmsg_request->request_buffer;
+	local_sockaddr = (struct sockaddr_in *)nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
+	mapped_sockaddr = (struct sockaddr_in *)nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
+
+	loc_addr = *(__be32 *)&local_sockaddr->sin_addr.s_addr;
+	if (cm_info->loc_addr != loc_addr ||
+		cm_info->loc_port != local_sockaddr->sin_port) {
+
+		pr_info("%s: Invalid ip/tcp address (Expected %pI4(%04X) Received: %pI4(%04X)\n",
+			__func__, (char *)&cm_info->loc_addr, cm_info->loc_port,
+			(char *)&loc_addr, local_sockaddr->sin_port);
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto add_mapping_response_exit;
+	}
+	if (mapped_sockaddr->sin_family != AF_INET) {
+		pr_info("%s: Invalid sockaddr family = %04X\n",
+				__func__, mapped_sockaddr->sin_family);
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto add_mapping_response_exit;
+	}
+
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	mapped_addr = *(__be32 *)&mapped_sockaddr->sin_addr.s_addr;
+	cm_info->mapped_loc_addr = mapped_addr;
+	cm_info->mapped_loc_port = mapped_sockaddr->sin_port;
+add_mapping_response_exit:
+	nes_debug(NES_DBG_NLMSG, "Received new mapped laddr %pI4 [0x%04X]\n",
+		&mapped_sockaddr->sin_addr.s_addr, mapped_sockaddr->sin_port);
+	nlmsg_request->request_done = 1;
+	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
+	barrier();
+	wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+/* netlink attribute policy for the add_and_query_mapping response */
+static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
+	[IWPM_NLA_QUERY_MAPPING_SEQ]      = { .type = NLA_U32 },
+	[IWPM_NLA_QUERY_LOCAL_ADDR]       = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_QUERY_REMOTE_ADDR]      = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { .len = sizeof(struct sockaddr_storage) },
+	[IWPM_NLA_RQUERY_MAPPING_ERR]	  = { .type = NLA_U16 }
+};
+
+/*
+ * nes_add_and_query_mapping_cb - Process response to add_and_query_mapping
+ *
+ * The response message contains mapping info for the requested
+ * connecting side local ip/tcp address and accepting side (remote) ip/tcp address
+ */
+static int nes_add_and_query_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nes_cm_info *cm_info;
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
+	u32 msg_seq;
+	struct sockaddr_in *local_sockaddr, *remote_sockaddr;
+	struct sockaddr_in *mapped_loc_sockaddr, *mapped_rem_sockaddr;
+	__be32 loc_addr, mapped_loc_addr, rem_addr, mapped_rem_addr;
+	const char *msg_type;
+	u16 err_code;
+
+	msg_type = "Query Mapping response";
+	if (nes_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
+				resp_query_policy, nltb, msg_type))
+		return -EINVAL;
+	msg_seq = nla_get_u32(nltb[IWPM_NLA_QUERY_MAPPING_SEQ]);
+	nlmsg_request = nes_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_info("%s: Could not find a matching request (seq = %u)\n",
+				 __func__, msg_seq);
+			return -EINVAL;
+	}
+	cm_info = nlmsg_request->request_buffer;
+	local_sockaddr =
+		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
+	remote_sockaddr =
+		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
+	mapped_loc_sockaddr =
+		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
+	mapped_rem_sockaddr =
+		(struct sockaddr_in *)nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
+
+	err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
+	if (err_code == IWPM_REMOTE_QUERY_REJECT) {
+		pr_info("%s: Received a Reject nlmsg (pid = %u, echo seq = %u)\n",
+			__func__, cb->nlh->nlmsg_pid, msg_seq);
+		nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
+	}
+	loc_addr = *(__be32 *)&local_sockaddr->sin_addr.s_addr;
+	rem_addr = *(__be32 *)&remote_sockaddr->sin_addr.s_addr;
+	if (cm_info->loc_addr != ntohl(loc_addr) ||
+			cm_info->loc_port != ntohs(local_sockaddr->sin_port) ||
+			cm_info->rem_addr != ntohl(rem_addr) ||
+			cm_info->rem_port != ntohs(remote_sockaddr->sin_port)) {
+
+		pr_info("%s: Expected laddr %pI4 [%04X] Received laddr %pI4 [%04X] "
+			"Expected raddr %pI4 [%04X] Received raddr %pI4 [%04X]\n", __func__,
+			(char *)&cm_info->loc_addr, cm_info->loc_port,
+			(char *)&loc_addr, ntohs(local_sockaddr->sin_port),
+			(char *)&cm_info->rem_addr, cm_info->rem_port,
+			(char *)&rem_addr, ntohs(remote_sockaddr->sin_port));
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto query_mapping_response_exit;
+	}
+	if (mapped_loc_sockaddr->sin_family != AF_INET ||
+			mapped_rem_sockaddr->sin_family != AF_INET) {
+		pr_info("%s: Invalid sockaddr family\n", __func__);
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto query_mapping_response_exit;
+	}
+
+	mapped_loc_addr = *(__be32 *)&mapped_loc_sockaddr->sin_addr.s_addr;
+	mapped_rem_addr = *(__be32 *)&mapped_rem_sockaddr->sin_addr.s_addr;
+
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	cm_info->mapped_loc_addr = ntohl(mapped_loc_addr);
+	cm_info->mapped_loc_port = ntohs(mapped_loc_sockaddr->sin_port);
+	cm_info->mapped_rem_addr = ntohl(mapped_rem_addr);
+	cm_info->mapped_rem_port = ntohs(mapped_rem_sockaddr->sin_port);
+
+query_mapping_response_exit:
+	nes_debug(NES_DBG_NLMSG, "Received mapped laddr %pI4 [0x%04X] raddr %pI4 [0x%04X]\n",
+		&mapped_loc_sockaddr->sin_addr.s_addr, mapped_loc_sockaddr->sin_port,
+		&mapped_rem_sockaddr->sin_addr.s_addr, mapped_rem_sockaddr->sin_port);
+	nlmsg_request->request_done = 1;
+	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
+	barrier();
+	wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+/* netlink attribute policy for the received request for mapping info */
+static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
+	[IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
+					.len = IWPM_ULIBNAME_SIZE - 1 },
+	[IWPM_NLA_MAPINFO_ULIB_VER]  = { .type = NLA_U16 }
+};
+
+/*
+ * nes_mapping_info_cb - Callback routine when message from the port mapper
+ *				is received, to notify that the port mapper is available
+ *				and request the nes records of mapping info
+ */
+static int nes_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
+	char *iwpm_name;
+	u16 iwpm_version;
+	const char *msg_type = "Mapping Info response";
+	void (*req_timer_func)(unsigned long) = NULL;
+	int async = 1;
+
+	if (nes_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX,
+				resp_mapinfo_policy, nltb, msg_type))
+		return -EINVAL;
+
+	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]);
+	iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
+	if (strcmp(iwpm_ulib_name, iwpm_name) || iwpm_version != iwpm_ulib_version) {
+		pr_info("%s: Invalid iWarpPortMapper info (name = %s version = %d)\n",
+				__func__, iwpm_name, iwpm_version);
+		return -EINVAL;
+	}
+	if (list_empty(&nes_mapping_info_list))
+		req_timer_func = &nes_nlmsg_req_timer_free;
+	else
+		req_timer_func = &nes_mapinfo_timer_send;
+
+	nes_register_iwpm_pid(nes_ifname, nes_ibdev, async, req_timer_func);
+	return 0;
+}
+
+/*
+ * nes_send_mapping_count - Send a netlink message with the number of mapping
+ *				info records to the userspace port mapper
+ */
+static int nes_send_mapping_count(u32 mapping_num)
+{
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	const char *err_str = "";
+	int ret = -EINVAL;
+
+	skb = nes_create_nlmsg(RDMA_NL_IWPM_MAP_INFO_NUM, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto map_count_error;
+	}
+	nlmsg_request = nes_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto map_count_error;
+	}
+
+	/* fill in the pid request message */
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+	nlh->nlmsg_seq = nlmsg_request->nlmsg_seq;
+	err_str = "Unable to put attribute of map count nlmsg";
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
+	if (ret)
+		goto map_count_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32),
+				&mapping_num, IWPM_NLA_MAPINFO_NUMBER);
+	if (ret)
+		goto map_count_error;
+
+	ret = ibnl_unicast(skb, nlh, nes_iwpm_pid);
+	if (ret) {
+		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+		goto map_count_error_exit;
+	}
+	nlmsg_request->mapcount = mapping_num;
+	nlmsg_request->async = 1;
+	nes_start_nlmsg_req_timer(nlmsg_request, nes_nlmsg_req_timer_free,
+					NES_IWPM_NL_TIMEOUT);
+	return 0;
+map_count_error:
+	pr_info("%s: %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+map_count_error_exit:
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * nes_send_nlmsg_done - Send a mapping info message
+ *
+ * Send to the port mapper an skb containing multi netlink messages,
+ * after appending a NLMSG_DONE message to the skb
+ */
+static int nes_send_nlmsg_done(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	int ret;
+	if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_NES,
+				RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
+		pr_info("%s: Unable to put NLMSG_DONE\n", __func__);
+		return -ENOMEM;
+	}
+	nlh->nlmsg_type = NLMSG_DONE;
+	ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, nes_iwpm_pid);
+	if (ret) {
+		nes_iwpm_pid = NES_IWPM_PID_UNDEFINED;
+		nes_debug(NES_DBG_NLMSG, "Unable to send a nlmsg\n");
+	}
+	return ret;
+}
+
+/*
+ * nes_send_mapping_info - Send mapping info records to the iwarp port mapper
+ *
+ * Mapping info message is used for synchronization,
+ * after the port mapper is restarted and doesn't have any mapping info records
+ */
+static int nes_send_mapping_info(void)
+{
+	struct sk_buff *skb = NULL;
+	struct nes_mapping_info *map_info;
+	struct nlmsghdr *nlh;
+	unsigned long flags;
+	int mapping_num = 0;
+	int nlmsg_bytes = 0;
+	int skb_num = 0;
+	const char *err_str = "";
+	int ret;
+
+	skb = dev_alloc_skb(NLMSG_GOODSIZE);
+	if (!skb) {
+		ret = -ENOMEM;
+		err_str = "Unable to allocate skb";
+		goto send_mapping_info_exit;
+	}
+	skb_num++;
+	spin_lock_irqsave(&nes_mapping_lock, flags);
+	list_for_each_entry(map_info, &nes_mapping_info_list, mapping_list) {
+		nlh = NULL;
+		if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_NES,
+				RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
+			ret = -ENOMEM;
+			err_str = "Unable to put the nlmsg header";
+			spin_unlock_irqrestore(&nes_mapping_lock, flags);
+			goto send_mapping_info_exit;
+		}
+		err_str = "Unable to put attribute of the nlmsg";
+		ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&map_info->local_sockaddr, IWPM_NLA_MAPINFO_LOCAL_ADDR);
+		if (ret) {
+			spin_unlock_irqrestore(&nes_mapping_lock, flags);
+			goto send_mapping_info_exit;
+		}
+		ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+				&map_info->mapped_sockaddr, IWPM_NLA_MAPINFO_MAPPED_ADDR);
+		if (ret) {
+			spin_unlock_irqrestore(&nes_mapping_lock, flags);
+			goto send_mapping_info_exit;
+		}
+		mapping_num++;
+		nlmsg_bytes += nlh->nlmsg_len;
+
+		/* check if all mappings can fit in one skb */
+		/* and leave room for NLMSG_DONE */
+		if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len*2) {
+			nlmsg_bytes = 0;
+			skb_num++;
+			nes_debug(NES_DBG_NLMSG, "Allocating skb #%d (mappings = %d nlmsg len = %d)\n",
+					skb_num, mapping_num, nlh->nlmsg_len);
+			spin_unlock_irqrestore(&nes_mapping_lock, flags);
+			/* send the skb */
+			ret = nes_send_nlmsg_done(skb);
+			skb = NULL;
+			if (ret) {
+				err_str = "Unable to send map info";
+				goto send_mapping_info_exit;
+			}
+			if (skb_num == NES_MAP_INFO_SKB_COUNT) {
+				ret = -ENOMEM;
+				err_str = "Insufficient skbs for map info";
+				goto send_mapping_info_exit;
+			}
+			skb = dev_alloc_skb(NLMSG_GOODSIZE);
+			if (!skb) {
+				ret = -ENOMEM;
+				err_str = "Unable to allocate skb";
+				goto send_mapping_info_exit;
+			}
+			spin_lock_irqsave(&nes_mapping_lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&nes_mapping_lock, flags);
+	if (skb)
+		nes_send_nlmsg_done(skb);
+	return mapping_num;
+send_mapping_info_exit:
+	if (skb)
+		dev_kfree_skb(skb);
+	if (ret > 0)
+		ret = -ret;
+	pr_info("%s: %s (ret = %d)\n", __func__, err_str, ret);
+	return ret;
+}
+
+/* netlink attribute policy for the received ack of mapping info */
+static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_COUNT_MAX] = {
+	[IWPM_NLA_MAPINFO_SEQ]    = { .type = NLA_U32 },
+	[IWPM_NLA_MAPINFO_NUMBER] = { .type = NLA_U32 }
+};
+
+/*
+ * nes_ack_mapping_info_cb - Callback routine when acknowledgement is received
+ *			     from the userspace port mapper
+ *
+ * The received netlink message contains the number of mappings the port mapper
+ * has processed
+ */
+static int nes_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_MAPINFO_COUNT_MAX];
+	u32 msg_seq, mapping_num;
+	const char *msg_type = "Mapping Info Ack";
+
+	if (nes_parse_nlmsg(cb, IWPM_NLA_MAPINFO_COUNT_MAX,
+				ack_mapinfo_policy, nltb, msg_type))
+		return -EINVAL;
+	msg_seq = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEQ]);
+	nlmsg_request = nes_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_info("%s: Could not find matching request (seq = %u)\n",
+				 __func__, msg_seq);
+		return -EINVAL;
+	}
+	mapping_num = nla_get_u32(nltb[IWPM_NLA_MAPINFO_NUMBER]);
+	if (nlmsg_request->mapcount != mapping_num)
+		pr_info("%s: Invalid mapinfo count (sent = %u ack-ed = %u)\n",
+				__func__, nlmsg_request->mapcount, mapping_num);
+
+	nes_debug(NES_DBG_NLMSG, "Received ack for mapping count = %u\n", mapping_num);
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	nlmsg_request->request_done = 1;
+	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
+	return 0;
+}
+
+/* netlink attribute policy for the received port mapper error message */
+static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
+	[IWPM_NLA_ERR_SEQ]        = { .type = NLA_U32 },
+	[IWPM_NLA_ERR_CODE]       = { .type = NLA_U16 },
+};
+
+/*
+ * nes_mapping_error_cb - Callback routine when error message is received
+ *			  from the port mapper
+ */
+static int nes_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct nes_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_ERR_MAX];
+	u32 msg_seq;
+	u16 err_code;
+	const char *msg_type = "Mapping Error Msg";
+
+	if (nes_parse_nlmsg(cb, IWPM_NLA_ERR_MAX,
+				map_error_policy, nltb, msg_type))
+		return -EINVAL;
+
+	msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]);
+	err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]);
+	pr_info("%s: Received msg seq = %u err code = %u\n", __func__, msg_seq, err_code);
+	/* look for nlmsg_request */
+	nlmsg_request = nes_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		/* not all errors have associated requests */
+		nes_debug(NES_DBG_NLMSG, "Could not find matching request (seq = %u)\n", msg_seq);
+		return -EINVAL;
+	}
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	nlmsg_request->err_code = err_code;
+	nlmsg_request->request_done = 1;
+	rem_ref_nlmsg_request(nlmsg_request); /* always for found request */
+	barrier();
+	if (!nlmsg_request->async)
+		wake_up(&nlmsg_request->waitq);
+	return 0;
+}
diff --git a/drivers/infiniband/hw/nes/nes_netlink.h b/drivers/infiniband/hw/nes/nes_netlink.h
new file mode 100644
index 0000000..8fde524
--- /dev/null
+++ b/drivers/infiniband/hw/nes/nes_netlink.h
@@ -0,0 +1,108 @@ 
+/*
+* Copyright (c) 2013 Intel Corporation. All rights reserved.
+*
+* This software is available to you under a choice of one of two
+* licenses.  You may choose to be licensed under the terms of the GNU
+* 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.
+*/
+
+#ifndef __NES_NETLINK_H
+#define __NES_NETLINK_H
+
+#include <rdma/rdma_netlink.h>
+#include <linux/errno.h>
+
+#define NES_IWPM_PID_UNDEFINED    -1
+#define NES_IWPM_PID_UNAVAILABLE  -2
+#define NES_IWPM_PID_ERROR        -3
+
+#define NES_IWPM_NL_TIMEOUT     (10*HZ)
+#define NES_MAP_INFO_SKB_COUNT  100
+
+#define IWPM_ULIBNAME_SIZE 32
+#define IWPM_DEVNAME_SIZE  32
+#define IWPM_IFNAME_SIZE   16
+
+extern struct list_head nes_nlmsg_request_list;
+extern struct list_head nes_mapping_info_list;
+extern spinlock_t nes_nlmsg_lock;
+extern spinlock_t nes_mapping_lock;
+extern atomic_t nes_nlmsg_seq;
+extern atomic_t echo_nlmsg_seq;
+extern char nes_ifname[IWPM_IFNAME_SIZE];
+extern char nes_ibdev[IWPM_DEVNAME_SIZE];
+
+extern struct ibnl_client_cbs nes_nl_cb_table[];
+extern int nes_iwpm_pid;
+
+struct nes_nlmsg_request {
+	struct list_head inprocess_list;
+	__u32            nlmsg_seq;
+	void             *request_buffer;
+	u8               request_done;
+	u8               async;
+	union {
+		wait_queue_head_t  waitq;
+		struct timer_list  service_timer;
+	};
+
+	atomic_t  refcount;
+	u16       err_code;
+	int       mapcount;
+
+};
+
+struct nes_mapping_info {
+	struct list_head mapping_list;
+	struct sockaddr_in local_sockaddr;
+	struct sockaddr_in mapped_sockaddr;
+};
+
+enum {
+	IWPM_INVALID_NLMSG_ERR = 10,
+	IWPM_CREATE_MAPPING_ERR,
+	IWPM_DUPLICATE_MAPPING_ERR,
+	IWPM_UNKNOWN_MAPPING_ERR,
+	IWPM_CLIENT_DEV_INFO_ERR,
+	IWPM_USER_LIB_INFO_ERR,
+	IWPM_REMOTE_QUERY_REJECT
+};
+
+struct nes_cm_info;
+struct nes_vnic;
+
+int nes_register_iwpm_pid(char *, char *, int, void (*req_timer_func)(unsigned long));
+int nes_add_mapping(struct nes_cm_info *);
+int nes_add_and_query_mapping(struct nes_cm_info *);
+int nes_remove_mapping(u32, u16);
+void nes_create_sockaddr(__be32, __be16, struct sockaddr_in *);
+int nes_create_mapinfo(struct sockaddr_in *, struct sockaddr_in *);
+int nes_remove_mapinfo(struct sockaddr_in *);
+void nes_destroy_mapinfo_list(void);
+void print_iwpm_available(int);
+
+#endif /* __NES_NETLINK_H */
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 49eb511..e140c5b 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -94,6 +94,9 @@  static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
 static int debug = -1;
 static int nics_per_function = 1;
 
+char nes_ifname[IWPM_IFNAME_SIZE];
+char nes_ibdev[IWPM_DEVNAME_SIZE];
+
 /**
  * nes_netdev_poll
  */
@@ -266,6 +269,8 @@  static int nes_netdev_open(struct net_device *netdev)
 	napi_enable(&nesvnic->napi);
 	nesvnic->netdev_open = 1;
 
+	memcpy(nes_ifname, nesvnic->netdev->name, IWPM_IFNAME_SIZE);
+	memcpy(nes_ibdev, nesvnic->nesibdev->ibdev.name, IWPM_DEVNAME_SIZE);
 	return 0;
 }