diff mbox

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

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

Commit Message

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

Signed-off-by: Vipul Pandya <vipul@chelsio.com>

---
 drivers/infiniband/hw/cxgb4/Makefile       |    2 +-
 drivers/infiniband/hw/cxgb4/c4iw_netlink.c | 1021 ++++++++++++++++++++++++++++
 drivers/infiniband/hw/cxgb4/c4iw_netlink.h |  273 ++++++++
 drivers/infiniband/hw/cxgb4/cm.c           |  138 ++++-
 drivers/infiniband/hw/cxgb4/device.c       |   24 +-
 drivers/infiniband/hw/cxgb4/iw_cxgb4.h     |   16 +
 6 files changed, 1448 insertions(+), 26 deletions(-)
 create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.c
 create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.h

Comments

Steve Wise Sept. 3, 2013, 4:14 p.m. UTC | #1
On 8/31/2013 2:47 PM, Tatyana Nikolova wrote:
> Add support for iWARP Port Mapper (IWPM) user space service

nit: This should probably have a From: Vipul... line.

more comments below:

> Signed-off-by: Vipul Pandya <vipul@chelsio.com>
>
> ---
>   drivers/infiniband/hw/cxgb4/Makefile       |    2 +-
>   drivers/infiniband/hw/cxgb4/c4iw_netlink.c | 1021 ++++++++++++++++++++++++++++
>   drivers/infiniband/hw/cxgb4/c4iw_netlink.h |  273 ++++++++
>   drivers/infiniband/hw/cxgb4/cm.c           |  138 ++++-
>   drivers/infiniband/hw/cxgb4/device.c       |   24 +-
>   drivers/infiniband/hw/cxgb4/iw_cxgb4.h     |   16 +
>   6 files changed, 1448 insertions(+), 26 deletions(-)
>   create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.c
>   create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.h
>
> diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile
> index e11cf72..7e4d948 100644
> --- a/drivers/infiniband/hw/cxgb4/Makefile
> +++ b/drivers/infiniband/hw/cxgb4/Makefile
> @@ -2,4 +2,4 @@ ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4
>   
>   obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
>   
> -iw_cxgb4-y :=  device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o
> +iw_cxgb4-y :=  device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o c4iw_netlink.o
> diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.c b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c
> new file mode 100644
> index 0000000..001c0e3
> --- /dev/null
> +++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c
> @@ -0,0 +1,1021 @@
> +/*
> + * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other  materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/mii.h>
> +#include <linux/if_vlan.h>
> +#include <linux/crc32.h>
> +#include <linux/in.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/if_arp.h>
> +#include <linux/highmem.h>
> +#include <linux/io.h>
> +#include <asm/irq.h>
> +#include <asm/byteorder.h>
> +#include <rdma/ib_smi.h>
> +#include <rdma/ib_verbs.h>
> +#include <rdma/ib_pack.h>
> +#include <rdma/iw_cm.h>
> +#include <net/netlink.h>
> +
> +#include "iw_cxgb4.h"
> +#include "c4iw_netlink.h"
> +
> +spinlock_t c4iw_nlmsg_lock;
> +struct list_head c4iw_nlmsg_request_list;
> +struct list_head c4iw_mapping_info_list;
> +spinlock_t c4iw_mapping_lock;
> +atomic_t c4iw_nlmsg_seq;
> +atomic_t echo_nlmsg_seq;
> +
> +int c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
> +static char iwpm_ulib_name[] = "iWarpPortMapperUser";
> +static int iwpm_ulib_version = 3;
> +
> +static char c4iw_ifname[IWPM_IFNAME_SIZE];
> +static char c4iw_ibdev[IWPM_DEVNAME_SIZE];
> +
> +static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void);
> +static int c4iw_send_mapping_info(void);
> +static int c4iw_send_mapping_count(u32);
> +static int c4iw_parse_nlmsg(struct netlink_callback *, int,
> +			    const struct nla_policy *, struct nlattr *[],
> +			    const char *);
> +
> +/* c4iw netlink callbacks */
> +static int c4iw_register_iwpm_pid_cb(struct sk_buff *,
> +				     struct netlink_callback *);
> +static int c4iw_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
> +static int c4iw_add_and_query_mapping_cb(struct sk_buff *,
> +					 struct netlink_callback *);
> +static int c4iw_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
> +static int c4iw_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
> +static int c4iw_ack_mapping_info_cb(struct sk_buff *,
> +				    struct netlink_callback *);
> +
> +static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void)
> +{
> +	unsigned long flags;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +
> +	nlmsg_request = kzalloc(sizeof(struct c4iw_nlmsg_request), GFP_ATOMIC);
> +	if (!nlmsg_request) {
> +		pr_err("%s Unable to allocate a nlmsg_request\n", __func__);
> +		return NULL;
> +	}
> +	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
> +	list_add_tail(&nlmsg_request->inprocess_list, &c4iw_nlmsg_request_list);
> +	spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags);
> +

 From what I can tell, c4iw_get_nlmsg_request() is never called in an 
interrupt context, so you can alloc with GFP_KERNEL.  Also, you could 
change the spin lock c4iw_nlmsg_lock to a mutex.  btw this same comment 
applies to nes_get_nlmsg_request().

> +	atomic_set(&nlmsg_request->refcount, 1);
> +	nlmsg_request->nlmsg_seq = atomic_inc_return(&c4iw_nlmsg_seq);
> +	nlmsg_request->request_done = 0;
> +	nlmsg_request->async = 0;
> +	nlmsg_request->err_code = 0;
> +	return nlmsg_request;
> +}
> +
> +static int c4iw_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 = c4iw_validate_nlmsg_attr(nltb, policy_max);
> +	if (ret) {
> +		err_str = "Invalid NULL attribute";
> +		goto parse_nlmsg_error;
> +	}
> +	return 0;
> +parse_nlmsg_error:
> +	pr_warn("%s %s (msg type %s ret = %d)\n",
> +		__func__, err_str, msg_type, ret);
> +	return ret;
> +}
> +
> +static void c4iw_nlmsg_req_timer_free(unsigned long data)
> +{
> +	struct c4iw_nlmsg_request *nlmsg_request = (struct c4iw_nlmsg_request *)
> +						    data;
> +
> +	if (!nlmsg_request->request_done && !nlmsg_request->err_code)
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNAVAILABLE;
> +
> +	if (c4iw_iwpm_pid < 0)
> +		pr_info("%s Port Mapper isn't available (err code = %d)\n"
> +			, __func__, nlmsg_request->err_code);
> +	rem_ref_nlmsg_request(nlmsg_request);
> +}
> +
> +static void c4iw_mapinfo_timer_send(unsigned long data)
> +{
> +	int mapping_num;
> +
> +	c4iw_nlmsg_req_timer_free(data);
> +
> +	if (c4iw_iwpm_pid < 0)
> +		return;
> +	mapping_num = c4iw_send_mapping_info();
> +	if (mapping_num < 0) {
> +		pr_info("%s Unable to send mapping info\n", __func__);
> +		return;
> +	}
> +	PDBG("%s Sending Mapping count msg (num = %d)\n", __func__
> +	     , mapping_num);
> +
> +	c4iw_send_mapping_count(mapping_num);
> +}
> +
> +static void c4iw_start_nlmsg_req_timer(struct c4iw_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);
> +}
> +
> +/*
> + * 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 c4iw_register_iwpm_pid(char *netdev_name, char *dev_name, int async,
> +			   void (*req_timer_func)(unsigned long))
> +{
> +	struct sk_buff *skb = NULL;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_REG_PID, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto pid_query_error;
> +	}
> +	nlmsg_request = c4iw_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, iwpm_ulib_name,
> +			    IWPM_NLA_REG_ULIB_NAME);
> +	if (ret)
> +		goto pid_query_error;
> +	memcpy(c4iw_ibdev, dev_name, IWPM_DEVNAME_SIZE);
> +	memcpy(c4iw_ifname, netdev_name, IWPM_IFNAME_SIZE);
> +	PDBG("%s Multicasting a nlmsg (echo seq = %u ibdevname = %s ifname = %s iwpm ulib name = %s) nlmsg len = %d request seq = %u\n"
> +	     , __func__, msg_seq, dev_name, netdev_name, iwpm_ulib_name
> +	     , nlh->nlmsg_len, nlmsg_request->nlmsg_seq);
> +
> +	ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
> +	if (ret) {
> +		skb = NULL; /* already freed in the netlink send-op handling */
> +		err_str = "Unable to send a nlmsg";
> +		goto pid_query_error;
> +	}
> +	nlmsg_request->async = async;
> +	if (async)
> +		c4iw_start_nlmsg_req_timer(nlmsg_request, req_timer_func,
> +					   C4IW_IWPM_NL_TIMEOUT);
> +	else
> +		ret = wait_complete_nlmsg_req(nlmsg_request,
> +					      C4IW_IWPM_PID_UNAVAILABLE);
> +	return ret;
> +pid_query_error:
> +	pr_warn("%s %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * Send a netlink add mapping request
> + * for the listener ip/tcp address to the userspace port mapper
> + * nlmsg attributes:
> + *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
> + *	[IWPM_NLA_MANAGE_ADDR]
> + */
> +int c4iw_add_mapping(struct c4iw_listen_ep *ep)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in *laddr = (struct sockaddr_in *)
> +				    &ep->com.local_addr;
> +	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)
> +				      &ep->com.local_addr;
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto add_mapping_error;
> +	}
> +
> +	nlmsg_request = c4iw_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto add_mapping_error;
> +	}
> +
> +	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),
> +			    &ep->com.local_addr, IWPM_NLA_MANAGE_ADDR);
> +	if (ret)
> +		goto add_mapping_error;
> +
> +	nlmsg_request->request_buffer = ep;
> +	if (ep->com.local_addr.ss_family == AF_INET)
> +		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) request seq = %u\n"
> +		     , __func__, msg_seq, &laddr->sin_addr.s_addr
> +		     , ntohs(laddr->sin_port), nlmsg_request->nlmsg_seq);
> +	else
> +		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) request seq = %u\n"
> +		     , __func__, msg_seq, &laddr6->sin6_addr.s6_addr
> +		     , ntohs(laddr6->sin6_port), nlmsg_request->nlmsg_seq);
> +
> +	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
> +	if (ret) {
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; /* ret = -111 */
> +		skb = NULL; /* already freed in the netlink send-op handling */
> +		err_str = "Unable to send a nlmsg";
> +		goto add_mapping_error;
> +	}
> +	ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED);
> +	return ret;
> +add_mapping_error:
> +	pr_warn("%s %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * Send both a netlink add mapping request for the connecting
> + * side ip/tcp address and a query for the accepting remote peer
> + * mapped 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 c4iw_add_and_query_mapping(struct c4iw_ep *ep)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in *laddr = (struct sockaddr_in *)
> +				     &ep->com.local_addr;
> +	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)
> +				      &ep->com.local_addr;
> +	struct sockaddr_in *raddr = (struct sockaddr_in *)
> +				     &ep->com.remote_addr;
> +	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)
> +				      &ep->com.remote_addr;
> +	const char *err_str = "";
> +	int ret = -ENOMEM;
> +
> +	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto query_mapping_error;
> +	}
> +	nlmsg_request = c4iw_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto query_mapping_error;
> +	}
> +
> +	msg_seq = atomic_read(&echo_nlmsg_seq);
> +	/* 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),
> +			    &ep->com.local_addr,
> +			    IWPM_NLA_QUERY_LOCAL_ADDR);
> +	if (ret)
> +		goto query_mapping_error;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
> +			    &ep->com.remote_addr,
> +			    IWPM_NLA_QUERY_REMOTE_ADDR);
> +	if (ret)
> +		goto query_mapping_error;
> +
> +	nlmsg_request->request_buffer = ep;
> +	if (ep->com.local_addr.ss_family == AF_INET)
> +		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) Remote addr %pI4 [0x%04X]) request seq = %u\n"
> +		     , __func__, msg_seq, &laddr->sin_addr.s_addr
> +		     , ntohs(laddr->sin_port), &raddr->sin_addr.s_addr
> +		     , ntohs(raddr->sin_port), nlmsg_request->nlmsg_seq);
> +	else
> +		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) Remote addr %pI6 [0x%04X]) request seq = %u\n"
> +		     , __func__, msg_seq, &laddr6->sin6_addr.s6_addr
> +		     , ntohs(laddr6->sin6_port), &raddr6->sin6_addr.s6_addr
> +		     , ntohs(raddr6->sin6_port), nlmsg_request->nlmsg_seq);
> +
> +	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
> +	if (ret) {
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
> +		skb = NULL; /* already freed in the netlink send-op handling */
> +		err_str = "Unable to send a nlmsg";
> +		goto query_mapping_error;
> +	}
> +	ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED);
> +	return ret;
> +query_mapping_error:
> +	pr_warn("%s %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +/*
> + * Send a netlink remove mapping request to the userspace port mapper
> + * nlmsg attributes:
> + *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
> + *	[IWPM_NLA_MANAGE_ADDR]
> + */
> +int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr)
> +{
> +	struct sk_buff *skb;
> +	struct nlmsghdr *nlh;
> +	struct nlmsghdr **nlh_next = &nlh;
> +	u32 msg_seq;
> +	struct sockaddr_in *mapped_la = (struct sockaddr_in *)
> +					mapped_local_addr;
> +	struct sockaddr_in6 *mapped_la6 = (struct sockaddr_in6 *)
> +					  mapped_local_addr;
> +	const char *err_str = "";
> +	int ret;
> +
> +	if (c4iw_remove_mapinfo(mapped_local_addr)) {
> +		if (mapped_local_addr->ss_family == AF_INET)
> +			pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n"
> +				, __func__, ntohs(mapped_la->sin_port));
> +		else
> +			pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n"
> +				, __func__, ntohs(mapped_la6->sin6_port));
> +		return -EINVAL;
> +	}
> +	if (c4iw_iwpm_pid < 0)
> +		return 0;
> +
> +	skb = c4iw_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(&c4iw_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_local_addr, IWPM_NLA_MANAGE_ADDR);
> +	if (ret)
> +		goto remove_mapping_error;
> +
> +	if (mapped_local_addr->ss_family == AF_INET)
> +		PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI4 [0x%04X])\n"
> +		     , __func__, msg_seq, &mapped_la->sin_addr.s_addr
> +		     , ntohs(mapped_la->sin_port));
> +	else
> +		PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI6 [0x%04X])\n"
> +		     , __func__, msg_seq, mapped_la6->sin6_addr.s6_addr
> +		     , ntohs(mapped_la6->sin6_port));
> +
> +	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
> +	if (ret) {
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
> +		skb = NULL;
> +		err_str = "Unable to send a nlmsg";
> +		goto remove_mapping_error;
> +	}
> +	return 0;
> +remove_mapping_error:
> +	pr_warn("%s %s\n", __func__, err_str);
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	return ret;
> +}
> +
> +/* registered netlink c4iw callbacks */
> +struct ibnl_client_cbs c4iw_nl_cb_table[] = {
> +	[RDMA_NL_IWPM_REG_PID] = {.dump = c4iw_register_iwpm_pid_cb},
> +	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = c4iw_add_mapping_cb},
> +	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = c4iw_add_and_query_mapping_cb},
> +	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = c4iw_mapping_error_cb},
> +	[RDMA_NL_IWPM_MAP_INFO] = {.dump = c4iw_mapping_info_cb},
> +	[RDMA_NL_IWPM_MAP_INFO_NUM] = {.dump = c4iw_ack_mapping_info_cb}
> +};
> +
> +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 }
> +};
> +
> +static int c4iw_register_iwpm_pid_cb(struct sk_buff *skb,
> +				     struct netlink_callback *cb)
> +{
> +	struct c4iw_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";
> +
> +	c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
> +
> +	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_warn("%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(c4iw_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;
> +	}
> +	PDBG("%s Received info (dev = %s name = %s version = %d) request seq = %u\n"
> +	     , __func__, dev_name, iwpm_name, iwpm_version
> +	     , nlmsg_request->nlmsg_seq);
> +
> +	c4iw_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__, c4iw_iwpm_pid);
> +register_pid_response_exit:
> +	nlmsg_request->request_done = 1;
> +	/* always for found nlmsg_request */
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	barrier();
> +	if (!nlmsg_request->async)
> +		wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +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 }
> +};
> +
> +static int c4iw_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct c4iw_listen_ep *ep;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
> +	u32 msg_seq;
> +	struct sockaddr_storage *local_sockaddr, *mapped_sockaddr;
> +	const char *msg_type;
> +
> +	msg_type = "Add Mapping response";
> +	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_warn("%s Could not find a matching request (seq = %u)\n"
> +			, __func__, msg_seq);
> +		return -EINVAL;
> +	}
> +	ep = nlmsg_request->request_buffer;
> +	local_sockaddr = (struct sockaddr_storage *)
> +			 nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
> +	mapped_sockaddr = (struct sockaddr_storage *)
> +			  nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
> +
> +	if (memcmp(&ep->com.local_addr, local_sockaddr,
> +		   sizeof(ep->com.local_addr))) {
> +		print_addr(&ep->com.local_addr,
> +			   "Invalid ip/tcp address Local: expected");
> +		print_addr(local_sockaddr,
> +			   "Invalid ip/tcp address Local: received");
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto add_mapping_response_exit;
> +	}
> +
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	memcpy(&ep->com.mapped_local_addr, mapped_sockaddr,
> +	       sizeof(ep->com.mapped_local_addr));
> +add_mapping_response_exit:
> +	print_addr(mapped_sockaddr, "Received a new mapping mapped local");
> +	nlmsg_request->request_done = 1;
> +	/* always for found nlmsg_request */
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	barrier();
> +	wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +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 }
> +};
> +
> +static int c4iw_add_and_query_mapping_cb(struct sk_buff *skb,
> +					 struct netlink_callback *cb)
> +{
> +	struct c4iw_ep *ep;
> +	struct c4iw_nlmsg_request *nlmsg_request = NULL;
> +	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
> +	u32 msg_seq;
> +	struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
> +	struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
> +	struct sockaddr_in *laddr;
> +	struct sockaddr_in6 *laddr6;
> +	struct sockaddr_in *raddr;
> +	struct sockaddr_in6 *raddr6;
> +	struct sockaddr_in *map_laddr;
> +	struct sockaddr_in6 *map_laddr6;
> +	struct sockaddr_in *map_raddr;
> +	struct sockaddr_in6 *map_raddr6;
> +	const char *msg_type;
> +	u16 err_code;
> +
> +	msg_type = "Query Mapping response";
> +	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_warn("%s Could not find a matching request (seq = %u)\n"
> +			, __func__, msg_seq);
> +			return -EINVAL;
> +	}
> +	ep = nlmsg_request->request_buffer;
> +	local_sockaddr = (struct sockaddr_storage *)
> +			  nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
> +	remote_sockaddr = (struct sockaddr_storage *)
> +			   nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
> +	mapped_loc_sockaddr = (struct sockaddr_storage *)
> +			       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
> +	mapped_rem_sockaddr = (struct sockaddr_storage *)
> +			       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
> +	map_laddr = (struct sockaddr_in *)mapped_loc_sockaddr;
> +	map_laddr6 = (struct sockaddr_in6 *)mapped_loc_sockaddr;
> +	map_raddr = (struct sockaddr_in *)mapped_rem_sockaddr;
> +	map_raddr6 = (struct sockaddr_in6 *) mapped_rem_sockaddr;
> +	laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr;
> +	laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
> +	raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
> +	raddr6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;
> +
> +	err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
> +	if (err_code == IWPM_REMOTE_QUERY_REJECT) {
> +		pr_info("%s Received a Query Reject nlmsg. nlmsg (pid = %u, seq = %u) echo seq = %u.\n"
> +			, __func__, cb->nlh->nlmsg_pid, cb->nlh->nlmsg_seq
> +			, msg_seq);
> +		nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
> +	}
> +	if (memcmp(&ep->com.local_addr, local_sockaddr,
> +		   sizeof(ep->com.local_addr) != 0) ||
> +	    memcmp(&ep->com.remote_addr, remote_sockaddr,
> +		   sizeof(ep->com.remote_addr) != 0)) {
> +		print_addr(&ep->com.local_addr,
> +			   "Invalid ip/tcp address Local: expected");
> +		print_addr(local_sockaddr,
> +			   "Invalid ip/tcp address Local: received");
> +		print_addr(&ep->com.remote_addr,
> +			   "Invalid ip/tcp address Remote: expected");
> +		print_addr(remote_sockaddr,
> +			   "Invalid ip/tcp address Remote: received");
> +		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
> +		goto query_mapping_response_exit;
> +	}
> +
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	if (ep->com.local_addr.ss_family == AF_INET) {
> +		laddr->sin_addr.s_addr = map_laddr->sin_addr.s_addr,
> +		laddr->sin_port = map_laddr->sin_port;
> +		raddr->sin_addr.s_addr = map_raddr->sin_addr.s_addr,
> +		raddr->sin_port = map_raddr->sin_port;
> +	} else {
> +		memcpy(laddr6->sin6_addr.s6_addr, map_laddr6->sin6_addr.s6_addr,
> +		       IWPM_IPADDR_SIZE);
> +		laddr6->sin6_port = map_laddr6->sin6_port;
> +		memcpy(raddr6->sin6_addr.s6_addr, map_raddr6->sin6_addr.s6_addr,
> +		       IWPM_IPADDR_SIZE);
> +		raddr6->sin6_port = map_raddr6->sin6_port;
> +	}
> +query_mapping_response_exit:
> +	print_addr(mapped_loc_sockaddr, "Received a new mapping mapped local");
> +	print_addr(mapped_rem_sockaddr, "Received a new mapping mapped remote");
> +	nlmsg_request->request_done = 1;
> +	/* always for found nlmsg_request */
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	barrier();
> +	wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> +
> +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 }
> +};
> +
> +static int c4iw_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 (c4iw_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(&c4iw_mapping_info_list))
> +		req_timer_func = &c4iw_nlmsg_req_timer_free;
> +	else
> +		req_timer_func = &c4iw_mapinfo_timer_send;
> +
> +	c4iw_register_iwpm_pid(c4iw_ifname, c4iw_ibdev, async, req_timer_func);
> +	return 0;
> +}
> +
> +static int c4iw_send_mapping_count(u32 mapping_num)
> +{
> +	struct c4iw_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 = c4iw_create_nlmsg(RDMA_NL_IWPM_MAP_INFO_NUM, nlh_next);
> +	if (!skb) {
> +		err_str = "Unable to create a nlmsg";
> +		goto mapping_count_exit;
> +	}
> +	nlmsg_request = c4iw_get_nlmsg_request();
> +	if (!nlmsg_request) {
> +		err_str = "Unable to allocate netlink request";
> +		goto mapping_count_exit;
> +	}
> +
> +	/* 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 mapping_count_exit;
> +	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &mapping_num,
> +			    IWPM_NLA_MAPINFO_NUMBER);
> +	if (ret)
> +		goto mapping_count_exit;
> +
> +	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
> +	if (ret) {
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
> +		/* already freed in the netlink send-op handling */
> +		skb = NULL;
> +		err_str = "Unable to send a nlmsg";
> +		goto mapping_count_exit;
> +	}
> +	nlmsg_request->mapcount = mapping_num;
> +	nlmsg_request->async = 1;
> +	c4iw_start_nlmsg_req_timer(nlmsg_request, c4iw_nlmsg_req_timer_free,
> +				   C4IW_IWPM_NL_TIMEOUT);
> +	return 0;
> +mapping_count_exit:
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (nlmsg_request)
> +		free_nlmsg_request(nlmsg_request);
> +	pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret);
> +	return ret;
> +}
> +
> +static int c4iw_send_nlmsg_done(struct sk_buff *skb)
> +{
> +	struct nlmsghdr *nlh = NULL;
> +	int ret;
> +	if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW,
> +			   RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
> +		pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
> +		return -ENOMEM;
> +	}
> +	nlh->nlmsg_type = NLMSG_DONE;
> +	ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, c4iw_iwpm_pid);
> +	if (ret) {
> +		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
> +		pr_warn("%s Unable to send a nlmsg\n", __func__);
> +	}
> +	return ret;
> +}
> +
> +static int c4iw_send_mapping_info(void)
> +{
> +	struct sk_buff *skb = NULL;
> +	struct c4iw_mapping_info *map_info;
> +	struct nlmsghdr *nlh;
> +	int skb_num = 0, mapping_num = 0, nlmsg_bytes = 0;
> +	unsigned long flags;
> +	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(&c4iw_mapping_lock, flags);
> +	list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) {
> +		nlh = NULL;
> +		if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW,
> +				   RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
> +			ret = -ENOMEM;
> +			err_str = "Unable to put the nlmsg header";
> +			spin_unlock_irqrestore(&c4iw_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(&c4iw_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(&c4iw_mapping_lock, flags);
> +			goto send_mapping_info_exit;
> +		}
> +		mapping_num++;
> +		nlmsg_bytes += nlh->nlmsg_len;
> +
> +		/* check if all mappings can fit in one skb */
> +		if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len*2) {
> +			nlmsg_bytes = 0;
> +			skb_num++;
> +			PDBG("%s Mappings Sent %d (nlmsg_bytes = %d nlmsg_len = %d). Allocating another skb (num = %d size = %lu)\n"
> +			     , __func__, mapping_num, nlmsg_bytes
> +			     , nlh->nlmsg_len, skb_num
> +			     , NLMSG_GOODSIZE);
> +			/* and leave room for NLMSG_DONE */
> +			spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
> +			/* send the skb */
> +			ret = c4iw_send_nlmsg_done(skb);
> +			skb = NULL;
> +			if (ret) {
> +				err_str = "Unable to send map info";
> +				goto send_mapping_info_exit;
> +			}
> +			if (skb_num == C4IW_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(&c4iw_mapping_lock, flags);
> +		}
> +	}
> +	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
> +	if (skb)
> +		c4iw_send_nlmsg_done(skb);
> +	return mapping_num;
> +send_mapping_info_exit:
> +	if (skb)
> +		dev_kfree_skb(skb);
> +	if (ret > 0)
> +		ret = -ret;
> +	pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret);
> +	return ret;
> +}
> +
> +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 }
> +};
> +
> +static int c4iw_ack_mapping_info_cb(struct sk_buff *skb,
> +				    struct netlink_callback *cb)
> +{
> +	struct c4iw_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 (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		pr_warn("%s Could not find a matching request with 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 map info count (sent = %u ack-ed = %u)\n"
> +			, __func__, nlmsg_request->mapcount, mapping_num);
> +	}
> +	PDBG("%s Received ack for mapping count = %u\n", __func__, mapping_num);
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	nlmsg_request->request_done = 1;
> +	/* always for found nlmsg_request */
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	return 0;
> +}
> +
> +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 },
> +};
> +
> +static int c4iw_mapping_error_cb(struct sk_buff *skb,
> +				 struct netlink_callback *cb)
> +{
> +	struct c4iw_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 (c4iw_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_warn("%s Received msg_seq = %u err_code = %u\n"
> +		, __func__, msg_seq, err_code);
> +	/* look for nlmsg_request */
> +	nlmsg_request = c4iw_find_nlmsg_request(msg_seq);
> +	if (!nlmsg_request) {
> +		/* not all errors have associated requests */
> +		PDBG("%s Could not find a matching request with seq = %u\n"
> +		     , __func__, msg_seq);
> +		return -EINVAL;
> +	}
> +	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
> +	nlmsg_request->err_code = err_code;
> +	nlmsg_request->request_done = 1;
> +	/* always for found nlmsg_request */
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	barrier();
> +	if (!nlmsg_request->async)
> +		wake_up(&nlmsg_request->waitq);
> +	return 0;
> +}
> diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.h b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h
> new file mode 100644
> index 0000000..aa1b66c
> --- /dev/null
> +++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h
> @@ -0,0 +1,273 @@
> +/*
> + * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other  materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#ifndef __C4IW_NETLINK_H
> +#define __C4IW_NETLINK_H
> +
> +#include <rdma/rdma_netlink.h>
> +#include <linux/errno.h>
> +
> +#define C4IW_IWPM_PID_UNDEFINED    -1
> +#define C4IW_IWPM_PID_UNAVAILABLE  -2
> +#define C4IW_IWPM_PID_ERROR	   -3
> +
> +#define C4IW_IWPM_NL_RETRANS	3
> +#define C4IW_IWPM_NL_TIMEOUT     10000
> +#define C4IW_MAP_INFO_SKB_COUNT  20
> +
> +#define IWPM_ULIBNAME_SIZE 32
> +#define IWPM_DEVNAME_SIZE  32
> +#define IWPM_IFNAME_SIZE   16
> +#define IWPM_IPADDR_SIZE   16
> +
> +extern struct list_head c4iw_nlmsg_request_list;
> +extern struct list_head c4iw_mapping_info_list;
> +extern spinlock_t c4iw_nlmsg_lock;
> +extern spinlock_t c4iw_mapping_lock;
> +extern atomic_t c4iw_nlmsg_seq;
> +extern atomic_t echo_nlmsg_seq;
> +
> +extern struct ibnl_client_cbs c4iw_nl_cb_table[];
> +extern int c4iw_iwpm_pid;
> +
> +struct c4iw_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 c4iw_mapping_info {
> +	struct list_head mapping_list;
> +	struct sockaddr_storage local_sockaddr;
> +	struct sockaddr_storage 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
> +};
> +
> +int c4iw_register_iwpm_pid(char *, char *, int,
> +			   void (*req_timer_func)(unsigned long));
> +int c4iw_add_mapping(struct c4iw_listen_ep *ep);
> +int c4iw_add_and_query_mapping(struct c4iw_ep *ep);
> +int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr);
> +void c4iw_timer_send_mapinfo(unsigned long);
> +
> +static inline int c4iw_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;
> +}
> +
> +static inline void c4iw_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;
> +}
> +
> +static inline struct sk_buff *c4iw_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_C4IW, nl_op,
> +			   NLM_F_REQUEST))) {
> +		pr_warn("%s Unable to put the nlmsg header\n", __func__);
> +		dev_kfree_skb(skb);
> +		skb = NULL;
> +	}
> +create_nlmsg_exit:
> +	return skb;
> +}
> +
> +static inline void free_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
> +	list_del_init(&nlmsg_request->inprocess_list);
> +	spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags);
> +
> +	if (nlmsg_request->async)
> +		del_timer(&nlmsg_request->service_timer);
> +
> +	if (!nlmsg_request->request_done)
> +		pr_warn("%s Freeing incomplete nlmsg request (seq = %u).\n",
> +			__func__, nlmsg_request->nlmsg_seq);
> +	kfree(nlmsg_request);
> +}
> +
> +static void rem_ref_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request)
> +{
> +	if (atomic_dec_and_test(&nlmsg_request->refcount))
> +		free_nlmsg_request(nlmsg_request);
> +}
> +

This looks like a candidate to use krefs.

> +static inline int wait_complete_nlmsg_req(struct c4iw_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),
> +				 C4IW_IWPM_NL_TIMEOUT);
> +	if (!ret) {
> +		c4iw_iwpm_pid = iwpm_pid;
> +		pr_warn("%s: Timeout %d sec for netlink request (seq = %u)\n"
> +			, __func__, (C4IW_IWPM_NL_TIMEOUT/HZ)
> +			, nlmsg_request->nlmsg_seq);
> +	} else
> +		ret = nlmsg_request->err_code;
> +
> +	rem_ref_nlmsg_request(nlmsg_request);
> +	return ret;
> +}
> +
> +static inline struct c4iw_nlmsg_request *c4iw_find_nlmsg_request(__u32 echo_seq)
> +{
> +	struct c4iw_nlmsg_request *nlmsg_request;
> +	struct c4iw_nlmsg_request *found_request = NULL;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
> +	list_for_each_entry(nlmsg_request, &c4iw_nlmsg_request_list,
> +			    inprocess_list) {
> +		PDBG("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(&c4iw_nlmsg_lock, flags);
> +	return found_request;
> +}
> +
> +static inline int c4iw_create_mapinfo(struct sockaddr_storage *local_sockaddr,
> +				      struct sockaddr_storage *mapped_sockaddr,
> +				      const char *msg_type)
> +{
> +	struct c4iw_mapping_info *map_info;
> +	unsigned long flags;
> +
> +	map_info = kzalloc(sizeof(struct c4iw_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_storage));
> +	memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
> +	       sizeof(struct sockaddr_storage));
> +
> +	spin_lock_irqsave(&c4iw_mapping_lock, flags);
> +	list_add_tail(&map_info->mapping_list, &c4iw_mapping_info_list);
> +	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
> +
> +	return 0;
> +}
> +
> +static inline int c4iw_remove_mapinfo(struct sockaddr_storage
> +				      *mapped_local_addr)
> +{
> +	struct c4iw_mapping_info *map_info = NULL;
> +	unsigned long flags;
> +	int ret = -EINVAL;
> +	const char *msg = "Remove mapped";
> +
> +	print_addr(mapped_local_addr, msg);
> +
> +	spin_lock_irqsave(&c4iw_mapping_lock, flags);
> +	list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) {
> +		print_addr(&map_info->mapped_sockaddr
> +			   , "Going through mapinfo mapped local");
> +		if (!memcmp(&map_info->mapped_sockaddr,	mapped_local_addr,
> +			    sizeof(struct sockaddr_storage))) {
> +			list_del_init(&map_info->mapping_list);
> +			kfree(map_info);
> +			ret = 0;
> +			break;
> +		}
> +	}
> +	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
> +	return ret;
> +}
> +
> +static inline void c4iw_destroy_mapinfo_list(void)
> +{
> +	struct c4iw_mapping_info *map_info, *map_info_tmp;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&c4iw_mapping_lock, flags);
> +	list_for_each_entry_safe(map_info, map_info_tmp,
> +				 &c4iw_mapping_info_list, mapping_list) {
> +		print_addr(&map_info->mapped_sockaddr,
> +			   "Delete mapinfo mapped local");
> +		list_del(&map_info->mapping_list);
> +		kfree(map_info);
> +	}
> +	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
> +}
> +
> +#endif /* __C4IW_NETLINK_H */
> diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
> index 12fef76..b8e2117 100644
> --- a/drivers/infiniband/hw/cxgb4/cm.c
> +++ b/drivers/infiniband/hw/cxgb4/cm.c
> @@ -39,6 +39,7 @@
>   #include <linux/ip.h>
>   #include <linux/tcp.h>
>   #include <linux/if_vlan.h>
> +#include <linux/fcntl.h>
>   
>   #include <net/neighbour.h>
>   #include <net/netevent.h>
> @@ -48,6 +49,7 @@
>   #include <net/addrconf.h>
>   
>   #include "iw_cxgb4.h"
> +#include "c4iw_netlink.h"
>   
>   static char *states[] = {
>   	"idle",
> @@ -586,10 +588,14 @@ static int send_connect(struct c4iw_ep *ep)
>   	int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
>   				sizeof(struct cpl_act_open_req6) :
>   				sizeof(struct cpl_t5_act_open_req6);
> -	struct sockaddr_in *la = (struct sockaddr_in *)&ep->com.local_addr;
> -	struct sockaddr_in *ra = (struct sockaddr_in *)&ep->com.remote_addr;
> -	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
> -	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
> +	struct sockaddr_in *la = (struct sockaddr_in *)
> +				 &ep->com.mapped_local_addr;
> +	struct sockaddr_in *ra = (struct sockaddr_in *)
> +				 &ep->com.mapped_remote_addr;
> +	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)
> +				   &ep->com.mapped_local_addr;
> +	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
> +				   &ep->com.mapped_remote_addr;
>   
>   	wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
>   			roundup(sizev4, 16) :
> @@ -1612,6 +1618,9 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
>   	}
>   	mutex_unlock(&ep->com.mutex);
>   
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
> +
>   	if (release)
>   		release_ep_resources(ep);
>   	return 0;
> @@ -1866,10 +1875,10 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
>   	struct sockaddr_in6 *ra6;
>   
>   	ep = lookup_atid(t, atid);
> -	la = (struct sockaddr_in *)&ep->com.local_addr;
> -	ra = (struct sockaddr_in *)&ep->com.remote_addr;
> -	la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
> -	ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
> +	la = (struct sockaddr_in *)&ep->com.mapped_local_addr;
> +	ra = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
> +	la6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
> +	ra6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;
>   
>   	PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
>   	     status, status2errno(status));
> @@ -1971,6 +1980,10 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
>   
>   	PDBG("%s ep %p\n", __func__, ep);
>   	c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
> +
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
> +
>   	return 0;
>   }
>   
> @@ -2422,6 +2435,9 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
>   	rpl->cmd = CPL_ABORT_NO_RST;
>   	c4iw_ofld_send(&ep->com.dev->rdev, rpl_skb);
>   out:
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
> +
>   	if (release)
>   		release_ep_resources(ep);
>   	else if (ep->retry_with_mpa_v1) {
> @@ -2476,6 +2492,9 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
>   		break;
>   	}
>   	mutex_unlock(&ep->com.mutex);
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
> +
>   	if (release)
>   		release_ep_resources(ep);
>   	return 0;
> @@ -2721,13 +2740,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
>   	struct c4iw_ep *ep;
>   	int err = 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_in6 *laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr;
> -	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)
> -				      &cm_id->remote_addr;
> +	struct sockaddr_in *laddr;
> +	struct sockaddr_in *raddr;
> +	struct sockaddr_in6 *laddr6;
> +	struct sockaddr_in6 *raddr6;
>   	__u8 *ra;
>   	int iptype;
> +	const char *msg_type = "Create Connect Mapping";
> +	int async = 0;
> +	int iwpm_err = 0;
>   
>   	if ((conn_param->ord > c4iw_max_read_depth) ||
>   	    (conn_param->ird > c4iw_max_read_depth)) {
> @@ -2775,6 +2796,44 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   	}
>   	insert_handle(dev, &dev->atid_idr, ep, ep->atid);
>   
> +	memcpy(&ep->com.local_addr, &cm_id->local_addr,
> +	       sizeof(ep->com.local_addr));
> +	memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
> +	       sizeof(ep->com.remote_addr));
> +
> +	/* No port mapper available, go with the specified peer information */
> +	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
> +	       sizeof(ep->com.mapped_local_addr));
> +	memcpy(&ep->com.mapped_remote_addr, &cm_id->remote_addr,
> +	       sizeof(ep->com.mapped_remote_addr));
> +	laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr;
> +	raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
> +	laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
> +	raddr6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr;
> +
> +	if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) {
> +		iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name,
> +						  dev->ibdev.name, async, NULL);
> +		if (iwpm_err) {
> +			c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
> +			PDBG("%s Port Mapper register pid failure (err_code = %d).\n"
> +			     , __func__, iwpm_err);
> +		}
> +	}
> +	if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */
> +		iwpm_err = c4iw_add_and_query_mapping(ep);
> +		if (iwpm_err)
> +			PDBG("%s Port Mapper query failure (err_code = %d).\n"
> +			     , __func__, iwpm_err);
> +	} else
> +		pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n"
> +			, __func__, c4iw_iwpm_pid);
> +	if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr,
> +				msg_type)) {
> +		err = -ENOMEM;
> +		goto fail3;
> +	}
> +
>   	if (cm_id->remote_addr.ss_family == AF_INET) {
>   		iptype = 4;
>   		ra = (__u8 *)&raddr->sin_addr;
> @@ -2809,10 +2868,11 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   		}
>   
>   		/* find a route */
> -		PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n",
> +		PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x sin6_scope_id %d\n",
>   		     __func__, laddr6->sin6_addr.s6_addr,
>   		     ntohs(laddr6->sin6_port),
> -		     raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port));
> +		     raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port),
> +		     raddr6->sin6_scope_id);
>   		ep->dst = find_route6(dev, laddr6->sin6_addr.s6_addr,
>   				      raddr6->sin6_addr.s6_addr,
>   				      laddr6->sin6_port, raddr6->sin6_port, 0,
> @@ -2836,10 +2896,6 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   
>   	state_set(&ep->com, CONNECTING);
>   	ep->tos = 0;
> -	memcpy(&ep->com.local_addr, &cm_id->local_addr,
> -	       sizeof(ep->com.local_addr));
> -	memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
> -	       sizeof(ep->com.remote_addr));
>   
>   	/* send connect request to rnic */
>   	err = send_connect(ep);
> @@ -2850,6 +2906,8 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
>   fail4:
>   	dst_release(ep->dst);
>   fail3:
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
>   	remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
>   	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
>   fail2:
> @@ -2862,7 +2920,8 @@ out:
>   static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
>   {
>   	int err;
> -	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ep->com.local_addr;
> +	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
> +				    &ep->com.mapped_local_addr;
>   
>   	c4iw_init_wr_wait(&ep->com.wr_wait);
>   	err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0],
> @@ -2883,7 +2942,8 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
>   static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
>   {
>   	int err;
> -	struct sockaddr_in *sin = (struct sockaddr_in *)&ep->com.local_addr;
> +	struct sockaddr_in *sin = (struct sockaddr_in *)
> +				  &ep->com.mapped_local_addr;
>   
>   	if (dev->rdev.lldi.enable_fw_ofld_conn) {
>   		do {
> @@ -2918,6 +2978,9 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
>   	int err = 0;
>   	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
>   	struct c4iw_listen_ep *ep;
> +	const char *msg_type = "Create Listen Mapping";
> +	int async = 0;
> +	int iwpm_err = 0;
>   
>   	might_sleep();
>   
> @@ -2932,6 +2995,7 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
>   	ep->com.cm_id = cm_id;
>   	ep->com.dev = dev;
>   	ep->backlog = backlog;
> +
>   	memcpy(&ep->com.local_addr, &cm_id->local_addr,
>   	       sizeof(ep->com.local_addr));
>   
> @@ -2951,6 +3015,34 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
>   		goto fail2;
>   	}
>   	insert_handle(dev, &dev->stid_idr, ep, ep->stid);
> +
> +	/* No port mapper available, go with the specified info */
> +	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
> +	       sizeof(ep->com.mapped_local_addr));
> +
> +	if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) {
> +		iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name,
> +						  dev->ibdev.name, async, NULL);
> +		if (iwpm_err) {
> +			c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
> +			PDBG("%s Port Mapper register pid failure (err_code = %d).\n"
> +			     , __func__, iwpm_err);
> +		}
> +	}
> +	if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */
> +		iwpm_err = c4iw_add_mapping(ep);
> +		if (iwpm_err)
> +			PDBG("%s Port Mapper query failure (err_code = %d).\n"
> +			     , __func__, iwpm_err);
> +	} else
> +		pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n"
> +			, __func__, c4iw_iwpm_pid);
> +	if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr,
> +				msg_type)) {
> +		err = -ENOMEM;
> +		goto fail3;
> +	}
> +
>   	state_set(&ep->com, LISTEN);
>   	if (ep->com.local_addr.ss_family == AF_INET)
>   		err = create_server4(dev, ep);
> @@ -2960,6 +3052,10 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
>   		cm_id->provider_data = ep;
>   		goto out;
>   	}
> +
> +fail3:
> +	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
> +	c4iw_remove_mapping(&ep->com.mapped_local_addr);
>   	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,
>   			ep->com.local_addr.ss_family);
>   fail2:
> diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
> index 33d2cc6..8810f78 100644
> --- a/drivers/infiniband/hw/cxgb4/device.c
> +++ b/drivers/infiniband/hw/cxgb4/device.c
> @@ -37,6 +37,7 @@
>   #include <rdma/ib_verbs.h>
>   
>   #include "iw_cxgb4.h"
> +#include "c4iw_netlink.h"
>   
>   #define DRV_VERSION "0.1"
>   
> @@ -106,9 +107,9 @@ static int dump_qp(int id, void *p, void *data)
>   	if (qp->ep) {
>   		if (qp->ep->com.local_addr.ss_family == AF_INET) {
>   			struct sockaddr_in *lsin = (struct sockaddr_in *)
> -				&qp->ep->com.local_addr;
> +				&qp->ep->com.mapped_local_addr;
>   			struct sockaddr_in *rsin = (struct sockaddr_in *)
> -				&qp->ep->com.remote_addr;
> +				&qp->ep->com.mapped_remote_addr;
>   
>   			cc = snprintf(qpd->buf + qpd->pos, space,
>   				      "rc qp sq id %u rq id %u state %u "
> @@ -122,9 +123,9 @@ static int dump_qp(int id, void *p, void *data)
>   				      &rsin->sin_addr, ntohs(rsin->sin_port));
>   		} else {
>   			struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)
> -				&qp->ep->com.local_addr;
> +				&qp->ep->com.mapped_local_addr;
>   			struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *)
> -				&qp->ep->com.remote_addr;
> +				&qp->ep->com.mapped_remote_addr;
>   
>   			cc = snprintf(qpd->buf + qpd->pos, space,
>   				      "rc qp sq id %u rq id %u state %u "
> @@ -1210,6 +1211,19 @@ static int __init c4iw_init_module(void)
>   		printk(KERN_WARNING MOD
>   		       "could not create debugfs entry, continuing\n");
>   
> +	spin_lock_init(&c4iw_nlmsg_lock);
> +	spin_lock_init(&c4iw_mapping_lock);
> +
> +	/* List of submitted requests, searched for completions */
> +	INIT_LIST_HEAD(&c4iw_nlmsg_request_list);
> +	/* List of iwpm mappings in use */
> +	INIT_LIST_HEAD(&c4iw_mapping_info_list);
> +
> +	if (ibnl_add_client(RDMA_NL_C4IW, RDMA_NL_IWPM_NUM_OPS,
> +			c4iw_nl_cb_table))
> +		pr_err("%s[%u]: Failed to add netlink callback\n"
> +			, __func__, __LINE__);
> +
>   	cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info);
>   
>   	return 0;
> @@ -1227,6 +1241,8 @@ static void __exit c4iw_exit_module(void)
>   	}
>   	mutex_unlock(&dev_mutex);
>   	cxgb4_unregister_uld(CXGB4_ULD_RDMA);
> +	ibnl_remove_client(RDMA_NL_C4IW);
> +	c4iw_destroy_mapinfo_list();
>   	c4iw_cm_term();
>   	debugfs_remove_recursive(c4iw_debugfs_root);
>   }
> diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
> index 23eaeab..7b3405d 100644
> --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
> +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
> @@ -152,6 +152,20 @@ struct c4iw_rdev {
>   	struct c4iw_stats stats;
>   };
>   
> +static inline void print_addr(struct sockaddr_storage *addr,
> +			      const char *msg)
> +{
> +	struct sockaddr_in *laddr = (struct sockaddr_in *)addr;
> +	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)addr;
> +
> +	if (addr->ss_family == AF_INET)
> +		PDBG("%s %s addr %pI4 port 0x%04X\n", __func__, msg
> +		     , &laddr->sin_addr.s_addr, ntohs(laddr->sin_port));
> +	else
> +		PDBG("%s %s addr %pI6 port 0x%04X\n", __func__, msg
> +		     , laddr6->sin6_addr.s6_addr, ntohs(laddr6->sin6_port));
> +}
> +
>   static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
>   {
>   	return rdev->flags & T4_FATAL_ERROR;
> @@ -754,6 +768,8 @@ struct c4iw_ep_common {
>   	struct mutex mutex;
>   	struct sockaddr_storage local_addr;
>   	struct sockaddr_storage remote_addr;
> +	struct sockaddr_storage mapped_local_addr;
> +	struct sockaddr_storage mapped_remote_addr;
>   	struct c4iw_wr_wait wr_wait;
>   	unsigned long flags;
>   	unsigned long history;

--
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/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile
index e11cf72..7e4d948 100644
--- a/drivers/infiniband/hw/cxgb4/Makefile
+++ b/drivers/infiniband/hw/cxgb4/Makefile
@@ -2,4 +2,4 @@  ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4
 
 obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
 
-iw_cxgb4-y :=  device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o
+iw_cxgb4-y :=  device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o c4iw_netlink.o
diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.c b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c
new file mode 100644
index 0000000..001c0e3
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c
@@ -0,0 +1,1021 @@ 
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other  materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/iw_cm.h>
+#include <net/netlink.h>
+
+#include "iw_cxgb4.h"
+#include "c4iw_netlink.h"
+
+spinlock_t c4iw_nlmsg_lock;
+struct list_head c4iw_nlmsg_request_list;
+struct list_head c4iw_mapping_info_list;
+spinlock_t c4iw_mapping_lock;
+atomic_t c4iw_nlmsg_seq;
+atomic_t echo_nlmsg_seq;
+
+int c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
+static char iwpm_ulib_name[] = "iWarpPortMapperUser";
+static int iwpm_ulib_version = 3;
+
+static char c4iw_ifname[IWPM_IFNAME_SIZE];
+static char c4iw_ibdev[IWPM_DEVNAME_SIZE];
+
+static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void);
+static int c4iw_send_mapping_info(void);
+static int c4iw_send_mapping_count(u32);
+static int c4iw_parse_nlmsg(struct netlink_callback *, int,
+			    const struct nla_policy *, struct nlattr *[],
+			    const char *);
+
+/* c4iw netlink callbacks */
+static int c4iw_register_iwpm_pid_cb(struct sk_buff *,
+				     struct netlink_callback *);
+static int c4iw_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
+static int c4iw_add_and_query_mapping_cb(struct sk_buff *,
+					 struct netlink_callback *);
+static int c4iw_mapping_error_cb(struct sk_buff *, struct netlink_callback *);
+static int c4iw_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
+static int c4iw_ack_mapping_info_cb(struct sk_buff *,
+				    struct netlink_callback *);
+
+static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void)
+{
+	unsigned long flags;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+
+	nlmsg_request = kzalloc(sizeof(struct c4iw_nlmsg_request), GFP_ATOMIC);
+	if (!nlmsg_request) {
+		pr_err("%s Unable to allocate a nlmsg_request\n", __func__);
+		return NULL;
+	}
+	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
+	list_add_tail(&nlmsg_request->inprocess_list, &c4iw_nlmsg_request_list);
+	spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags);
+
+	atomic_set(&nlmsg_request->refcount, 1);
+	nlmsg_request->nlmsg_seq = atomic_inc_return(&c4iw_nlmsg_seq);
+	nlmsg_request->request_done = 0;
+	nlmsg_request->async = 0;
+	nlmsg_request->err_code = 0;
+	return nlmsg_request;
+}
+
+static int c4iw_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 = c4iw_validate_nlmsg_attr(nltb, policy_max);
+	if (ret) {
+		err_str = "Invalid NULL attribute";
+		goto parse_nlmsg_error;
+	}
+	return 0;
+parse_nlmsg_error:
+	pr_warn("%s %s (msg type %s ret = %d)\n",
+		__func__, err_str, msg_type, ret);
+	return ret;
+}
+
+static void c4iw_nlmsg_req_timer_free(unsigned long data)
+{
+	struct c4iw_nlmsg_request *nlmsg_request = (struct c4iw_nlmsg_request *)
+						    data;
+
+	if (!nlmsg_request->request_done && !nlmsg_request->err_code)
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNAVAILABLE;
+
+	if (c4iw_iwpm_pid < 0)
+		pr_info("%s Port Mapper isn't available (err code = %d)\n"
+			, __func__, nlmsg_request->err_code);
+	rem_ref_nlmsg_request(nlmsg_request);
+}
+
+static void c4iw_mapinfo_timer_send(unsigned long data)
+{
+	int mapping_num;
+
+	c4iw_nlmsg_req_timer_free(data);
+
+	if (c4iw_iwpm_pid < 0)
+		return;
+	mapping_num = c4iw_send_mapping_info();
+	if (mapping_num < 0) {
+		pr_info("%s Unable to send mapping info\n", __func__);
+		return;
+	}
+	PDBG("%s Sending Mapping count msg (num = %d)\n", __func__
+	     , mapping_num);
+
+	c4iw_send_mapping_count(mapping_num);
+}
+
+static void c4iw_start_nlmsg_req_timer(struct c4iw_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);
+}
+
+/*
+ * 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 c4iw_register_iwpm_pid(char *netdev_name, char *dev_name, int async,
+			   void (*req_timer_func)(unsigned long))
+{
+	struct sk_buff *skb = NULL;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_REG_PID, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto pid_query_error;
+	}
+	nlmsg_request = c4iw_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, iwpm_ulib_name,
+			    IWPM_NLA_REG_ULIB_NAME);
+	if (ret)
+		goto pid_query_error;
+	memcpy(c4iw_ibdev, dev_name, IWPM_DEVNAME_SIZE);
+	memcpy(c4iw_ifname, netdev_name, IWPM_IFNAME_SIZE);
+	PDBG("%s Multicasting a nlmsg (echo seq = %u ibdevname = %s ifname = %s iwpm ulib name = %s) nlmsg len = %d request seq = %u\n"
+	     , __func__, msg_seq, dev_name, netdev_name, iwpm_ulib_name
+	     , nlh->nlmsg_len, nlmsg_request->nlmsg_seq);
+
+	ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
+	if (ret) {
+		skb = NULL; /* already freed in the netlink send-op handling */
+		err_str = "Unable to send a nlmsg";
+		goto pid_query_error;
+	}
+	nlmsg_request->async = async;
+	if (async)
+		c4iw_start_nlmsg_req_timer(nlmsg_request, req_timer_func,
+					   C4IW_IWPM_NL_TIMEOUT);
+	else
+		ret = wait_complete_nlmsg_req(nlmsg_request,
+					      C4IW_IWPM_PID_UNAVAILABLE);
+	return ret;
+pid_query_error:
+	pr_warn("%s %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * Send a netlink add mapping request
+ * for the listener ip/tcp address to the userspace port mapper
+ * nlmsg attributes:
+ *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
+ *	[IWPM_NLA_MANAGE_ADDR]
+ */
+int c4iw_add_mapping(struct c4iw_listen_ep *ep)
+{
+	struct sk_buff *skb = NULL;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in *laddr = (struct sockaddr_in *)
+				    &ep->com.local_addr;
+	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)
+				      &ep->com.local_addr;
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto add_mapping_error;
+	}
+
+	nlmsg_request = c4iw_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto add_mapping_error;
+	}
+
+	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),
+			    &ep->com.local_addr, IWPM_NLA_MANAGE_ADDR);
+	if (ret)
+		goto add_mapping_error;
+
+	nlmsg_request->request_buffer = ep;
+	if (ep->com.local_addr.ss_family == AF_INET)
+		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) request seq = %u\n"
+		     , __func__, msg_seq, &laddr->sin_addr.s_addr
+		     , ntohs(laddr->sin_port), nlmsg_request->nlmsg_seq);
+	else
+		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) request seq = %u\n"
+		     , __func__, msg_seq, &laddr6->sin6_addr.s6_addr
+		     , ntohs(laddr6->sin6_port), nlmsg_request->nlmsg_seq);
+
+	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
+	if (ret) {
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; /* ret = -111 */
+		skb = NULL; /* already freed in the netlink send-op handling */
+		err_str = "Unable to send a nlmsg";
+		goto add_mapping_error;
+	}
+	ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED);
+	return ret;
+add_mapping_error:
+	pr_warn("%s %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * Send both a netlink add mapping request for the connecting
+ * side ip/tcp address and a query for the accepting remote peer
+ * mapped 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 c4iw_add_and_query_mapping(struct c4iw_ep *ep)
+{
+	struct sk_buff *skb = NULL;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in *laddr = (struct sockaddr_in *)
+				     &ep->com.local_addr;
+	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)
+				      &ep->com.local_addr;
+	struct sockaddr_in *raddr = (struct sockaddr_in *)
+				     &ep->com.remote_addr;
+	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)
+				      &ep->com.remote_addr;
+	const char *err_str = "";
+	int ret = -ENOMEM;
+
+	skb = c4iw_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto query_mapping_error;
+	}
+	nlmsg_request = c4iw_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto query_mapping_error;
+	}
+
+	msg_seq = atomic_read(&echo_nlmsg_seq);
+	/* 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),
+			    &ep->com.local_addr,
+			    IWPM_NLA_QUERY_LOCAL_ADDR);
+	if (ret)
+		goto query_mapping_error;
+	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
+			    &ep->com.remote_addr,
+			    IWPM_NLA_QUERY_REMOTE_ADDR);
+	if (ret)
+		goto query_mapping_error;
+
+	nlmsg_request->request_buffer = ep;
+	if (ep->com.local_addr.ss_family == AF_INET)
+		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) Remote addr %pI4 [0x%04X]) request seq = %u\n"
+		     , __func__, msg_seq, &laddr->sin_addr.s_addr
+		     , ntohs(laddr->sin_port), &raddr->sin_addr.s_addr
+		     , ntohs(raddr->sin_port), nlmsg_request->nlmsg_seq);
+	else
+		PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) Remote addr %pI6 [0x%04X]) request seq = %u\n"
+		     , __func__, msg_seq, &laddr6->sin6_addr.s6_addr
+		     , ntohs(laddr6->sin6_port), &raddr6->sin6_addr.s6_addr
+		     , ntohs(raddr6->sin6_port), nlmsg_request->nlmsg_seq);
+
+	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
+	if (ret) {
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
+		skb = NULL; /* already freed in the netlink send-op handling */
+		err_str = "Unable to send a nlmsg";
+		goto query_mapping_error;
+	}
+	ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED);
+	return ret;
+query_mapping_error:
+	pr_warn("%s %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+/*
+ * Send a netlink remove mapping request to the userspace port mapper
+ * nlmsg attributes:
+ *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
+ *	[IWPM_NLA_MANAGE_ADDR]
+ */
+int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct nlmsghdr **nlh_next = &nlh;
+	u32 msg_seq;
+	struct sockaddr_in *mapped_la = (struct sockaddr_in *)
+					mapped_local_addr;
+	struct sockaddr_in6 *mapped_la6 = (struct sockaddr_in6 *)
+					  mapped_local_addr;
+	const char *err_str = "";
+	int ret;
+
+	if (c4iw_remove_mapinfo(mapped_local_addr)) {
+		if (mapped_local_addr->ss_family == AF_INET)
+			pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n"
+				, __func__, ntohs(mapped_la->sin_port));
+		else
+			pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n"
+				, __func__, ntohs(mapped_la6->sin6_port));
+		return -EINVAL;
+	}
+	if (c4iw_iwpm_pid < 0)
+		return 0;
+
+	skb = c4iw_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(&c4iw_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_local_addr, IWPM_NLA_MANAGE_ADDR);
+	if (ret)
+		goto remove_mapping_error;
+
+	if (mapped_local_addr->ss_family == AF_INET)
+		PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI4 [0x%04X])\n"
+		     , __func__, msg_seq, &mapped_la->sin_addr.s_addr
+		     , ntohs(mapped_la->sin_port));
+	else
+		PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI6 [0x%04X])\n"
+		     , __func__, msg_seq, mapped_la6->sin6_addr.s6_addr
+		     , ntohs(mapped_la6->sin6_port));
+
+	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
+	if (ret) {
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
+		skb = NULL;
+		err_str = "Unable to send a nlmsg";
+		goto remove_mapping_error;
+	}
+	return 0;
+remove_mapping_error:
+	pr_warn("%s %s\n", __func__, err_str);
+	if (skb)
+		dev_kfree_skb(skb);
+	return ret;
+}
+
+/* registered netlink c4iw callbacks */
+struct ibnl_client_cbs c4iw_nl_cb_table[] = {
+	[RDMA_NL_IWPM_REG_PID] = {.dump = c4iw_register_iwpm_pid_cb},
+	[RDMA_NL_IWPM_ADD_MAPPING] = {.dump = c4iw_add_mapping_cb},
+	[RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = c4iw_add_and_query_mapping_cb},
+	[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = c4iw_mapping_error_cb},
+	[RDMA_NL_IWPM_MAP_INFO] = {.dump = c4iw_mapping_info_cb},
+	[RDMA_NL_IWPM_MAP_INFO_NUM] = {.dump = c4iw_ack_mapping_info_cb}
+};
+
+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 }
+};
+
+static int c4iw_register_iwpm_pid_cb(struct sk_buff *skb,
+				     struct netlink_callback *cb)
+{
+	struct c4iw_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";
+
+	c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
+
+	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_warn("%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(c4iw_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;
+	}
+	PDBG("%s Received info (dev = %s name = %s version = %d) request seq = %u\n"
+	     , __func__, dev_name, iwpm_name, iwpm_version
+	     , nlmsg_request->nlmsg_seq);
+
+	c4iw_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__, c4iw_iwpm_pid);
+register_pid_response_exit:
+	nlmsg_request->request_done = 1;
+	/* always for found nlmsg_request */
+	rem_ref_nlmsg_request(nlmsg_request);
+	barrier();
+	if (!nlmsg_request->async)
+		wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+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 }
+};
+
+static int c4iw_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct c4iw_listen_ep *ep;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
+	u32 msg_seq;
+	struct sockaddr_storage *local_sockaddr, *mapped_sockaddr;
+	const char *msg_type;
+
+	msg_type = "Add Mapping response";
+	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_warn("%s Could not find a matching request (seq = %u)\n"
+			, __func__, msg_seq);
+		return -EINVAL;
+	}
+	ep = nlmsg_request->request_buffer;
+	local_sockaddr = (struct sockaddr_storage *)
+			 nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
+	mapped_sockaddr = (struct sockaddr_storage *)
+			  nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]);
+
+	if (memcmp(&ep->com.local_addr, local_sockaddr,
+		   sizeof(ep->com.local_addr))) {
+		print_addr(&ep->com.local_addr,
+			   "Invalid ip/tcp address Local: expected");
+		print_addr(local_sockaddr,
+			   "Invalid ip/tcp address Local: received");
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto add_mapping_response_exit;
+	}
+
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	memcpy(&ep->com.mapped_local_addr, mapped_sockaddr,
+	       sizeof(ep->com.mapped_local_addr));
+add_mapping_response_exit:
+	print_addr(mapped_sockaddr, "Received a new mapping mapped local");
+	nlmsg_request->request_done = 1;
+	/* always for found nlmsg_request */
+	rem_ref_nlmsg_request(nlmsg_request);
+	barrier();
+	wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+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 }
+};
+
+static int c4iw_add_and_query_mapping_cb(struct sk_buff *skb,
+					 struct netlink_callback *cb)
+{
+	struct c4iw_ep *ep;
+	struct c4iw_nlmsg_request *nlmsg_request = NULL;
+	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
+	u32 msg_seq;
+	struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
+	struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
+	struct sockaddr_in *laddr;
+	struct sockaddr_in6 *laddr6;
+	struct sockaddr_in *raddr;
+	struct sockaddr_in6 *raddr6;
+	struct sockaddr_in *map_laddr;
+	struct sockaddr_in6 *map_laddr6;
+	struct sockaddr_in *map_raddr;
+	struct sockaddr_in6 *map_raddr6;
+	const char *msg_type;
+	u16 err_code;
+
+	msg_type = "Query Mapping response";
+	if (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_warn("%s Could not find a matching request (seq = %u)\n"
+			, __func__, msg_seq);
+			return -EINVAL;
+	}
+	ep = nlmsg_request->request_buffer;
+	local_sockaddr = (struct sockaddr_storage *)
+			  nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
+	remote_sockaddr = (struct sockaddr_storage *)
+			   nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
+	mapped_loc_sockaddr = (struct sockaddr_storage *)
+			       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
+	mapped_rem_sockaddr = (struct sockaddr_storage *)
+			       nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
+	map_laddr = (struct sockaddr_in *)mapped_loc_sockaddr;
+	map_laddr6 = (struct sockaddr_in6 *)mapped_loc_sockaddr;
+	map_raddr = (struct sockaddr_in *)mapped_rem_sockaddr;
+	map_raddr6 = (struct sockaddr_in6 *) mapped_rem_sockaddr;
+	laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr;
+	laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
+	raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
+	raddr6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;
+
+	err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
+	if (err_code == IWPM_REMOTE_QUERY_REJECT) {
+		pr_info("%s Received a Query Reject nlmsg. nlmsg (pid = %u, seq = %u) echo seq = %u.\n"
+			, __func__, cb->nlh->nlmsg_pid, cb->nlh->nlmsg_seq
+			, msg_seq);
+		nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
+	}
+	if (memcmp(&ep->com.local_addr, local_sockaddr,
+		   sizeof(ep->com.local_addr) != 0) ||
+	    memcmp(&ep->com.remote_addr, remote_sockaddr,
+		   sizeof(ep->com.remote_addr) != 0)) {
+		print_addr(&ep->com.local_addr,
+			   "Invalid ip/tcp address Local: expected");
+		print_addr(local_sockaddr,
+			   "Invalid ip/tcp address Local: received");
+		print_addr(&ep->com.remote_addr,
+			   "Invalid ip/tcp address Remote: expected");
+		print_addr(remote_sockaddr,
+			   "Invalid ip/tcp address Remote: received");
+		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
+		goto query_mapping_response_exit;
+	}
+
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	if (ep->com.local_addr.ss_family == AF_INET) {
+		laddr->sin_addr.s_addr = map_laddr->sin_addr.s_addr,
+		laddr->sin_port = map_laddr->sin_port;
+		raddr->sin_addr.s_addr = map_raddr->sin_addr.s_addr,
+		raddr->sin_port = map_raddr->sin_port;
+	} else {
+		memcpy(laddr6->sin6_addr.s6_addr, map_laddr6->sin6_addr.s6_addr,
+		       IWPM_IPADDR_SIZE);
+		laddr6->sin6_port = map_laddr6->sin6_port;
+		memcpy(raddr6->sin6_addr.s6_addr, map_raddr6->sin6_addr.s6_addr,
+		       IWPM_IPADDR_SIZE);
+		raddr6->sin6_port = map_raddr6->sin6_port;
+	}
+query_mapping_response_exit:
+	print_addr(mapped_loc_sockaddr, "Received a new mapping mapped local");
+	print_addr(mapped_rem_sockaddr, "Received a new mapping mapped remote");
+	nlmsg_request->request_done = 1;
+	/* always for found nlmsg_request */
+	rem_ref_nlmsg_request(nlmsg_request);
+	barrier();
+	wake_up(&nlmsg_request->waitq);
+	return 0;
+}
+
+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 }
+};
+
+static int c4iw_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 (c4iw_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(&c4iw_mapping_info_list))
+		req_timer_func = &c4iw_nlmsg_req_timer_free;
+	else
+		req_timer_func = &c4iw_mapinfo_timer_send;
+
+	c4iw_register_iwpm_pid(c4iw_ifname, c4iw_ibdev, async, req_timer_func);
+	return 0;
+}
+
+static int c4iw_send_mapping_count(u32 mapping_num)
+{
+	struct c4iw_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 = c4iw_create_nlmsg(RDMA_NL_IWPM_MAP_INFO_NUM, nlh_next);
+	if (!skb) {
+		err_str = "Unable to create a nlmsg";
+		goto mapping_count_exit;
+	}
+	nlmsg_request = c4iw_get_nlmsg_request();
+	if (!nlmsg_request) {
+		err_str = "Unable to allocate netlink request";
+		goto mapping_count_exit;
+	}
+
+	/* 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 mapping_count_exit;
+	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &mapping_num,
+			    IWPM_NLA_MAPINFO_NUMBER);
+	if (ret)
+		goto mapping_count_exit;
+
+	ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid);
+	if (ret) {
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
+		/* already freed in the netlink send-op handling */
+		skb = NULL;
+		err_str = "Unable to send a nlmsg";
+		goto mapping_count_exit;
+	}
+	nlmsg_request->mapcount = mapping_num;
+	nlmsg_request->async = 1;
+	c4iw_start_nlmsg_req_timer(nlmsg_request, c4iw_nlmsg_req_timer_free,
+				   C4IW_IWPM_NL_TIMEOUT);
+	return 0;
+mapping_count_exit:
+	if (skb)
+		dev_kfree_skb(skb);
+	if (nlmsg_request)
+		free_nlmsg_request(nlmsg_request);
+	pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret);
+	return ret;
+}
+
+static int c4iw_send_nlmsg_done(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	int ret;
+	if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW,
+			   RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
+		pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
+		return -ENOMEM;
+	}
+	nlh->nlmsg_type = NLMSG_DONE;
+	ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, c4iw_iwpm_pid);
+	if (ret) {
+		c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED;
+		pr_warn("%s Unable to send a nlmsg\n", __func__);
+	}
+	return ret;
+}
+
+static int c4iw_send_mapping_info(void)
+{
+	struct sk_buff *skb = NULL;
+	struct c4iw_mapping_info *map_info;
+	struct nlmsghdr *nlh;
+	int skb_num = 0, mapping_num = 0, nlmsg_bytes = 0;
+	unsigned long flags;
+	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(&c4iw_mapping_lock, flags);
+	list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) {
+		nlh = NULL;
+		if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW,
+				   RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) {
+			ret = -ENOMEM;
+			err_str = "Unable to put the nlmsg header";
+			spin_unlock_irqrestore(&c4iw_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(&c4iw_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(&c4iw_mapping_lock, flags);
+			goto send_mapping_info_exit;
+		}
+		mapping_num++;
+		nlmsg_bytes += nlh->nlmsg_len;
+
+		/* check if all mappings can fit in one skb */
+		if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len*2) {
+			nlmsg_bytes = 0;
+			skb_num++;
+			PDBG("%s Mappings Sent %d (nlmsg_bytes = %d nlmsg_len = %d). Allocating another skb (num = %d size = %lu)\n"
+			     , __func__, mapping_num, nlmsg_bytes
+			     , nlh->nlmsg_len, skb_num
+			     , NLMSG_GOODSIZE);
+			/* and leave room for NLMSG_DONE */
+			spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
+			/* send the skb */
+			ret = c4iw_send_nlmsg_done(skb);
+			skb = NULL;
+			if (ret) {
+				err_str = "Unable to send map info";
+				goto send_mapping_info_exit;
+			}
+			if (skb_num == C4IW_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(&c4iw_mapping_lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
+	if (skb)
+		c4iw_send_nlmsg_done(skb);
+	return mapping_num;
+send_mapping_info_exit:
+	if (skb)
+		dev_kfree_skb(skb);
+	if (ret > 0)
+		ret = -ret;
+	pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret);
+	return ret;
+}
+
+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 }
+};
+
+static int c4iw_ack_mapping_info_cb(struct sk_buff *skb,
+				    struct netlink_callback *cb)
+{
+	struct c4iw_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 (c4iw_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 = c4iw_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		pr_warn("%s Could not find a matching request with 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 map info count (sent = %u ack-ed = %u)\n"
+			, __func__, nlmsg_request->mapcount, mapping_num);
+	}
+	PDBG("%s Received ack for mapping count = %u\n", __func__, mapping_num);
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	nlmsg_request->request_done = 1;
+	/* always for found nlmsg_request */
+	rem_ref_nlmsg_request(nlmsg_request);
+	return 0;
+}
+
+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 },
+};
+
+static int c4iw_mapping_error_cb(struct sk_buff *skb,
+				 struct netlink_callback *cb)
+{
+	struct c4iw_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 (c4iw_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_warn("%s Received msg_seq = %u err_code = %u\n"
+		, __func__, msg_seq, err_code);
+	/* look for nlmsg_request */
+	nlmsg_request = c4iw_find_nlmsg_request(msg_seq);
+	if (!nlmsg_request) {
+		/* not all errors have associated requests */
+		PDBG("%s Could not find a matching request with seq = %u\n"
+		     , __func__, msg_seq);
+		return -EINVAL;
+	}
+	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+	nlmsg_request->err_code = err_code;
+	nlmsg_request->request_done = 1;
+	/* always for found nlmsg_request */
+	rem_ref_nlmsg_request(nlmsg_request);
+	barrier();
+	if (!nlmsg_request->async)
+		wake_up(&nlmsg_request->waitq);
+	return 0;
+}
diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.h b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h
new file mode 100644
index 0000000..aa1b66c
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h
@@ -0,0 +1,273 @@ 
+/*
+ * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other  materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __C4IW_NETLINK_H
+#define __C4IW_NETLINK_H
+
+#include <rdma/rdma_netlink.h>
+#include <linux/errno.h>
+
+#define C4IW_IWPM_PID_UNDEFINED    -1
+#define C4IW_IWPM_PID_UNAVAILABLE  -2
+#define C4IW_IWPM_PID_ERROR	   -3
+
+#define C4IW_IWPM_NL_RETRANS	3
+#define C4IW_IWPM_NL_TIMEOUT     10000
+#define C4IW_MAP_INFO_SKB_COUNT  20
+
+#define IWPM_ULIBNAME_SIZE 32
+#define IWPM_DEVNAME_SIZE  32
+#define IWPM_IFNAME_SIZE   16
+#define IWPM_IPADDR_SIZE   16
+
+extern struct list_head c4iw_nlmsg_request_list;
+extern struct list_head c4iw_mapping_info_list;
+extern spinlock_t c4iw_nlmsg_lock;
+extern spinlock_t c4iw_mapping_lock;
+extern atomic_t c4iw_nlmsg_seq;
+extern atomic_t echo_nlmsg_seq;
+
+extern struct ibnl_client_cbs c4iw_nl_cb_table[];
+extern int c4iw_iwpm_pid;
+
+struct c4iw_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 c4iw_mapping_info {
+	struct list_head mapping_list;
+	struct sockaddr_storage local_sockaddr;
+	struct sockaddr_storage 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
+};
+
+int c4iw_register_iwpm_pid(char *, char *, int,
+			   void (*req_timer_func)(unsigned long));
+int c4iw_add_mapping(struct c4iw_listen_ep *ep);
+int c4iw_add_and_query_mapping(struct c4iw_ep *ep);
+int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr);
+void c4iw_timer_send_mapinfo(unsigned long);
+
+static inline int c4iw_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;
+}
+
+static inline void c4iw_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;
+}
+
+static inline struct sk_buff *c4iw_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_C4IW, nl_op,
+			   NLM_F_REQUEST))) {
+		pr_warn("%s Unable to put the nlmsg header\n", __func__);
+		dev_kfree_skb(skb);
+		skb = NULL;
+	}
+create_nlmsg_exit:
+	return skb;
+}
+
+static inline void free_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
+	list_del_init(&nlmsg_request->inprocess_list);
+	spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags);
+
+	if (nlmsg_request->async)
+		del_timer(&nlmsg_request->service_timer);
+
+	if (!nlmsg_request->request_done)
+		pr_warn("%s Freeing incomplete nlmsg request (seq = %u).\n",
+			__func__, nlmsg_request->nlmsg_seq);
+	kfree(nlmsg_request);
+}
+
+static void rem_ref_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request)
+{
+	if (atomic_dec_and_test(&nlmsg_request->refcount))
+		free_nlmsg_request(nlmsg_request);
+}
+
+static inline int wait_complete_nlmsg_req(struct c4iw_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),
+				 C4IW_IWPM_NL_TIMEOUT);
+	if (!ret) {
+		c4iw_iwpm_pid = iwpm_pid;
+		pr_warn("%s: Timeout %d sec for netlink request (seq = %u)\n"
+			, __func__, (C4IW_IWPM_NL_TIMEOUT/HZ)
+			, nlmsg_request->nlmsg_seq);
+	} else
+		ret = nlmsg_request->err_code;
+
+	rem_ref_nlmsg_request(nlmsg_request);
+	return ret;
+}
+
+static inline struct c4iw_nlmsg_request *c4iw_find_nlmsg_request(__u32 echo_seq)
+{
+	struct c4iw_nlmsg_request *nlmsg_request;
+	struct c4iw_nlmsg_request *found_request = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c4iw_nlmsg_lock, flags);
+	list_for_each_entry(nlmsg_request, &c4iw_nlmsg_request_list,
+			    inprocess_list) {
+		PDBG("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(&c4iw_nlmsg_lock, flags);
+	return found_request;
+}
+
+static inline int c4iw_create_mapinfo(struct sockaddr_storage *local_sockaddr,
+				      struct sockaddr_storage *mapped_sockaddr,
+				      const char *msg_type)
+{
+	struct c4iw_mapping_info *map_info;
+	unsigned long flags;
+
+	map_info = kzalloc(sizeof(struct c4iw_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_storage));
+	memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
+	       sizeof(struct sockaddr_storage));
+
+	spin_lock_irqsave(&c4iw_mapping_lock, flags);
+	list_add_tail(&map_info->mapping_list, &c4iw_mapping_info_list);
+	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
+
+	return 0;
+}
+
+static inline int c4iw_remove_mapinfo(struct sockaddr_storage
+				      *mapped_local_addr)
+{
+	struct c4iw_mapping_info *map_info = NULL;
+	unsigned long flags;
+	int ret = -EINVAL;
+	const char *msg = "Remove mapped";
+
+	print_addr(mapped_local_addr, msg);
+
+	spin_lock_irqsave(&c4iw_mapping_lock, flags);
+	list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) {
+		print_addr(&map_info->mapped_sockaddr
+			   , "Going through mapinfo mapped local");
+		if (!memcmp(&map_info->mapped_sockaddr,	mapped_local_addr,
+			    sizeof(struct sockaddr_storage))) {
+			list_del_init(&map_info->mapping_list);
+			kfree(map_info);
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
+	return ret;
+}
+
+static inline void c4iw_destroy_mapinfo_list(void)
+{
+	struct c4iw_mapping_info *map_info, *map_info_tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c4iw_mapping_lock, flags);
+	list_for_each_entry_safe(map_info, map_info_tmp,
+				 &c4iw_mapping_info_list, mapping_list) {
+		print_addr(&map_info->mapped_sockaddr,
+			   "Delete mapinfo mapped local");
+		list_del(&map_info->mapping_list);
+		kfree(map_info);
+	}
+	spin_unlock_irqrestore(&c4iw_mapping_lock, flags);
+}
+
+#endif /* __C4IW_NETLINK_H */
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 12fef76..b8e2117 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -39,6 +39,7 @@ 
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if_vlan.h>
+#include <linux/fcntl.h>
 
 #include <net/neighbour.h>
 #include <net/netevent.h>
@@ -48,6 +49,7 @@ 
 #include <net/addrconf.h>
 
 #include "iw_cxgb4.h"
+#include "c4iw_netlink.h"
 
 static char *states[] = {
 	"idle",
@@ -586,10 +588,14 @@  static int send_connect(struct c4iw_ep *ep)
 	int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
 				sizeof(struct cpl_act_open_req6) :
 				sizeof(struct cpl_t5_act_open_req6);
-	struct sockaddr_in *la = (struct sockaddr_in *)&ep->com.local_addr;
-	struct sockaddr_in *ra = (struct sockaddr_in *)&ep->com.remote_addr;
-	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
-	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
+	struct sockaddr_in *la = (struct sockaddr_in *)
+				 &ep->com.mapped_local_addr;
+	struct sockaddr_in *ra = (struct sockaddr_in *)
+				 &ep->com.mapped_remote_addr;
+	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)
+				   &ep->com.mapped_local_addr;
+	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
+				   &ep->com.mapped_remote_addr;
 
 	wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
 			roundup(sizev4, 16) :
@@ -1612,6 +1618,9 @@  static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 	}
 	mutex_unlock(&ep->com.mutex);
 
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
+
 	if (release)
 		release_ep_resources(ep);
 	return 0;
@@ -1866,10 +1875,10 @@  static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 	struct sockaddr_in6 *ra6;
 
 	ep = lookup_atid(t, atid);
-	la = (struct sockaddr_in *)&ep->com.local_addr;
-	ra = (struct sockaddr_in *)&ep->com.remote_addr;
-	la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
-	ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
+	la = (struct sockaddr_in *)&ep->com.mapped_local_addr;
+	ra = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
+	la6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
+	ra6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;
 
 	PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
 	     status, status2errno(status));
@@ -1971,6 +1980,10 @@  static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 
 	PDBG("%s ep %p\n", __func__, ep);
 	c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
+
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
+
 	return 0;
 }
 
@@ -2422,6 +2435,9 @@  static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 	rpl->cmd = CPL_ABORT_NO_RST;
 	c4iw_ofld_send(&ep->com.dev->rdev, rpl_skb);
 out:
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
+
 	if (release)
 		release_ep_resources(ep);
 	else if (ep->retry_with_mpa_v1) {
@@ -2476,6 +2492,9 @@  static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 		break;
 	}
 	mutex_unlock(&ep->com.mutex);
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
+
 	if (release)
 		release_ep_resources(ep);
 	return 0;
@@ -2721,13 +2740,15 @@  int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
 	struct c4iw_ep *ep;
 	int err = 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_in6 *laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr;
-	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *)
-				      &cm_id->remote_addr;
+	struct sockaddr_in *laddr;
+	struct sockaddr_in *raddr;
+	struct sockaddr_in6 *laddr6;
+	struct sockaddr_in6 *raddr6;
 	__u8 *ra;
 	int iptype;
+	const char *msg_type = "Create Connect Mapping";
+	int async = 0;
+	int iwpm_err = 0;
 
 	if ((conn_param->ord > c4iw_max_read_depth) ||
 	    (conn_param->ird > c4iw_max_read_depth)) {
@@ -2775,6 +2796,44 @@  int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 	}
 	insert_handle(dev, &dev->atid_idr, ep, ep->atid);
 
+	memcpy(&ep->com.local_addr, &cm_id->local_addr,
+	       sizeof(ep->com.local_addr));
+	memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
+	       sizeof(ep->com.remote_addr));
+
+	/* No port mapper available, go with the specified peer information */
+	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
+	       sizeof(ep->com.mapped_local_addr));
+	memcpy(&ep->com.mapped_remote_addr, &cm_id->remote_addr,
+	       sizeof(ep->com.mapped_remote_addr));
+	laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr;
+	raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr;
+	laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr;
+	raddr6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr;
+
+	if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) {
+		iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name,
+						  dev->ibdev.name, async, NULL);
+		if (iwpm_err) {
+			c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
+			PDBG("%s Port Mapper register pid failure (err_code = %d).\n"
+			     , __func__, iwpm_err);
+		}
+	}
+	if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */
+		iwpm_err = c4iw_add_and_query_mapping(ep);
+		if (iwpm_err)
+			PDBG("%s Port Mapper query failure (err_code = %d).\n"
+			     , __func__, iwpm_err);
+	} else
+		pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n"
+			, __func__, c4iw_iwpm_pid);
+	if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr,
+				msg_type)) {
+		err = -ENOMEM;
+		goto fail3;
+	}
+
 	if (cm_id->remote_addr.ss_family == AF_INET) {
 		iptype = 4;
 		ra = (__u8 *)&raddr->sin_addr;
@@ -2809,10 +2868,11 @@  int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 		}
 
 		/* find a route */
-		PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n",
+		PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x sin6_scope_id %d\n",
 		     __func__, laddr6->sin6_addr.s6_addr,
 		     ntohs(laddr6->sin6_port),
-		     raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port));
+		     raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port),
+		     raddr6->sin6_scope_id);
 		ep->dst = find_route6(dev, laddr6->sin6_addr.s6_addr,
 				      raddr6->sin6_addr.s6_addr,
 				      laddr6->sin6_port, raddr6->sin6_port, 0,
@@ -2836,10 +2896,6 @@  int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 
 	state_set(&ep->com, CONNECTING);
 	ep->tos = 0;
-	memcpy(&ep->com.local_addr, &cm_id->local_addr,
-	       sizeof(ep->com.local_addr));
-	memcpy(&ep->com.remote_addr, &cm_id->remote_addr,
-	       sizeof(ep->com.remote_addr));
 
 	/* send connect request to rnic */
 	err = send_connect(ep);
@@ -2850,6 +2906,8 @@  int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 fail4:
 	dst_release(ep->dst);
 fail3:
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
 	remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
 	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
 fail2:
@@ -2862,7 +2920,8 @@  out:
 static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
 {
 	int err;
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ep->com.local_addr;
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
+				    &ep->com.mapped_local_addr;
 
 	c4iw_init_wr_wait(&ep->com.wr_wait);
 	err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0],
@@ -2883,7 +2942,8 @@  static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
 static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)
 {
 	int err;
-	struct sockaddr_in *sin = (struct sockaddr_in *)&ep->com.local_addr;
+	struct sockaddr_in *sin = (struct sockaddr_in *)
+				  &ep->com.mapped_local_addr;
 
 	if (dev->rdev.lldi.enable_fw_ofld_conn) {
 		do {
@@ -2918,6 +2978,9 @@  int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
 	int err = 0;
 	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
 	struct c4iw_listen_ep *ep;
+	const char *msg_type = "Create Listen Mapping";
+	int async = 0;
+	int iwpm_err = 0;
 
 	might_sleep();
 
@@ -2932,6 +2995,7 @@  int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
 	ep->com.cm_id = cm_id;
 	ep->com.dev = dev;
 	ep->backlog = backlog;
+
 	memcpy(&ep->com.local_addr, &cm_id->local_addr,
 	       sizeof(ep->com.local_addr));
 
@@ -2951,6 +3015,34 @@  int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
 		goto fail2;
 	}
 	insert_handle(dev, &dev->stid_idr, ep, ep->stid);
+
+	/* No port mapper available, go with the specified info */
+	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr,
+	       sizeof(ep->com.mapped_local_addr));
+
+	if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) {
+		iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name,
+						  dev->ibdev.name, async, NULL);
+		if (iwpm_err) {
+			c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR;
+			PDBG("%s Port Mapper register pid failure (err_code = %d).\n"
+			     , __func__, iwpm_err);
+		}
+	}
+	if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */
+		iwpm_err = c4iw_add_mapping(ep);
+		if (iwpm_err)
+			PDBG("%s Port Mapper query failure (err_code = %d).\n"
+			     , __func__, iwpm_err);
+	} else
+		pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n"
+			, __func__, c4iw_iwpm_pid);
+	if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr,
+				msg_type)) {
+		err = -ENOMEM;
+		goto fail3;
+	}
+
 	state_set(&ep->com, LISTEN);
 	if (ep->com.local_addr.ss_family == AF_INET)
 		err = create_server4(dev, ep);
@@ -2960,6 +3052,10 @@  int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
 		cm_id->provider_data = ep;
 		goto out;
 	}
+
+fail3:
+	print_addr(&ep->com.mapped_local_addr, "Delete mapped local");
+	c4iw_remove_mapping(&ep->com.mapped_local_addr);
 	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,
 			ep->com.local_addr.ss_family);
 fail2:
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 33d2cc6..8810f78 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -37,6 +37,7 @@ 
 #include <rdma/ib_verbs.h>
 
 #include "iw_cxgb4.h"
+#include "c4iw_netlink.h"
 
 #define DRV_VERSION "0.1"
 
@@ -106,9 +107,9 @@  static int dump_qp(int id, void *p, void *data)
 	if (qp->ep) {
 		if (qp->ep->com.local_addr.ss_family == AF_INET) {
 			struct sockaddr_in *lsin = (struct sockaddr_in *)
-				&qp->ep->com.local_addr;
+				&qp->ep->com.mapped_local_addr;
 			struct sockaddr_in *rsin = (struct sockaddr_in *)
-				&qp->ep->com.remote_addr;
+				&qp->ep->com.mapped_remote_addr;
 
 			cc = snprintf(qpd->buf + qpd->pos, space,
 				      "rc qp sq id %u rq id %u state %u "
@@ -122,9 +123,9 @@  static int dump_qp(int id, void *p, void *data)
 				      &rsin->sin_addr, ntohs(rsin->sin_port));
 		} else {
 			struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)
-				&qp->ep->com.local_addr;
+				&qp->ep->com.mapped_local_addr;
 			struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *)
-				&qp->ep->com.remote_addr;
+				&qp->ep->com.mapped_remote_addr;
 
 			cc = snprintf(qpd->buf + qpd->pos, space,
 				      "rc qp sq id %u rq id %u state %u "
@@ -1210,6 +1211,19 @@  static int __init c4iw_init_module(void)
 		printk(KERN_WARNING MOD
 		       "could not create debugfs entry, continuing\n");
 
+	spin_lock_init(&c4iw_nlmsg_lock);
+	spin_lock_init(&c4iw_mapping_lock);
+
+	/* List of submitted requests, searched for completions */
+	INIT_LIST_HEAD(&c4iw_nlmsg_request_list);
+	/* List of iwpm mappings in use */
+	INIT_LIST_HEAD(&c4iw_mapping_info_list);
+
+	if (ibnl_add_client(RDMA_NL_C4IW, RDMA_NL_IWPM_NUM_OPS,
+			c4iw_nl_cb_table))
+		pr_err("%s[%u]: Failed to add netlink callback\n"
+			, __func__, __LINE__);
+
 	cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info);
 
 	return 0;
@@ -1227,6 +1241,8 @@  static void __exit c4iw_exit_module(void)
 	}
 	mutex_unlock(&dev_mutex);
 	cxgb4_unregister_uld(CXGB4_ULD_RDMA);
+	ibnl_remove_client(RDMA_NL_C4IW);
+	c4iw_destroy_mapinfo_list();
 	c4iw_cm_term();
 	debugfs_remove_recursive(c4iw_debugfs_root);
 }
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 23eaeab..7b3405d 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -152,6 +152,20 @@  struct c4iw_rdev {
 	struct c4iw_stats stats;
 };
 
+static inline void print_addr(struct sockaddr_storage *addr,
+			      const char *msg)
+{
+	struct sockaddr_in *laddr = (struct sockaddr_in *)addr;
+	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)addr;
+
+	if (addr->ss_family == AF_INET)
+		PDBG("%s %s addr %pI4 port 0x%04X\n", __func__, msg
+		     , &laddr->sin_addr.s_addr, ntohs(laddr->sin_port));
+	else
+		PDBG("%s %s addr %pI6 port 0x%04X\n", __func__, msg
+		     , laddr6->sin6_addr.s6_addr, ntohs(laddr6->sin6_port));
+}
+
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
 {
 	return rdev->flags & T4_FATAL_ERROR;
@@ -754,6 +768,8 @@  struct c4iw_ep_common {
 	struct mutex mutex;
 	struct sockaddr_storage local_addr;
 	struct sockaddr_storage remote_addr;
+	struct sockaddr_storage mapped_local_addr;
+	struct sockaddr_storage mapped_remote_addr;
 	struct c4iw_wr_wait wr_wait;
 	unsigned long flags;
 	unsigned long history;