Add support for iWARP Port Mapper (IWPM) user space service
Signed-off-by: Vipul Pandya <[email protected]>
---
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);
+
+ 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;
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html