--- /dev/null
+Add functionality to allow the port mapper to provide to its client
+the actual (non-mapped) ip/tcp address information of the remote connecting peer
+
+Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
+---
+ drivers/infiniband/core/iwpm_msg.c | 73 +++++++++++-
+ drivers/infiniband/core/iwpm_util.c | 222 +++++++++++++++++++++++++++++-----
+ drivers/infiniband/core/iwpm_util.h | 15 +++
+ include/rdma/iw_portmap.h | 25 ++++
+ include/uapi/rdma/rdma_netlink.h | 1 +
+ 5 files changed, 302 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
+index b85ddbc..ab08170 100644
+--- a/drivers/infiniband/core/iwpm_msg.c
++++ b/drivers/infiniband/core/iwpm_msg.c
+@@ -468,7 +468,8 @@ add_mapping_response_exit:
+ }
+ EXPORT_SYMBOL(iwpm_add_mapping_cb);
+
+-/* netlink attribute policy for the response to add and query mapping request */
++/* netlink attribute policy for the response to add and query mapping request
++ * and response with remote address info */
+ 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) },
+@@ -559,6 +560,76 @@ query_mapping_response_exit:
+ }
+ EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb);
+
++/*
++ * iwpm_remote_info_cb - Process a port mapper message, containing
++ * the remote connecting peer address info
++ */
++int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
++{
++ struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
++ struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
++ struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
++ struct iwpm_remote_info *rem_info;
++ const char *msg_type;
++ u8 nl_client;
++ int ret = -EINVAL;
++
++ msg_type = "Remote Mapping info";
++ if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
++ resp_query_policy, nltb, msg_type))
++ return ret;
++
++ nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
++ if (!iwpm_valid_client(nl_client)) {
++ pr_info("%s: Invalid port mapper client = %d\n",
++ __func__, nl_client);
++ return ret;
++ }
++ atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
++
++ 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]);
++
++ if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
++ mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
++ pr_info("%s: Sockaddr family doesn't match the requested one\n",
++ __func__);
++ return ret;
++ }
++ rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC);
++ if (!rem_info) {
++ pr_err("%s: Unable to allocate a remote info\n", __func__);
++ ret = -ENOMEM;
++ return ret;
++ }
++ memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr,
++ sizeof(struct sockaddr_storage));
++ memcpy(&rem_info->remote_sockaddr, remote_sockaddr,
++ sizeof(struct sockaddr_storage));
++ memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr,
++ sizeof(struct sockaddr_storage));
++ rem_info->nl_client = nl_client;
++
++ iwpm_add_remote_info(rem_info);
++
++ iwpm_print_sockaddr(local_sockaddr,
++ "remote_info: Local sockaddr:");
++ iwpm_print_sockaddr(mapped_loc_sockaddr,
++ "remote_info: Mapped local sockaddr:");
++ iwpm_print_sockaddr(remote_sockaddr,
++ "remote_info: Remote sockaddr:");
++ iwpm_print_sockaddr(mapped_rem_sockaddr,
++ "remote_info: Mapped remote sockaddr:");
++ return ret;
++}
++EXPORT_SYMBOL(iwpm_remote_info_cb);
++
+ /* netlink attribute policy for the received request for mapping info */
+ static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
+ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
+diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c
+index 5e01389..43b4f25 100644
+--- a/drivers/infiniband/core/iwpm_util.c
++++ b/drivers/infiniband/core/iwpm_util.c
+@@ -33,8 +33,10 @@
+
+ #include "iwpm_util.h"
+
+-#define IWPM_HASH_BUCKET_SIZE 512
+-#define IWPM_HASH_BUCKET_MASK (IWPM_HASH_BUCKET_SIZE - 1)
++#define IWPM_MAPINFO_HASH_SIZE 512
++#define IWPM_MAPINFO_HASH_MASK (IWPM_MAPINFO_HASH_SIZE - 1)
++#define IWPM_REMINFO_HASH_SIZE 64
++#define IWPM_REMINFO_HASH_MASK (IWPM_REMINFO_HASH_SIZE - 1)
+
+ static LIST_HEAD(iwpm_nlmsg_req_list);
+ static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
+@@ -42,31 +44,49 @@ static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
+ static struct hlist_head *iwpm_hash_bucket;
+ static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
+
++static struct hlist_head *iwpm_reminfo_bucket;
++static DEFINE_SPINLOCK(iwpm_reminfo_lock);
++
+ static DEFINE_MUTEX(iwpm_admin_lock);
+ static struct iwpm_admin_data iwpm_admin;
+
+ int iwpm_init(u8 nl_client)
+ {
++ int ret = 0;
+ if (iwpm_valid_client(nl_client))
+ return -EINVAL;
+ mutex_lock(&iwpm_admin_lock);
+ if (atomic_read(&iwpm_admin.refcount) == 0) {
+- iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE *
++ iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE *
+ sizeof(struct hlist_head), GFP_KERNEL);
+ if (!iwpm_hash_bucket) {
+- mutex_unlock(&iwpm_admin_lock);
++ ret = -ENOMEM;
+ pr_err("%s Unable to create mapinfo hash table\n", __func__);
+- return -ENOMEM;
++ goto init_exit;
++ }
++ iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE *
++ sizeof(struct hlist_head), GFP_KERNEL);
++ if (!iwpm_reminfo_bucket) {
++ kfree(iwpm_hash_bucket);
++ ret = -ENOMEM;
++ pr_err("%s Unable to create reminfo hash table\n", __func__);
++ goto init_exit;
+ }
+ }
+ atomic_inc(&iwpm_admin.refcount);
++init_exit:
+ mutex_unlock(&iwpm_admin_lock);
+- iwpm_set_valid(nl_client, 1);
+- return 0;
++ if (!ret) {
++ iwpm_set_valid(nl_client, 1);
++ pr_debug("%s: Mapinfo and reminfo tables are created\n",
++ __func__);
++ }
++ return ret;
+ }
+ EXPORT_SYMBOL(iwpm_init);
+
+ static void free_hash_bucket(void);
++static void free_reminfo_bucket(void);
+
+ int iwpm_exit(u8 nl_client)
+ {
+@@ -81,7 +101,8 @@ int iwpm_exit(u8 nl_client)
+ }
+ if (atomic_dec_and_test(&iwpm_admin.refcount)) {
+ free_hash_bucket();
+- pr_debug("%s: Mapinfo hash table is destroyed\n", __func__);
++ free_reminfo_bucket();
++ pr_debug("%s: Resources are destroyed\n", __func__);
+ }
+ mutex_unlock(&iwpm_admin_lock);
+ iwpm_set_valid(nl_client, 0);
+@@ -89,7 +110,7 @@ int iwpm_exit(u8 nl_client)
+ }
+ EXPORT_SYMBOL(iwpm_exit);
+
+-static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *,
++static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
+ struct sockaddr_storage *);
+
+ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
+@@ -99,9 +120,10 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
+ struct hlist_head *hash_bucket_head;
+ struct iwpm_mapping_info *map_info;
+ unsigned long flags;
++ int ret = -EINVAL;
+
+ if (!iwpm_valid_client(nl_client))
+- return -EINVAL;
++ return ret;
+ map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
+ if (!map_info) {
+ pr_err("%s: Unable to allocate a mapping info\n", __func__);
+@@ -115,13 +137,16 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
+
+ spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+ if (iwpm_hash_bucket) {
+- hash_bucket_head = get_hash_bucket_head(
++ hash_bucket_head = get_mapinfo_hash_bucket(
+ &map_info->local_sockaddr,
+ &map_info->mapped_sockaddr);
+- hlist_add_head(&map_info->hlist_node, hash_bucket_head);
++ if (hash_bucket_head) {
++ hlist_add_head(&map_info->hlist_node, hash_bucket_head);
++ ret = 0;
++ }
+ }
+ spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
+- return 0;
++ return ret;
+ }
+ EXPORT_SYMBOL(iwpm_create_mapinfo);
+
+@@ -139,9 +164,12 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
+
+ spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+ if (iwpm_hash_bucket) {
+- hash_bucket_head = get_hash_bucket_head(
++ hash_bucket_head = get_mapinfo_hash_bucket(
+ local_sockaddr,
+ mapped_local_addr);
++ if (!hash_bucket_head)
++ goto remove_mapinfo_exit;
++
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
+ hlist_for_each_entry_safe(map_info, node, tmp_hlist_node,
+ hash_bucket_head, hlist_node) {
+@@ -159,6 +187,7 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
+ }
+ }
+ }
++remove_mapinfo_exit:
+ spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
+ return ret;
+ }
+@@ -176,7 +205,7 @@ static void free_hash_bucket(void)
+
+ /* remove all the mapinfo data from the list */
+ spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+- for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
++ for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
+ hlist_for_each_entry_safe(map_info, node, tmp_hlist_node,
+ &iwpm_hash_bucket[i], hlist_node) {
+@@ -194,6 +223,110 @@ static void free_hash_bucket(void)
+ spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
+ }
+
++static void free_reminfo_bucket(void)
++{
++ struct hlist_node *tmp_hlist_node;
++ struct iwpm_remote_info *rem_info;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
++ struct hlist_node *node;
++#endif
++ unsigned long flags;
++ int i;
++
++ /* remove all the remote info from the list */
++ spin_lock_irqsave(&iwpm_reminfo_lock, flags);
++ for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) {
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
++ hlist_for_each_entry_safe(rem_info, node, tmp_hlist_node,
++ &iwpm_reminfo_bucket[i], hlist_node) {
++#else
++ hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
++ &iwpm_reminfo_bucket[i], hlist_node) {
++#endif
++ hlist_del_init(&rem_info->hlist_node);
++ kfree(rem_info);
++ }
++ }
++ /* free the hash list */
++ kfree(iwpm_reminfo_bucket);
++ iwpm_reminfo_bucket = NULL;
++ spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
++}
++
++static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *,
++ struct sockaddr_storage *);
++
++void iwpm_add_remote_info(struct iwpm_remote_info *rem_info)
++{
++ struct hlist_head *hash_bucket_head;
++ unsigned long flags;
++
++ spin_lock_irqsave(&iwpm_reminfo_lock, flags);
++ if (iwpm_reminfo_bucket) {
++ hash_bucket_head = get_reminfo_hash_bucket(
++ &rem_info->mapped_loc_sockaddr,
++ &rem_info->mapped_rem_sockaddr);
++ if (hash_bucket_head)
++ hlist_add_head(&rem_info->hlist_node, hash_bucket_head);
++ }
++ spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
++}
++
++int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
++ struct sockaddr_storage *mapped_rem_addr,
++ struct sockaddr_storage *remote_addr,
++ u8 nl_client)
++{
++ struct hlist_node *tmp_hlist_node;
++ struct hlist_head *hash_bucket_head;
++ struct iwpm_remote_info *rem_info = NULL;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
++ struct hlist_node *node;
++#endif
++ unsigned long flags;
++ int ret = -EINVAL;
++
++ if (!iwpm_valid_client(nl_client)) {
++ pr_info("%s: Invalid client = %d\n", __func__, nl_client);
++ return ret;
++ }
++ spin_lock_irqsave(&iwpm_reminfo_lock, flags);
++ if (iwpm_reminfo_bucket) {
++ hash_bucket_head = get_reminfo_hash_bucket(
++ mapped_loc_addr,
++ mapped_rem_addr);
++ if (!hash_bucket_head)
++ goto get_remote_info_exit;
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
++ hlist_for_each_entry_safe(rem_info, node, tmp_hlist_node,
++ hash_bucket_head, hlist_node) {
++#else
++ hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
++ hash_bucket_head, hlist_node) {
++#endif
++ if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr,
++ mapped_loc_addr) &&
++ !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr,
++ mapped_rem_addr)) {
++
++ memcpy(remote_addr, &rem_info->remote_sockaddr,
++ sizeof(struct sockaddr_storage));
++ iwpm_print_sockaddr(remote_addr,
++ "get_remote_info: Remote sockaddr:");
++
++ hlist_del_init(&rem_info->hlist_node);
++ kfree(rem_info);
++ ret = 0;
++ break;
++ }
++ }
++ }
++get_remote_info_exit:
++ spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
++ return ret;
++}
++EXPORT_SYMBOL(iwpm_get_remote_info);
++
+ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
+ u8 nl_client, gfp_t gfp)
+ {
+@@ -423,31 +556,54 @@ static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
+ return hash;
+ }
+
+-static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage
+- *local_sockaddr,
+- struct sockaddr_storage
+- *mapped_sockaddr)
++static int get_hash_bucket(struct sockaddr_storage *a_sockaddr,
++ struct sockaddr_storage *b_sockaddr, u32 *hash)
+ {
+- u32 local_hash, mapped_hash, hash;
++ u32 a_hash, b_hash;
+
+- if (local_sockaddr->ss_family == AF_INET) {
+- local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr);
+- mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr);
++ if (a_sockaddr->ss_family == AF_INET) {
++ a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr);
++ b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr);
+
+- } else if (local_sockaddr->ss_family == AF_INET6) {
+- local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr);
+- mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr);
++ } else if (a_sockaddr->ss_family == AF_INET6) {
++ a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr);
++ b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr);
+ } else {
+ pr_err("%s: Invalid sockaddr family\n", __func__);
+- return NULL;
++ return -EINVAL;
+ }
+
+- if (local_hash == mapped_hash) /* if port mapper isn't available */
+- hash = local_hash;
++ if (a_hash == b_hash) /* if port mapper isn't available */
++ *hash = a_hash;
+ else
+- hash = jhash_2words(local_hash, mapped_hash, 0);
++ *hash = jhash_2words(a_hash, b_hash, 0);
++ return 0;
++}
++
++static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage
++ *local_sockaddr, struct sockaddr_storage
++ *mapped_sockaddr)
++{
++ u32 hash;
++ int ret;
++
++ ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash);
++ if (ret)
++ return NULL;
++ return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK];
++}
+
+- return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK];
++static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage
++ *mapped_loc_sockaddr, struct sockaddr_storage
++ *mapped_rem_sockaddr)
++{
++ u32 hash;
++ int ret;
++
++ ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash);
++ if (ret)
++ return NULL;
++ return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK];
+ }
+
+ static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
+@@ -529,7 +685,7 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
+ }
+ skb_num++;
+ spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+- for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
++ for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
+ hlist_for_each_entry(map_info, node,
+ &iwpm_hash_bucket[i], hlist_node) {
+@@ -617,7 +773,7 @@ int iwpm_mapinfo_available(void)
+
+ spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
+ if (iwpm_hash_bucket) {
+- for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) {
++ for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
+ if (!hlist_empty(&iwpm_hash_bucket[i])) {
+ full_bucket = 1;
+ break;
+diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h
+index 9777c86..ee2d9ff 100644
+--- a/drivers/infiniband/core/iwpm_util.h
++++ b/drivers/infiniband/core/iwpm_util.h
+@@ -76,6 +76,14 @@ struct iwpm_mapping_info {
+ u8 nl_client;
+ };
+
++struct iwpm_remote_info {
++ struct hlist_node hlist_node;
++ struct sockaddr_storage remote_sockaddr;
++ struct sockaddr_storage mapped_loc_sockaddr;
++ struct sockaddr_storage mapped_rem_sockaddr;
++ u8 nl_client;
++};
++
+ struct iwpm_admin_data {
+ atomic_t refcount;
+ atomic_t nlmsg_seq;
+@@ -128,6 +136,13 @@ int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request);
+ int iwpm_get_nlmsg_seq(void);
+
+ /**
++ * iwpm_add_reminfo - Add remote address info of the connecting peer
++ * to the remote info hash table
++ * @reminfo: The remote info to be added
++ */
++void iwpm_add_remote_info(struct iwpm_remote_info *reminfo);
++
++/**
+ * iwpm_valid_client - Check if the port mapper client is valid
+ * @nl_client: The index of the netlink client
+ *
+diff --git a/include/rdma/iw_portmap.h b/include/rdma/iw_portmap.h
+index 928b277..fda3167 100644
+--- a/include/rdma/iw_portmap.h
++++ b/include/rdma/iw_portmap.h
+@@ -148,6 +148,16 @@ int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *);
+ int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *);
+
+ /**
++ * iwpm_remote_info_cb - Process remote connecting peer address info, which
++ * the port mapper has received from the connecting peer
++ *
++ * @cb: Contains the received message (payload and netlink header)
++ *
++ * Stores the IPv4/IPv6 address info in a hash table
++ */
++int iwpm_remote_info_cb(struct sk_buff *, struct netlink_callback *);
++
++/**
+ * iwpm_mapping_error_cb - Process port mapper notification for error
+ *
+ * @skb:
+@@ -175,6 +185,21 @@ int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
+ int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *);
+
+ /**
++ * iwpm_get_remote_info - Get the remote connecting peer address info
++ *
++ * @mapped_loc_addr: Mapped local address of the listening peer
++ * @mapped_rem_addr: Mapped remote address of the connecting peer
++ * @remote_addr: To store the remote address of the connecting peer
++ * @nl_client: The index of the netlink client
++ *
++ * The remote address info is retrieved and provided to the client in
++ * the remote_addr. After that it is removed from the hash table
++ */
++int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
++ struct sockaddr_storage *mapped_rem_addr,
++ struct sockaddr_storage *remote_addr, u8 nl_client);
++
++/**
+ * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
+ * info in a hash table
+ * @local_addr: Local ip/tcp address
+diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h
+index de69170..6e4bb42 100644
+--- a/include/uapi/rdma/rdma_netlink.h
++++ b/include/uapi/rdma/rdma_netlink.h
+@@ -37,6 +37,7 @@ enum {
+ RDMA_NL_IWPM_ADD_MAPPING,
+ RDMA_NL_IWPM_QUERY_MAPPING,
+ RDMA_NL_IWPM_REMOVE_MAPPING,
++ RDMA_NL_IWPM_REMOTE_INFO,
+ RDMA_NL_IWPM_HANDLE_ERR,
+ RDMA_NL_IWPM_MAPINFO,
+ RDMA_NL_IWPM_MAPINFO_NUM,
+--
+1.7.1
+
--- /dev/null
+Get the actual (non-mapped) ip/tcp address of the remote connecting peer
+from the port mapper and report the address info to the user space application
+at the time of connection establishment
+
+Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
+---
+ drivers/infiniband/hw/nes/nes.c | 1 +
+ drivers/infiniband/hw/nes/nes_cm.c | 65 ++++++++++++++++++++++++++---------
+ 2 files changed, 49 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
+index 3b2a6dc..9f9d5c5 100644
+--- a/drivers/infiniband/hw/nes/nes.c
++++ b/drivers/infiniband/hw/nes/nes.c
+@@ -116,6 +116,7 @@ static struct ibnl_client_cbs nes_nl_cb_table[] = {
+ [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
+ [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
+ [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
++ [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
+ [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
+ [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
+ [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
+diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
+index 6f09a72..785c2fa 100644
+--- a/drivers/infiniband/hw/nes/nes_cm.c
++++ b/drivers/infiniband/hw/nes/nes_cm.c
+@@ -596,27 +596,52 @@ static void nes_form_reg_msg(struct nes_vnic *nesvnic,
+ memcpy(pm_msg->if_name, nesvnic->netdev->name, IWPM_IFNAME_SIZE);
+ }
+
++static void record_sockaddr_info(struct sockaddr_storage *addr_info,
++ nes_addr_t *ip_addr, u16 *port_num)
++{
++ struct sockaddr_in *in_addr = (struct sockaddr_in *)addr_info;
++
++ if (in_addr->sin_family == AF_INET) {
++ *ip_addr = ntohl(in_addr->sin_addr.s_addr);
++ *port_num = ntohs(in_addr->sin_port);
++ }
++}
++
+ /*
+ * nes_record_pm_msg - Save the received mapping info
+ */
+ static void nes_record_pm_msg(struct nes_cm_info *cm_info,
+ struct iwpm_sa_data *pm_msg)
+ {
+- struct sockaddr_in *mapped_loc_addr =
+- (struct sockaddr_in *)&pm_msg->mapped_loc_addr;
+- struct sockaddr_in *mapped_rem_addr =
+- (struct sockaddr_in *)&pm_msg->mapped_rem_addr;
+-
+- if (mapped_loc_addr->sin_family == AF_INET) {
+- cm_info->mapped_loc_addr =
+- ntohl(mapped_loc_addr->sin_addr.s_addr);
+- cm_info->mapped_loc_port = ntohs(mapped_loc_addr->sin_port);
+- }
+- if (mapped_rem_addr->sin_family == AF_INET) {
+- cm_info->mapped_rem_addr =
+- ntohl(mapped_rem_addr->sin_addr.s_addr);
+- cm_info->mapped_rem_port = ntohs(mapped_rem_addr->sin_port);
+- }
++ record_sockaddr_info(&pm_msg->mapped_loc_addr,
++ &cm_info->mapped_loc_addr, &cm_info->mapped_loc_port);
++
++ record_sockaddr_info(&pm_msg->mapped_rem_addr,
++ &cm_info->mapped_rem_addr, &cm_info->mapped_rem_port);
++}
++
++/*
++ * nes_get_reminfo - Get the address info of the remote connecting peer
++ */
++static int nes_get_remote_addr(struct nes_cm_node *cm_node)
++{
++ struct sockaddr_storage mapped_loc_addr, mapped_rem_addr;
++ struct sockaddr_storage remote_addr;
++ int ret;
++
++ nes_create_sockaddr(htonl(cm_node->mapped_loc_addr),
++ htons(cm_node->mapped_loc_port), &mapped_loc_addr);
++ nes_create_sockaddr(htonl(cm_node->mapped_rem_addr),
++ htons(cm_node->mapped_rem_port), &mapped_rem_addr);
++
++ ret = iwpm_get_remote_info(&mapped_loc_addr, &mapped_rem_addr,
++ &remote_addr, RDMA_NL_NES);
++ if (ret)
++ nes_debug(NES_DBG_CM, "Unable to find remote peer address info\n");
++ else
++ record_sockaddr_info(&remote_addr, &cm_node->rem_addr,
++ &cm_node->rem_port);
++ return ret;
+ }
+
+ /**
+@@ -1566,9 +1591,14 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
+ return NULL;
+
+ /* set our node specific transport info */
+- cm_node->loc_addr = cm_info->loc_addr;
++ if (listener) {
++ cm_node->loc_addr = listener->loc_addr;
++ cm_node->loc_port = listener->loc_port;
++ } else {
++ cm_node->loc_addr = cm_info->loc_addr;
++ cm_node->loc_port = cm_info->loc_port;
++ }
+ cm_node->rem_addr = cm_info->rem_addr;
+- cm_node->loc_port = cm_info->loc_port;
+ cm_node->rem_port = cm_info->rem_port;
+
+ cm_node->mapped_loc_addr = cm_info->mapped_loc_addr;
+@@ -2151,6 +2181,7 @@ static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
+ cm_node->state = NES_CM_STATE_ESTABLISHED;
+ if (datasize) {
+ cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
++ nes_get_remote_addr(cm_node);
+ handle_rcv_mpa(cm_node, skb);
+ } else { /* rcvd ACK only */
+ dev_kfree_skb_any(skb);
+--
+1.7.1
+
--- /dev/null
+From: Steve Wise <swise@opengridcomputing.com>
+
+When iWARP port mapping is being done, the passive side of a connection
+only knows the mapped address/port of the peer. So now query the IWPM
+to get the actual address/port of the peer.
+
+Also setup the passive side endpoint to correctly display the actual
+and mapped addresses for the new connection.
+
+Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+---
+
+ drivers/infiniband/hw/cxgb4/cm.c | 54 +++++++++++++++++++++++++++++++---
+ drivers/infiniband/hw/cxgb4/device.c | 1 +
+ 2 files changed, 51 insertions(+), 4 deletions(-)
+
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index c2fb71c..f6c7b32 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -580,6 +580,22 @@ static void c4iw_record_pm_msg(struct c4iw_ep *ep,
+ sizeof(ep->com.mapped_remote_addr));
+ }
+
++static int get_remote_addr(struct c4iw_ep *ep)
++{
++ int ret;
++
++ print_addr(&ep->com, __func__, "get_remote_addr");
++
++ ret = iwpm_get_remote_info(&ep->com.mapped_local_addr,
++ &ep->com.mapped_remote_addr,
++ &ep->com.remote_addr, RDMA_NL_C4IW);
++ if (ret)
++ pr_info(MOD "Unable to find remote peer addr info - err %d\n",
++ ret);
++
++ return ret;
++}
++
+ static void best_mtu(const unsigned short *mtus, unsigned short mtu,
+ unsigned int *idx, int use_ts)
+ {
+@@ -2343,27 +2359,57 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
+ state_set(&child_ep->com, CONNECTING);
+ child_ep->com.dev = dev;
+ child_ep->com.cm_id = NULL;
++
++ /*
++ * The mapped_local and mapped_remote addresses get setup with
++ * the actual 4-tuple. The local address will be based on the
++ * actual local address of the connection, but on the port number
++ * of the parent listening endpoint. The remote address is
++ * setup based on a query to the IWPM since we don't know what it
++ * originally was before mapping. If no mapping was done, then
++ * mapped_remote == remote, and mapped_local == local.
++ */
+ if (iptype == 4) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)
+- &child_ep->com.local_addr;
++ &child_ep->com.mapped_local_addr;
++
+ sin->sin_family = PF_INET;
+ sin->sin_port = local_port;
+ sin->sin_addr.s_addr = *(__be32 *)local_ip;
+- sin = (struct sockaddr_in *)&child_ep->com.remote_addr;
++
++ sin = (struct sockaddr_in *)&child_ep->com.local_addr;
++ sin->sin_family = PF_INET;
++ sin->sin_port = ((struct sockaddr_in *)
++ &parent_ep->com.local_addr)->sin_port;
++ sin->sin_addr.s_addr = *(__be32 *)local_ip;
++
++ sin = (struct sockaddr_in *)&child_ep->com.mapped_remote_addr;
+ sin->sin_family = PF_INET;
+ sin->sin_port = peer_port;
+ sin->sin_addr.s_addr = *(__be32 *)peer_ip;
+ } else {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
+- &child_ep->com.local_addr;
++ &child_ep->com.mapped_local_addr;
++
+ sin6->sin6_family = PF_INET6;
+ sin6->sin6_port = local_port;
+ memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
+- sin6 = (struct sockaddr_in6 *)&child_ep->com.remote_addr;
++
++ sin6 = (struct sockaddr_in6 *)&child_ep->com.local_addr;
++ sin6->sin6_family = PF_INET6;
++ sin6->sin6_port = ((struct sockaddr_in6 *)
++ &parent_ep->com.local_addr)->sin6_port;
++ memcpy(sin6->sin6_addr.s6_addr, local_ip, 16);
++
++ sin6 = (struct sockaddr_in6 *)&child_ep->com.mapped_remote_addr;
+ sin6->sin6_family = PF_INET6;
+ sin6->sin6_port = peer_port;
+ memcpy(sin6->sin6_addr.s6_addr, peer_ip, 16);
+ }
++ memcpy(&child_ep->com.remote_addr, &child_ep->com.mapped_remote_addr,
++ sizeof(child_ep->com.remote_addr));
++ get_remote_addr(child_ep);
++
+ c4iw_get_ep(&parent_ep->com);
+ child_ep->parent_ep = parent_ep;
+ child_ep->tos = GET_POPEN_TOS(ntohl(req->tos_stid));
+diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
+index 72f1f05..4c0f238 100644
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -93,6 +93,7 @@ static struct ibnl_client_cbs c4iw_nl_cb_table[] = {
+ [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
+ [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
+ [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
++ [RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
+ [RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
+ [RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
+ };
--- /dev/null
+IWPM_REG_CLIENT and IWPM_PREV_REG_CLIENT are added:
+
+IWPM_REG_CLIENT is a client, registered with the user
+space port mapper daemon, available at the time of the
+client register pid request.
+IWPM_PREV_REG_CLIENT is a client, which has been IWPM_REG_CLIENT
+before the user space port mapper daemon is stopped.
+After restarting the port mapper, IWPM_PREV_REG_CLIENTs provide
+their mapping info to the port mapper daemon and
+they are allowed to send remove mapping requests aftewards.
+
+Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
+---
+ drivers/infiniband/core/iwpm_msg.c | 13 +++++++------
+ drivers/infiniband/core/iwpm_util.c | 1 +
+ drivers/infiniband/core/iwpm_util.h | 3 +++
+ 3 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
+index ab08170..2aca295 100644
+--- a/drivers/infiniband/core/iwpm_msg.c
++++ b/drivers/infiniband/core/iwpm_msg.c
+@@ -67,7 +67,9 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
+ err_str = "Invalid port mapper client";
+ goto pid_query_error;
+ }
+- if (iwpm_registered_client(nl_client))
++ if (iwpm_registered_client(nl_client) == IWPM_REG_CLIENT)
++ return 0;
++ if (iwpm_user_pid == IWPM_PID_UNAVAILABLE)
+ return 0;
+ skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client);
+ if (!skb) {
+@@ -106,7 +108,6 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
+ ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
+ if (ret) {
+ skb = NULL; /* skb is freed in the netlink send-op handling */
+- iwpm_set_registered(nl_client, 1);
+ iwpm_user_pid = IWPM_PID_UNAVAILABLE;
+ err_str = "Unable to send a nlmsg";
+ goto pid_query_error;
+@@ -144,7 +145,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
+ err_str = "Invalid port mapper client";
+ goto add_mapping_error;
+ }
+- if (!iwpm_registered_client(nl_client)) {
++ if (iwpm_registered_client(nl_client) != IWPM_REG_CLIENT) {
+ err_str = "Unregistered port mapper client";
+ goto add_mapping_error;
+ }
+@@ -214,7 +215,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
+ err_str = "Invalid port mapper client";
+ goto query_mapping_error;
+ }
+- if (!iwpm_registered_client(nl_client)) {
++ if (iwpm_registered_client(nl_client) != IWPM_REG_CLIENT) {
+ err_str = "Unregistered port mapper client";
+ goto query_mapping_error;
+ }
+@@ -388,7 +389,7 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
+ pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
+ __func__, iwpm_user_pid);
+ if (iwpm_valid_client(nl_client))
+- iwpm_set_registered(nl_client, 1);
++ iwpm_set_registered(nl_client, IWPM_REG_CLIENT);
+ register_pid_response_exit:
+ nlmsg_request->request_done = 1;
+ /* always for found nlmsg_request */
+@@ -669,7 +670,7 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
+ __func__, nl_client);
+ return ret;
+ }
+- iwpm_set_registered(nl_client, 0);
++ iwpm_set_registered(nl_client, IWPM_PREV_REG_CLIENT);
+ atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+ if (!iwpm_mapinfo_available())
+ return 0;
+diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c
+index a626795..7a20a1b 100644
+--- a/drivers/infiniband/core/iwpm_util.c
++++ b/drivers/infiniband/core/iwpm_util.c
+@@ -106,6 +106,7 @@ int iwpm_exit(u8 nl_client)
+ }
+ mutex_unlock(&iwpm_admin_lock);
+ iwpm_set_valid(nl_client, 0);
++ iwpm_set_registered(nl_client, 0);
+ return 0;
+ }
+ EXPORT_SYMBOL(iwpm_exit);
+diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h
+index ee2d9ff..b1dfd1a 100644
+--- a/drivers/infiniband/core/iwpm_util.h
++++ b/drivers/infiniband/core/iwpm_util.h
+@@ -58,6 +58,9 @@
+ #define IWPM_PID_UNDEFINED -1
+ #define IWPM_PID_UNAVAILABLE -2
+
++#define IWPM_REG_CLIENT 1
++#define IWPM_PREV_REG_CLIENT 2
++
+ struct iwpm_nlmsg_request {
+ struct list_head inprocess_list;
+ __u32 nlmsg_seq;
+--
+1.7.1
+