All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
To: Tatyana Nikolova
	<Tatyana.E.Nikolova-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: Roland Dreier <roland-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	robert.o.sharp-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	john.s.lacombe-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
	vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH 4/4] RDMA/cxgb4: Add support for iWARP Port Mapper user space service
Date: Tue, 03 Sep 2013 11:14:39 -0500	[thread overview]
Message-ID: <52260AEF.3020804@opengridcomputing.com> (raw)
In-Reply-To: <20130831194718.GA7552@TENIKOLO-MOBL1>

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-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
>
> ---
>   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-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

      reply	other threads:[~2013-09-03 16:14 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-08-31 19:47 [PATCH 4/4] RDMA/cxgb4: Add support for iWARP Port Mapper user space service Tatyana Nikolova
2013-09-03 16:14 ` Steve Wise [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=52260AEF.3020804@opengridcomputing.com \
    --to=swise-7bpotxp6k4+p2yhjcf5u+vpxobypeauw@public.gmane.org \
    --cc=Tatyana.E.Nikolova-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    --cc=john.s.lacombe-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    --cc=linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=robert.o.sharp-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    --cc=roland-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.