mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-22 03:42:41 +00:00
396 lines
14 KiB
Diff
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, ".");
|