lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 31 Aug 2020 11:58:12 -0500
From:   Thomas Falcon <tlfalcon@...ux.ibm.com>
To:     netdev@...r.kernel.org
Cc:     drt@...ux.vnet.ibm.com, sukadev@...ux.vnet.ibm.com,
        ljp@...ux.vnet.ibm.com, cforno12@...ux.ibm.com,
        Thomas Falcon <tlfalcon@...ux.ibm.com>
Subject: [PATCH net-next 4/5] ibmvnic: Reporting device ACL settings through sysfs

Access Control Lists can be defined for each IBM VNIC
adapter at time of creation. MAC address and VLAN ID's
may be specified, as well as a Port VLAN ID (PVID).
These may all be requested though read-only sysfs files:
mac_acl, vlan_acl, and pvid. When these files are read,
a series of Command-Response Queue (CRQ) commands is sent to
firmware. The first command requests the size of the ACL
data. The driver allocates a buffer of this size and passes
the address in a second CRQ command to firmware, which then
writes the ACL data to this buffer. This data is then parsed
and printed to the respective sysfs file.

Signed-off-by: Thomas Falcon <tlfalcon@...ux.ibm.com>
---
 drivers/net/ethernet/ibm/ibmvnic.c | 199 +++++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/ibm/ibmvnic.h |  26 ++++-
 2 files changed, 222 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 91b9cc3..36dfa69 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -1163,6 +1163,60 @@ static int __ibmvnic_open(struct net_device *netdev)
 	return rc;
 }
 
+static int ibmvnic_query_acl_sz(struct ibmvnic_adapter *adapter)
+{
+	union ibmvnic_crq crq;
+
+	memset(&crq, 0, sizeof(crq));
+	crq.acl_query.first = IBMVNIC_CRQ_CMD;
+	crq.acl_query.cmd = ACL_QUERY;
+
+	if (ibmvnic_send_crq(adapter, &crq))
+		return -EIO;
+	return 0;
+}
+
+static int ibmvnic_request_acl_buf(struct ibmvnic_adapter *adapter)
+{
+	struct device *dev = &adapter->vdev->dev;
+	union ibmvnic_crq rcrq;
+	int rc;
+
+	rc = 0;
+	adapter->acl_buf = kmalloc(adapter->acl_buf_sz, GFP_KERNEL);
+	if (!adapter->acl_buf) {
+		rc = -ENOMEM;
+		goto acl_alloc_err;
+	}
+	adapter->acl_buf_token = dma_map_single(dev, adapter->acl_buf,
+						adapter->acl_buf_sz,
+						DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, adapter->acl_buf_token)) {
+		rc = -ENOMEM;
+		goto acl_dma_err;
+	}
+	memset(&rcrq, 0, sizeof(rcrq));
+	rcrq.acl_query.first = IBMVNIC_CRQ_CMD;
+	rcrq.acl_query.cmd = ACL_QUERY;
+	rcrq.acl_query.ioba = cpu_to_be32(adapter->acl_buf_token);
+	rcrq.acl_query.len = cpu_to_be32(adapter->acl_buf_sz);
+	if (ibmvnic_send_crq(adapter, &rcrq)) {
+		rc = -EIO;
+		goto acl_query_err;
+	}
+	return 0;
+acl_query_err:
+	dma_unmap_single(dev, adapter->acl_buf_token,
+			 adapter->acl_buf_sz, DMA_FROM_DEVICE);
+	adapter->acl_buf_token = 0;
+	adapter->acl_buf_sz = 0;
+acl_dma_err:
+	kfree(adapter->acl_buf);
+	adapter->acl_buf = NULL;
+acl_alloc_err:
+	return rc;
+}
+
 static int ibmvnic_open(struct net_device *netdev)
 {
 	struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@@ -4635,6 +4689,25 @@ static int handle_query_phys_parms_rsp(union ibmvnic_crq *crq,
 	return rc;
 }
 
+static void handle_acl_query_rsp(struct ibmvnic_adapter *adapter,
+				 union ibmvnic_crq *crq)
+{
+	struct net_device *netdev = adapter->netdev;
+	u8 rcode;
+
+	rcode = crq->acl_query_rsp.rc.code;
+	adapter->fw_done_rc = rcode;
+	/* NOMEMORY is returned when ACL buffer size request is successful */
+	if (rcode == NOMEMORY) {
+		adapter->acl_buf_sz = be32_to_cpu(crq->acl_query_rsp.len);
+		netdev_dbg(netdev, "ACL buffer size is %d.\n",
+			   adapter->acl_buf_sz);
+	} else if (rcode != SUCCESS) {
+		netdev_err(netdev, "ACL query failed, rc = %u\n", rcode);
+	}
+	complete(&adapter->fw_done);
+}
+
 static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
 			       struct ibmvnic_adapter *adapter)
 {
@@ -4798,6 +4871,9 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
 		adapter->fw_done_rc = handle_query_phys_parms_rsp(crq, adapter);
 		complete(&adapter->fw_done);
 		break;
+	case ACL_QUERY_RSP:
+		handle_acl_query_rsp(adapter, crq);
+		break;
 	default:
 		netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
 			   gen_crq->cmd);
@@ -5199,6 +5275,9 @@ static int ibmvnic_remove(struct vio_dev *dev)
 }
 
 static struct device_attribute dev_attr_failover;
+static struct device_attribute dev_attr_vlan_acl;
+static struct device_attribute dev_attr_mac_acl;
+static struct device_attribute dev_attr_pvid;
 
 static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
@@ -5234,10 +5313,130 @@ static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+static int ibmvnic_get_acls(struct ibmvnic_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int rc;
+
+	mutex_lock(&adapter->fw_lock);
+	reinit_completion(&adapter->fw_done);
+	adapter->fw_done_rc = 0;
+	rc = ibmvnic_query_acl_sz(adapter);
+	if (rc) {
+		netdev_err(netdev, "Query ACL buffer size failed, rc = %d\n",
+			   rc);
+		goto out;
+	}
+	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
+	if (rc) {
+		netdev_err(netdev,
+			   "Query ACL buffer size did not complete, rc = %d\n",
+			   rc);
+		goto out;
+	}
+	/* NOMEMORY is returned when the ACL buffer size is retrieved
+	 * successfully
+	 */
+	if (adapter->fw_done_rc != NOMEMORY) {
+		netdev_err(netdev, "Unable to get ACL buffer size, rc = %d\n",
+			   adapter->fw_done_rc);
+		rc = -EIO;
+		goto out;
+	}
+	reinit_completion(&adapter->fw_done);
+	rc = ibmvnic_request_acl_buf(adapter);
+	if (rc) {
+		netdev_err(netdev, "ACL buffer request failed, rc = %d\n", rc);
+		goto out;
+	}
+	rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
+	if (rc) {
+		netdev_err(netdev,
+			   "ACL buffer request did not complete, rc = %d\n",
+			   rc);
+		goto out;
+	}
+	if (adapter->fw_done_rc != SUCCESS) {
+		netdev_err(netdev, "Unable to retrieve ACL buffer, rc = %d\n",
+			   adapter->fw_done_rc);
+		rc = -EIO;
+	}
+out:
+	mutex_unlock(&adapter->fw_lock);
+	return rc;
+}
+
+static ssize_t acl_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct ibmvnic_acl_buffer *acl_buf;
+	struct ibmvnic_adapter *adapter;
+	struct net_device *netdev;
+	int num_entries;
+	ssize_t rsize;
+	int offset;
+	int rc;
+	int i;
+
+	rsize = 0;
+	netdev = dev_get_drvdata(dev);
+	adapter = netdev_priv(netdev);
+	rc = ibmvnic_get_acls(adapter);
+	if (rc)
+		return rc;
+	acl_buf = adapter->acl_buf;
+	if (attr == &dev_attr_mac_acl) {
+		offset = be32_to_cpu(acl_buf->offset_mac_addrs);
+		num_entries = be32_to_cpu(acl_buf->num_mac_addrs);
+		if (num_entries == 0)
+			goto out;
+		for (i = 0; i < num_entries; i++) {
+			char *entry = (char *)acl_buf + offset + i * 6;
+
+			rsize += scnprintf(buf + rsize, PAGE_SIZE,
+					   "%pM\n", entry);
+		}
+	} else if (attr == &dev_attr_vlan_acl) {
+		offset = be32_to_cpu(acl_buf->offset_vlan_ids);
+		num_entries = be32_to_cpu(acl_buf->num_vlan_ids);
+		if (num_entries == 0)
+			goto out;
+		for (i = 0 ; i < num_entries; i++) {
+			char *entry = (char *)acl_buf + offset + i * 2;
+
+			rsize += scnprintf(buf + rsize, PAGE_SIZE, "%d\n",
+					   be16_to_cpup((__be16 *)entry));
+		}
+	} else if (attr == &dev_attr_pvid) {
+		u16 pvid, vid;
+		u8 pri;
+
+		pvid = be16_to_cpu(acl_buf->pvid);
+		vid = pvid & VLAN_VID_MASK;
+		pri = (pvid & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+
+		rsize = scnprintf(buf, PAGE_SIZE, "%d\n%d\n", vid, pri);
+	}
+out:
+	dma_unmap_single(dev, adapter->acl_buf_token, adapter->acl_buf_sz,
+			 DMA_FROM_DEVICE);
+	kfree(adapter->acl_buf);
+	adapter->acl_buf = NULL;
+	adapter->acl_buf_token = 0;
+	adapter->acl_buf_sz = 0;
+	return rsize;
+}
+
 static DEVICE_ATTR_WO(failover);
+static DEVICE_ATTR(mac_acl, 0444, acl_show, NULL);
+static DEVICE_ATTR(vlan_acl, 0444, acl_show, NULL);
+static DEVICE_ATTR(pvid, 0444, acl_show, NULL);
 
 static struct attribute *dev_attrs[] = {
 	&dev_attr_failover.attr,
+	&dev_attr_mac_acl.attr,
+	&dev_attr_vlan_acl.attr,
+	&dev_attr_pvid.attr,
 	NULL,
 };
 
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index e497392..4768626 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -195,12 +195,15 @@ struct ibmvnic_acl_buffer {
 #define INITIAL_VERSION_IOB 1
 	u8 mac_acls_restrict;
 	u8 vlan_acls_restrict;
-	u8 reserved1[22];
+	__be16 pvid;
+	u8 reserved1[52];
+	__be32 max_mac_addrs;
 	__be32 num_mac_addrs;
 	__be32 offset_mac_addrs;
+	__be32 max_vlan_ids;
 	__be32 num_vlan_ids;
 	__be32 offset_vlan_ids;
-	u8 reserved2[80];
+	u8 reserved2[40];
 } __packed __aligned(8);
 
 /* descriptors have been changed, how should this be defined?  1? 4? */
@@ -585,6 +588,19 @@ struct ibmvnic_acl_query {
 	u8 reserved2[4];
 } __packed __aligned(8);
 
+struct ibmvnic_acl_query_rsp {
+	u8 first;
+	u8 cmd;
+#define ACL_EXISTS      0x8000
+#define VLAN_ACL_ON     0x4000
+#define MAC_ACL_ON      0x2000
+#define PVID_ON	        0x1000
+	__be16 flags;
+	u8 reserved[4];
+	__be32 len;
+	struct ibmvnic_rc rc;
+} __packed __aligned(8);
+
 struct ibmvnic_tune {
 	u8 first;
 	u8 cmd;
@@ -695,7 +711,7 @@ struct ibmvnic_query_map_rsp {
 	struct ibmvnic_get_vpd get_vpd;
 	struct ibmvnic_get_vpd_rsp get_vpd_rsp;
 	struct ibmvnic_acl_query acl_query;
-	struct ibmvnic_generic_crq acl_query_rsp;
+	struct ibmvnic_acl_query_rsp acl_query_rsp;
 	struct ibmvnic_tune tune;
 	struct ibmvnic_generic_crq tune_rsp;
 	struct ibmvnic_request_map request_map;
@@ -1001,6 +1017,10 @@ struct ibmvnic_adapter {
 	dma_addr_t login_rsp_buf_token;
 	int login_rsp_buf_sz;
 
+	struct ibmvnic_acl_buffer *acl_buf;
+	dma_addr_t acl_buf_token;
+	int acl_buf_sz;
+
 	atomic_t running_cap_crqs;
 	bool wait_capability;
 
-- 
1.8.3.1

Powered by blists - more mailing lists