wlan-ap-Telecominfraproject/feeds/ipq95xx/iw/patches/611-add-sawf-support.patch
John Crispin 460050a114 ipq50xx: add CIF WF-198 support
Signed-off-by: John Crispin <john@phrozen.org>
2024-02-28 18:56:21 +01:00

396 lines
14 KiB
Diff

From 8fea084fa76f76159bcc110699eb5a91854e6f19 Mon Sep 17 00:00:00 2001
From: Nagarajan Maran <quic_nmaran@quicinc.com>
Date: Thu, 10 Nov 2022 18:52:12 +0530
Subject: [PATCH] iw: add support for sawf
Add configure, disable and view support for SAWF service classes.
Below is the command to configure a service class
- iw phy <phyname> service_class create <service_id> <app_name>
[min_tput <min_thruput_rate>] [max_tput <max_thruput_rate>]
[burst_size <burst_size>] [service_interval <service_interval>]
[delay_bound <delay_bound>] [msdu_ttl <msdu_ttl>] [priority <priority>]
[tid <tid>] [msdu_loss <msdu_rate_loss>]
Below is the command to disable a service class
- iw phy <phyname> service_class delete <service_id>
Below is the command to view a specific service class
- iw phy <phyname> service_class view <service_id>
Below is the command to view all service classes
- iw phy <phyname> service_class view
Signed-off-by: Karthikeyan Kathirvel <quic_kathirve@quicinc.com>
Co-Developed-by: Nagarajan Maran <quic_nmaran@quicinc.com>
Signed-off-by: Nagarajan Maran <quic_nmaran@quicinc.com>
---
iw.h | 17 +++++
sawf.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 232 insertions(+)
create mode 100644 sawf.c
--- a/iw.h
+++ b/iw.h
@@ -69,6 +69,12 @@ enum id_input {
II_WDEV,
};
+enum qca_nl80211_vendor_subcmds {
+ QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS = 203,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_CREATE = 204,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_DISABLE = 205,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_VIEW = 206,
+};
/* Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and
* QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands.
@@ -82,6 +88,26 @@ enum qca_wlan_vendor_attr_config {
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
};
+enum qca_wlan_vendor_sawf_attr_config {
+ QCA_WLAN_VENDOR_ATTR_SAWF_SERVICE_CLASSES = 1,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID,
+ QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX =
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_AFTER_LAST - 1,
+};
+
#define HANDLER_RET_USAGE 1
#define HANDLER_RET_DONE 3
--- /dev/null
+++ b/sawf.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include <arpa/inet.h>
+
+#include "nl80211.h"
+#include "iw.h"
+
+#define OUI_QCA 0x001374
+#define MAX_OPTIONAL_STRINGS 9
+#define MAX_STRING_SIZE 60
+#define MAX_RANGE(type) pow(2, 8 * sizeof(type)) - 1
+#define SVC_CREATE_MIN_ARGUMENTS 2
+#define SVC_CREATE_MAX_ARGUMENTS 20
+#define SVC_DISABLE_MAX_ARGUMENTS 1
+#define SVC_VIEW_MAX_ARGUMENTS 1
+#define APP_NAME_MAX_BYTES 64
+
+struct sawf_disable_param {
+ uint8_t svc_id;
+};
+
+SECTION(service_class);
+
+static int handle_service_class_create(struct nl80211_state *state,
+ struct nl_msg *msg, int argc,
+ char **argv, enum id_input id)
+{
+ struct nlattr *service_class;
+ char app_name[APP_NAME_MAX_BYTES];
+ int parsed = 0, param_count;
+ char *end;
+ unsigned long value;
+ char service_check[MAX_OPTIONAL_STRINGS][MAX_STRING_SIZE] = {"min_tput",
+ "max_tput",
+ "burst_size",
+ "service_interval",
+ "delay_bound",
+ "msdu_ttl",
+ "priority",
+ "tid",
+ "msdu_loss"};
+
+ if (argc < SVC_CREATE_MIN_ARGUMENTS || argc > SVC_CREATE_MAX_ARGUMENTS ||
+ (argc % SVC_CREATE_MIN_ARGUMENTS) != 0)
+ goto err;
+
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_CREATE);
+
+ service_class = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!service_class)
+ return -ENOBUFS;
+
+ errno = 0;
+ value = strtoul(argv[0], &end, 10);
+ if (*end != '\0' || value > MAX_RANGE(uint8_t) || errno == ERANGE)
+ goto err;
+
+ strlcpy(app_name, argv[1], APP_NAME_MAX_BYTES);
+
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID, value);
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME, sizeof(app_name), app_name);
+
+ parsed += 2;
+
+ for (errno = 0; parsed < argc; parsed += 2, errno = 0) {
+ value = strtoul(argv[parsed + 1], &end, 10);
+ if (*end != '\0' || value > MAX_RANGE(uint32_t) || errno == ERANGE)
+ goto err;
+
+ for (param_count = 0; param_count < MAX_OPTIONAL_STRINGS;
+ param_count++) {
+ if (!strcmp(argv[parsed], service_check[param_count]))
+ break;
+ }
+
+ if (param_count == MAX_OPTIONAL_STRINGS)
+ goto err;
+
+ switch (param_count + QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP) {
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND,
+ value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID, value);
+ break;
+ case QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS:
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS,
+ value);
+ break;
+ }
+ }
+
+ nla_nest_end(msg, service_class);
+ return 0;
+err:
+ printf("Invalid SAWF service class command format: Usage\n");
+ printf("\t iw phy <phyname> service_class create <service_id> <app_name> ");
+ printf("[min_tput <min_thruput_rate>] [max_tput <max_thruput_rate>] ");
+ printf("[burst_size <burst_size>] [service_interval <service_interval>] ");
+ printf("[delay_bound <delay_bound>] [msdu_ttl <msdu_ttl>] ");
+ printf("[priority <priority>] [tid <tid>] [msdu_loss <msdu_rate_loss>]\n");
+
+ return -EINVAL;
+}
+
+COMMAND(service_class, create, "<service_id> <app_name> [min_tput <min_thruput_rate>]"
+ " [max_tput <max_thruput_rate>] [burst_size <burst_size>]"
+ " [service_interval <service_interval>] [delay_bound <delay_bound>]"
+ " [msdu_ttl <msdu_ttl>] [priority <priority>] [tid <tid>]"
+ " [msdu_loss <msdu_rate_loss>]", NL80211_CMD_VENDOR, 0, CIB_PHY,
+ handle_service_class_create, ".");
+
+static int handle_service_class_disable(struct nl80211_state *state,
+ struct nl_msg *msg, int argc,
+ char **argv, enum id_input id)
+{
+ struct nlattr *service_class;
+ unsigned long value;
+ char *end;
+
+ if (argc != SVC_DISABLE_MAX_ARGUMENTS)
+ goto err;
+
+ errno = 0;
+ value = strtoul(argv[0], &end, 10);
+ if (*end != '\0' || value > MAX_RANGE(uint8_t) || errno == ERANGE)
+ goto err;
+
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_DISABLE);
+
+ service_class = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!service_class)
+ return -ENOBUFS;
+
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID, value);
+
+ nla_nest_end(msg, service_class);
+ return 0;
+
+err:
+ printf("Invalid SAWF service class command format: Usage\n");
+ printf("\t iw phy <phyname> service_class disable <service_id>\n");
+ return -EINVAL;
+}
+
+COMMAND(service_class, disable, "<service_id>", NL80211_CMD_VENDOR, 0, CIB_PHY,
+ handle_service_class_disable, ".");
+
+static int print_sawf_service_classes(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct nlattr *sawf_service_classes;
+ struct nlattr *sawf_service_class;
+ struct nlattr *attrs[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int sawf_service_classes_len = 0;
+ char *app_name = NULL;
+ static struct nla_policy sawf_policy[QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID] = {.type = NLA_U8},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME] = {.type = NLA_STRING},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID] = {.type = NLA_U32},
+ [QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS] = {.type = NLA_U32},
+ };
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_VENDOR_DATA]) {
+ sawf_service_classes = nla_data(tb_msg[NL80211_ATTR_VENDOR_DATA]);
+ sawf_service_classes_len = nla_len(tb_msg[NL80211_ATTR_VENDOR_DATA]);
+ }
+ else
+ return NL_SKIP;
+
+ if (nla_type(sawf_service_classes) != QCA_WLAN_VENDOR_ATTR_SAWF_SERVICE_CLASSES )
+ return NL_SKIP;
+
+ nla_for_each_nested(sawf_service_class, sawf_service_classes,
+ sawf_service_classes_len) {
+ nla_parse_nested(attrs,
+ QCA_WLAN_VENDOR_SAWF_ATTR_CONFIG_MAX,
+ sawf_service_class, sawf_policy);
+
+ printf("***********************************\n");
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID])
+ printf("Service ID\t: %u\n",
+ nla_get_u8(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME]) {
+ app_name = nla_data(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_APP_NAME]);
+ printf("App Name\t: %s\n", app_name);
+ }
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP])
+ printf("Min throughput\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MIN_TP]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP])
+ printf("Max throughput\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MAX_TP]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE])
+ printf("Burst Size\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_BURST_SIZE]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL])
+ printf("Service Interval: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_INTERVAL]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND])
+ printf("Delay Bound\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_DELAY_BOUND]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL])
+ printf("MSDU TTL\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_TTL]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO])
+ printf("Priority\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_PRIO]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID])
+ printf("TID\t\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_TID]));
+ if (attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS])
+ printf("MSDU Loss Rate\t: %u\n",
+ nla_get_u32(attrs[QCA_WLAN_VENDOR_ATTR_SAWF_SVC_MSDU_RATE_LOSS]));
+ }
+ return NL_SKIP;
+}
+
+static int handle_service_class_dump(struct nl80211_state *state,
+ struct nl_msg *msg, int argc,
+ char **argv, enum id_input id)
+{
+ struct nlattr *service_class;
+ unsigned long value = 0;
+ char *end;
+
+ if (argc > SVC_VIEW_MAX_ARGUMENTS) {
+ goto err;
+ }
+ else if (argc == SVC_VIEW_MAX_ARGUMENTS) {
+ errno = 0;
+ value = strtoul(argv[0], &end, 10);
+ if (*end != '\0' || value > MAX_RANGE(uint8_t) || errno == ERANGE)
+ goto err;
+ }
+
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SVC_VIEW);
+
+ service_class = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!service_class)
+ return -ENOBUFS;
+
+ if (argc)
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SAWF_SVC_ID, value);
+
+ nla_nest_end(msg, service_class);
+
+ register_handler(print_sawf_service_classes, NULL);
+ return 0;
+err:
+ printf("Invalid SAWF service class command format: Usage\n");
+ printf("\t iw phy <phyname> service_class view [<service_id>]\n");
+ return -EINVAL;
+}
+
+COMMAND(service_class, view, "[<service_id>]", NL80211_CMD_VENDOR, NLM_F_DUMP, CIB_PHY,
+ handle_service_class_dump, ".");