aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c')
-rw-r--r--drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c b/drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c
new file mode 100644
index 000000000000..c26eae426cc1
--- /dev/null
+++ b/drivers/staging/xroeframer/sysfs_xroe_framer_ipv6.c
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Vasileios Bimpikas <vasileios.bimpikas@xilinx.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include "xroe_framer.h"
+
+enum { XROE_SIZE_MAX = 60 };
+static int xroe_size;
+static char xroe_tmp[XROE_SIZE_MAX];
+
+static void utils_ipv6addr_32to16(u32 *ip32, uint16_t *ip16);
+static int utils_ipv6addr_chartohex(char *ip_addr, uint32_t *p_ip_addr);
+
+/**
+ * ipv6_version_show - Returns the IPv6 version number
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 version number
+ *
+ * Returns the IPv6 version number
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_version_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buff)
+{
+ u32 version;
+
+ version = utils_sysfs_show_wrapper(ETH_IPV6_V_ADDR, ETH_IPV6_V_OFFSET,
+ ETH_IPV6_V_MASK, kobj);
+ sprintf(buff, "%d\n", version);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_version_store - Writes to the IPv6 version number sysfs entry
+ * (not permitted)
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 version
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 version number sysfs entry (not permitted)
+ *
+ * Return: 0
+ */
+static ssize_t ipv6_version_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buff, size_t count)
+{
+ return 0;
+}
+
+/**
+ * ipv6_traffic_class_show - Returns the IPv6 traffic class
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 traffic class
+ *
+ * Returns the IPv6 traffic class
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_traffic_class_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buff)
+{
+ u32 traffic_class;
+
+ traffic_class = utils_sysfs_show_wrapper(ETH_IPV6_TRAFFIC_CLASS_ADDR,
+ ETH_IPV6_TRAFFIC_CLASS_OFFSET,
+ ETH_IPV6_TRAFFIC_CLASS_MASK,
+ kobj);
+ sprintf(buff, "%d\n", traffic_class);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_traffic_class_store - Writes to the IPv6 traffic class
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 traffic class
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 traffic class sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_traffic_class_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buff, size_t count)
+{
+ int ret;
+ u32 traffic_class;
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ ret = kstrtouint(buff, 10, &traffic_class);
+ if (ret)
+ return ret;
+ utils_sysfs_store_wrapper(ETH_IPV6_TRAFFIC_CLASS_ADDR,
+ ETH_IPV6_TRAFFIC_CLASS_OFFSET,
+ ETH_IPV6_TRAFFIC_CLASS_MASK, traffic_class,
+ kobj);
+ return xroe_size;
+}
+
+/**
+ * ipv6_flow_label_show - Returns the IPv6 flow label
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 flow label
+ *
+ * Returns the IPv6 flow label
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_flow_label_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buff)
+{
+ u32 flow_label;
+
+ flow_label = utils_sysfs_show_wrapper(ETH_IPV6_FLOW_LABEL_ADDR,
+ ETH_IPV6_FLOW_LABEL_OFFSET,
+ ETH_IPV6_FLOW_LABEL_MASK, kobj);
+ sprintf(buff, "%d\n", flow_label);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_flow_label_store - Writes to the IPv6 flow label
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 flow label
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 flow label sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_flow_label_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buff, size_t count)
+{
+ int ret;
+ u32 flow_label;
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ ret = kstrtouint(buff, 10, &flow_label);
+ if (ret)
+ return ret;
+ utils_sysfs_store_wrapper(ETH_IPV6_FLOW_LABEL_ADDR,
+ ETH_IPV6_FLOW_LABEL_OFFSET,
+ ETH_IPV6_FLOW_LABEL_MASK, flow_label, kobj);
+ return xroe_size;
+}
+
+/**
+ * ipv6_next_header_show - Returns the IPv6 next header
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 next header
+ *
+ * Returns the IPv6 next header
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_next_header_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buff)
+{
+ u32 next_header;
+
+ next_header = utils_sysfs_show_wrapper(ETH_IPV6_NEXT_HEADER_ADDR,
+ ETH_IPV6_NEXT_HEADER_OFFSET,
+ ETH_IPV6_NEXT_HEADER_MASK, kobj);
+ sprintf(buff, "%d\n", next_header);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_next_header_store - Writes to the IPv6 next header
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 next header
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 next header sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_next_header_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buff, size_t count)
+{
+ int ret;
+ u32 next_header;
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ ret = kstrtouint(buff, 10, &next_header);
+ if (ret)
+ return ret;
+ utils_sysfs_store_wrapper(ETH_IPV6_NEXT_HEADER_ADDR,
+ ETH_IPV6_NEXT_HEADER_OFFSET,
+ ETH_IPV6_NEXT_HEADER_MASK, next_header, kobj);
+ return xroe_size;
+}
+
+/**
+ * ipv6_hop_limit_show - Returns the IPv6 hop limit
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 hop limit
+ *
+ * Returns the IPv6 hop limit
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_hop_limit_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buff)
+{
+ u32 hop_limit;
+
+ hop_limit = utils_sysfs_show_wrapper(ETH_IPV6_HOP_LIMIT_ADDR,
+ ETH_IPV6_HOP_LIMIT_OFFSET,
+ ETH_IPV6_HOP_LIMIT_MASK, kobj);
+ sprintf(buff, "%d\n", hop_limit);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_hop_limit_store - Writes to the IPv6 hop limit
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv6 hop limit
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 hop limit sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_hop_limit_store
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buff,
+size_t count)
+{
+ int ret;
+ u32 hop_limit;
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ ret = kstrtouint(buff, 10, &hop_limit);
+ if (ret)
+ return ret;
+ utils_sysfs_store_wrapper(ETH_IPV6_HOP_LIMIT_ADDR,
+ ETH_IPV6_HOP_LIMIT_OFFSET,
+ ETH_IPV6_HOP_LIMIT_MASK, hop_limit, kobj);
+ return xroe_size;
+}
+
+/**
+ * ipv6_source_address_show - Returns the IPv6 source address
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv4 source address
+ *
+ * Returns the IPv6 source address in xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx
+ * format
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_source_address_show
+(struct kobject *kobj, struct kobj_attribute *attr, char *buff)
+{
+ u32 source[4];
+ u16 source_add16[8];
+
+ source[0] = utils_sysfs_show_wrapper(ETH_IPV6_SOURCE_ADD_31_0_ADDR,
+ ETH_IPV6_SOURCE_ADD_31_0_OFFSET,
+ ETH_IPV6_SOURCE_ADD_31_0_MASK,
+ kobj);
+ source[1] = utils_sysfs_show_wrapper(ETH_IPV6_SOURCE_ADD_63_32_ADDR,
+ ETH_IPV6_SOURCE_ADD_63_32_OFFSET,
+ ETH_IPV6_SOURCE_ADD_63_32_MASK,
+ kobj);
+ source[2] = utils_sysfs_show_wrapper(ETH_IPV6_SOURCE_ADD_95_64_ADDR,
+ ETH_IPV6_SOURCE_ADD_95_64_OFFSET,
+ ETH_IPV6_SOURCE_ADD_95_64_MASK,
+ kobj);
+ source[3] = utils_sysfs_show_wrapper(ETH_IPV6_SOURCE_ADD_127_96_ADDR,
+ ETH_IPV6_SOURCE_ADD_127_96_OFFSET,
+ ETH_IPV6_SOURCE_ADD_127_96_MASK,
+ kobj);
+
+ utils_ipv6addr_32to16(source, source_add16);
+ sprintf(buff, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ source_add16[0], source_add16[1], source_add16[2],
+ source_add16[3],
+ source_add16[4], source_add16[5], source_add16[6],
+ source_add16[7]);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_source_address_store - Writes to the IPv6 source address sysfs entry
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv4 source address
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 source address sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_source_address_store
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buff,
+size_t count)
+{
+ u32 source_add[4];
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ strncpy(xroe_tmp, buff, xroe_size);
+ if (utils_ipv6addr_chartohex(xroe_tmp, source_add) == 8) {
+ utils_sysfs_store_wrapper(ETH_IPV6_SOURCE_ADD_31_0_ADDR,
+ ETH_IPV6_SOURCE_ADD_31_0_OFFSET,
+ ETH_IPV6_SOURCE_ADD_31_0_MASK,
+ source_add[0], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_SOURCE_ADD_63_32_ADDR,
+ ETH_IPV6_SOURCE_ADD_63_32_OFFSET,
+ ETH_IPV6_SOURCE_ADD_63_32_MASK,
+ source_add[1], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_SOURCE_ADD_95_64_ADDR,
+ ETH_IPV6_SOURCE_ADD_95_64_OFFSET,
+ ETH_IPV6_SOURCE_ADD_95_64_MASK,
+ source_add[2], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_SOURCE_ADD_127_96_ADDR,
+ ETH_IPV6_SOURCE_ADD_127_96_OFFSET,
+ ETH_IPV6_SOURCE_ADD_127_96_MASK,
+ source_add[3], kobj);
+ }
+ return xroe_size;
+}
+
+/**
+ * ipv6_destination_address_show - Returns the IPv6 destination address
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv4 destination address
+ *
+ * Returns the IPv6 destination address in
+ * xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx format
+ *
+ * Return: XROE_SIZE_MAX on success
+ */
+static ssize_t ipv6_destination_address_show
+(struct kobject *kobj, struct kobj_attribute *attr, char *buff)
+{
+ u32 dest[4];
+ u16 dest_add16[8];
+
+ dest[0] = utils_sysfs_show_wrapper(ETH_IPV6_DEST_ADD_31_0_ADDR,
+ ETH_IPV6_DEST_ADD_31_0_OFFSET,
+ ETH_IPV6_DEST_ADD_31_0_MASK,
+ kobj);
+ dest[1] = utils_sysfs_show_wrapper(ETH_IPV6_DEST_ADD_63_32_ADDR,
+ ETH_IPV6_DEST_ADD_63_32_OFFSET,
+ ETH_IPV6_DEST_ADD_63_32_MASK,
+ kobj);
+ dest[2] = utils_sysfs_show_wrapper(ETH_IPV6_DEST_ADD_95_64_ADDR,
+ ETH_IPV6_DEST_ADD_95_64_OFFSET,
+ ETH_IPV6_DEST_ADD_95_64_MASK,
+ kobj);
+ dest[3] = utils_sysfs_show_wrapper(ETH_IPV6_DEST_ADD_127_96_ADDR,
+ ETH_IPV6_DEST_ADD_127_96_OFFSET,
+ ETH_IPV6_DEST_ADD_127_96_MASK,
+ kobj);
+
+ utils_ipv6addr_32to16(dest, dest_add16);
+ sprintf(buff, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ dest_add16[0], dest_add16[1], dest_add16[2],
+ dest_add16[3],
+ dest_add16[4], dest_add16[5], dest_add16[6],
+ dest_add16[7]);
+ return XROE_SIZE_MAX;
+}
+
+/**
+ * ipv6_destination_address_store - Writes to the IPv6 destination address
+ * sysfs entry
+ * @kobj: The kernel object of the entry
+ * @attr: The attributes of the kernel object
+ * @buff: The buffer containing the IPv4 destination address
+ * @count: The number of characters typed by the user
+ *
+ * Writes to the IPv6 destination address sysfs entry
+ *
+ * Return: XROE_SIZE_MAX or the value of "count", if that's lesser, on success
+ */
+static ssize_t ipv6_destination_address_store
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buff,
+size_t count)
+{
+ u32 dest_add[4];
+
+ xroe_size = min_t(size_t, count, (size_t)XROE_SIZE_MAX);
+ strncpy(xroe_tmp, buff, xroe_size);
+ if (utils_ipv6addr_chartohex(xroe_tmp, dest_add) == 8) {
+ utils_sysfs_store_wrapper(ETH_IPV6_DEST_ADD_31_0_ADDR,
+ ETH_IPV6_DEST_ADD_31_0_OFFSET,
+ ETH_IPV6_DEST_ADD_31_0_MASK,
+ dest_add[0], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_DEST_ADD_63_32_ADDR,
+ ETH_IPV6_DEST_ADD_63_32_OFFSET,
+ ETH_IPV6_DEST_ADD_63_32_MASK,
+ dest_add[1], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_DEST_ADD_95_64_ADDR,
+ ETH_IPV6_DEST_ADD_95_64_OFFSET,
+ ETH_IPV6_DEST_ADD_95_64_MASK,
+ dest_add[2], kobj);
+ utils_sysfs_store_wrapper(ETH_IPV6_DEST_ADD_127_96_ADDR,
+ ETH_IPV6_DEST_ADD_127_96_OFFSET,
+ ETH_IPV6_DEST_ADD_127_96_MASK,
+ dest_add[3], kobj);
+ }
+ return xroe_size;
+}
+
+/* TODO Use DEVICE_ATTR/_RW/_RO macros */
+
+static struct kobj_attribute version_attribute =
+ __ATTR(version, 0444, ipv6_version_show, ipv6_version_store);
+static struct kobj_attribute traffic_class =
+ __ATTR(traffic_class, 0660, ipv6_traffic_class_show,
+ ipv6_traffic_class_store);
+static struct kobj_attribute flow_label =
+ __ATTR(flow_label, 0660, ipv6_flow_label_show, ipv6_flow_label_store);
+static struct kobj_attribute next_header =
+ __ATTR(next_header, 0660, ipv6_next_header_show,
+ ipv6_next_header_store);
+static struct kobj_attribute hop_limit =
+ __ATTR(hop_limit, 0660, ipv6_hop_limit_show, ipv6_hop_limit_store);
+static struct kobj_attribute source_add_attribute =
+ __ATTR(source_add, 0660, ipv6_source_address_show,
+ ipv6_source_address_store);
+static struct kobj_attribute dest_add_attribute =
+ __ATTR(dest_add, 0660, ipv6_destination_address_show,
+ ipv6_destination_address_store);
+
+static struct attribute *attrs[] = {
+ &version_attribute.attr,
+ &traffic_class.attr,
+ &flow_label.attr,
+ &next_header.attr,
+ &hop_limit.attr,
+ &source_add_attribute.attr,
+ &dest_add_attribute.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+static struct kobject *kobj_ipv6[MAX_NUM_ETH_PORTS];
+
+/**
+ * xroe_sysfs_ipv6_init - Creates the xroe sysfs "ipv6" subdirectory & entries
+ *
+ * Return: 0 on success, negative value in case of failure to
+ * create the sysfs group
+ *
+ * Creates the xroe sysfs "ipv6" subdirectory and entries under "xroe"
+ */
+int xroe_sysfs_ipv6_init(void)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ kobj_ipv6[i] = kobject_create_and_add("ipv6",
+ kobj_eth_ports[i]);
+ if (!kobj_ipv6[i])
+ return -ENOMEM;
+ ret = sysfs_create_group(kobj_ipv6[i], &attr_group);
+ if (ret)
+ kobject_put(kobj_ipv6[i]);
+ }
+ return ret;
+}
+
+/**
+ * xroe_sysfs_ipv4_exit - Deletes the xroe sysfs "ipv6" subdirectory & entries
+ *
+ * Deletes the xroe sysfs "ipv6" subdirectory and entries,
+ * under the "xroe" entry
+ *
+ */
+void xroe_sysfs_ipv6_exit(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM_ETH_PORTS; i++)
+ kobject_put(kobj_ipv6[i]);
+}
+
+/**
+ * utils_ipv6addr_32to16 - uint32_t to uint16_t for IPv6 addresses
+ * @ip32: The IPv6 address in uint32_t format
+ * @ip16: The IPv6 address in uint16_t format
+ *
+ * Coverts an IPv6 address given in uint32_t format to uint16_t
+ */
+static void utils_ipv6addr_32to16(u32 *ip32, uint16_t *ip16)
+{
+ ip16[0] = ip32[0] >> 16;
+ ip16[1] = ip32[0] & 0x0000FFFF;
+ ip16[2] = ip32[1] >> 16;
+ ip16[3] = ip32[1] & 0x0000FFFF;
+ ip16[4] = ip32[2] >> 16;
+ ip16[5] = ip32[2] & 0x0000FFFF;
+ ip16[6] = ip32[3] >> 16;
+ ip16[7] = ip32[3] & 0x0000FFFF;
+}
+
+/**
+ * utils_ipv6addr_chartohex - Character to char array for IPv6 addresses
+ * @ip_addr: The character array containing the IP address
+ * @p_ip_addr: The converted IPv4 address
+ *
+ * Coverts an IPv6 address given as a character array to integer format
+ *
+ * Return: 8 (the length of the resulting character array) on success,
+ * -1 in case of wrong input
+ */
+static int utils_ipv6addr_chartohex(char *ip_addr, uint32_t *p_ip_addr)
+{
+ int ret;
+ int count;
+ char *string;
+ unsigned char *found;
+ u16 ip_array_16[8];
+ u32 field;
+
+ ret = -1;
+ count = 0;
+ string = ip_addr;
+ while ((found = (unsigned char *)strsep(&string, ":")) != NULL) {
+ if (count <= 8) {
+ ret = kstrtouint(found, 16, &field);
+ if (ret)
+ return ret;
+ ip_array_16[count] = (uint16_t)field;
+ } else {
+ break;
+ }
+ count++;
+ }
+ if (count == 8) {
+ p_ip_addr[0] = ip_array_16[1] | (ip_array_16[0] << 16);
+ p_ip_addr[1] = ip_array_16[3] | (ip_array_16[2] << 16);
+ p_ip_addr[2] = ip_array_16[5] | (ip_array_16[4] << 16);
+ p_ip_addr[3] = ip_array_16[7] | (ip_array_16[6] << 16);
+ ret = count;
+ }
+ return ret;
+}