To support security applications, that need to filter out connections based
on SGID, an ioctl command to retrieve SGID of a given socket is added.

Signed-off-by: Yuval Shaia <yuval.sh...@oracle.com>
---
 drivers/infiniband/ulp/ipoib/Makefile      |    3 +-
 drivers/infiniband/ulp/ipoib/ipoib.h       |   11 ++
 drivers/infiniband/ulp/ipoib/ipoib_ioctl.c |  152 ++++++++++++++++++++++++++++
 drivers/infiniband/ulp/ipoib/ipoib_main.c  |    6 +
 4 files changed, 171 insertions(+), 1 deletions(-)
 create mode 100644 drivers/infiniband/ulp/ipoib/ipoib_ioctl.c

diff --git a/drivers/infiniband/ulp/ipoib/Makefile 
b/drivers/infiniband/ulp/ipoib/Makefile
index e5430dd..9915cf8 100644
--- a/drivers/infiniband/ulp/ipoib/Makefile
+++ b/drivers/infiniband/ulp/ipoib/Makefile
@@ -6,7 +6,8 @@ ib_ipoib-y                                      := ipoib_main.o 
\
                                                   ipoib_verbs.o \
                                                   ipoib_vlan.o \
                                                   ipoib_ethtool.o \
-                                                  ipoib_netlink.o
+                                                  ipoib_netlink.o \
+                                                  ipoib_ioctl.o
 ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM)         += ipoib_cm.o
 ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG)      += ipoib_fs.o
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h 
b/drivers/infiniband/ulp/ipoib/ipoib.h
index edc5b85..01b8d4d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -434,6 +434,15 @@ struct ipoib_neigh {
        unsigned long       alive;
 };
 
+/* ioctl API */
+#define IPOIBGETSGUID          SIOCDEVPRIVATE
+
+struct ipoib_ioctl_getsgid_data {
+       u64     gid;
+       u64     subnet_prefix;
+       int     fd;
+};
+
 #define IPOIB_UD_MTU(ib_mtu)           (ib_mtu - IPOIB_ENCAP_LEN)
 #define IPOIB_UD_BUF_SIZE(ib_mtu)      (ib_mtu + IB_GRH_BYTES)
 
@@ -452,6 +461,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 
*gid);
 extern struct workqueue_struct *ipoib_workqueue;
 
 /* functions */
+struct list_head *ipoib_get_dev_list(struct ib_device *dev);
 
 int ipoib_poll(struct napi_struct *napi, int budget);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
@@ -467,6 +477,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah)
 int ipoib_open(struct net_device *dev);
 int ipoib_add_pkey_attr(struct net_device *dev);
 int ipoib_add_umcast_attr(struct net_device *dev);
+int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 void ipoib_send(struct net_device *dev, struct sk_buff *skb,
                struct ipoib_ah *address, u32 qpn);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c 
b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c
new file mode 100644
index 0000000..124d545
--- /dev/null
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015 Oracle Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <net/arp.h>
+#include <linux/jhash.h>
+#include <net/inet_sock.h>
+#include <net/route.h>
+
+#include "ipoib.h"
+
+static int ipoib_get_sguid(struct net_device *dev, int fd, u64 *sgid,
+                          u64 *subnet_prefix)
+{
+       struct socket *sock;
+       struct inet_sock *inetsock;
+       struct neighbour *neigh;
+       int rc = 0;
+       union ib_gid *gid;
+       struct list_head *dev_list = 0;
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       u16 pkey_index = priv->pkey_index;
+       struct ipoib_dev_priv *child_priv;
+
+       sock = sockfd_lookup(fd, &rc);
+       if (IS_ERR_OR_NULL(sock))
+               return -EINVAL;
+
+       inetsock = inet_sk(sock->sk);
+
+       neigh = neigh_lookup(&arp_tbl, &inetsock->inet_daddr, dev);
+       if (!IS_ERR_OR_NULL(neigh))
+               goto found;
+
+       /* If not found try in all other ipoib devices */
+       dev_list = ipoib_get_dev_list(priv->ca);
+       if (!dev_list)
+               return -EINVAL;
+
+       list_for_each_entry(priv, dev_list, list) {
+               if (priv->pkey_index == pkey_index) {
+                       neigh = neigh_lookup(&arp_tbl, &inetsock->inet_daddr,
+                                            priv->dev);
+                       if (!IS_ERR_OR_NULL(neigh))
+                               goto found;
+               }
+               list_for_each_entry(child_priv, &priv->child_intfs, list) {
+                       if (child_priv->pkey_index == pkey_index) {
+                               neigh = neigh_lookup(&arp_tbl,
+                                                    &inetsock->inet_daddr,
+                                                    child_priv->dev);
+                               if (!IS_ERR_OR_NULL(neigh))
+                                       goto found;
+                       }
+               }
+       }
+
+       return -ENODEV;
+
+found:
+       if (!(neigh->nud_state & NUD_VALID))
+               return -EINVAL;
+
+       gid = (union ib_gid *)(neigh->ha + 4);
+       *sgid = be64_to_cpu(gid->global.interface_id);
+       *subnet_prefix = be64_to_cpu(gid->global.subnet_prefix);
+
+       neigh_release(neigh);
+
+       return 0;
+}
+
+static int ipoib_ioctl_getsguid(struct net_device *dev, struct ifreq *ifr)
+{
+       struct ipoib_ioctl_getsgid_data req_data;
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       int rc;
+
+       rc = copy_from_user(&req_data, ifr->ifr_data,
+                           sizeof(struct ipoib_ioctl_getsgid_data));
+       if (rc != 0) {
+               ipoib_warn(priv, "ioctl fail to copy request data\n");
+               return -EINVAL;
+       }
+       rc = ipoib_get_sguid(dev, req_data.fd, &req_data.gid,
+                            &req_data.subnet_prefix);
+       if (rc) {
+               ipoib_warn(priv, "Invalid fd %d (err=%d)\n",
+                          req_data.fd, rc);
+               return rc;
+       }
+       ipoib_dbg(priv, "ioctl_getsgid: subnet_prefix=0x%llx\n",
+                 req_data.subnet_prefix);
+       ipoib_dbg(priv, "ioctl_getsgid: src_gid=0x%llx\n", req_data.gid);
+       rc = copy_to_user(ifr->ifr_data, &req_data,
+                         sizeof(struct ipoib_ioctl_getsgid_data));
+       if (rc != 0) {
+               ipoib_warn(priv,
+                          "ioctl fail to copy back request data\n");
+               return -EINVAL;
+       }
+
+       return rc;
+}
+
+int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       int rc = -EINVAL;
+
+       switch (cmd) {
+       case IPOIBGETSGUID:
+               rc = ipoib_ioctl_getsguid(dev, ifr);
+               if (rc != 0)
+                       return -EINVAL;
+               break;
+       default:
+               ipoib_warn(priv, "invalid ioctl opcode 0x%x\n", cmd);
+               rc = -EINVAL;
+               break;
+       }
+
+       return rc;
+}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c 
b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index babba05..15665af 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1619,6 +1619,7 @@ static const struct net_device_ops ipoib_netdev_ops = {
        .ndo_tx_timeout          = ipoib_timeout,
        .ndo_set_rx_mode         = ipoib_set_mcast_list,
        .ndo_get_iflink          = ipoib_get_iflink,
+       .ndo_do_ioctl            = ipoib_do_ioctl,
 };
 
 void ipoib_setup(struct net_device *dev)
@@ -1962,6 +1963,11 @@ static void ipoib_add_one(struct ib_device *device)
        ib_set_client_data(device, &ipoib_client, dev_list);
 }
 
+struct list_head *ipoib_get_dev_list(struct ib_device *dev)
+{
+       return ib_get_client_data(dev, &ipoib_client);
+}
+
 static void ipoib_remove_one(struct ib_device *device, void *client_data)
 {
        struct ipoib_dev_priv *priv, *tmp;
-- 
1.7.1

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

Reply via email to