mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-21 11:22:50 +00:00
Some checks failed
Build OpenWrt/uCentral images / build (cig_wf186h) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf186w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf188n) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf189) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cig_wf196) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-a1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (cybertan_eww631-b1) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap102) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap104) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap105) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap111) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_eap112) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (edgecore_oap101e-6e) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_3) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4x_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xe) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi) (push) Has been cancelled
Build OpenWrt/uCentral images / build (hfcl_ion4xi_w) (push) Has been cancelled
Build OpenWrt/uCentral images / build (indio_um-305ax) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sercomm_ap72tip) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630c-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-211g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (sonicfi_rap630w-311g) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-id2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (udaya_a6-od2) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr5018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018) (push) Has been cancelled
Build OpenWrt/uCentral images / build (wallys_dr6018-v4) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax820) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_ax840) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap640) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap650) (push) Has been cancelled
Build OpenWrt/uCentral images / build (yuncore_fap655) (push) Has been cancelled
Build OpenWrt/uCentral images / trigger-testing (push) Has been cancelled
Build OpenWrt/uCentral images / create-x64_vm-ami (push) Has been cancelled
Signed-off-by: John Crispin <john@phrozen.org>
1369 lines
43 KiB
Diff
1369 lines
43 KiB
Diff
From 061f80f99ca46941eca7140307711c21b6e4ec95 Mon Sep 17 00:00:00 2001
|
|
From: Balamurugan Ramar <quic_bramar@quicinc.com>
|
|
Date: Thu, 23 Nov 2023 16:26:52 +0530
|
|
Subject: [PATCH] hostapd: Add SCS UL Support.
|
|
|
|
Stream classification service classifies incoming individually
|
|
addressed msdus based upon the parameters provided by the STA.
|
|
|
|
AP advertise the SCS capability in beacon frame or probe response
|
|
or assoc response to the station. Station sends the SCS request
|
|
frame to the AP if AP advertise scs capabaility.
|
|
|
|
AP subscribe robust AV stream action frame to receive the SCS
|
|
frame from kernel. AP parse the scs descriptors, qos attributes and
|
|
send the latency params to the driver via NL vendor commands.
|
|
|
|
STA that supports SCS may request use of SCS by sending an SCS Request
|
|
frame that includes SCS Descriptor element with the Request Type field
|
|
set to Add or Change.
|
|
|
|
The SCS Descriptor List field in the SCS Descriptor element identifies
|
|
how MSDUs are classified and the priority to assign to MSDUs that match
|
|
this classification.
|
|
|
|
Each SCS stream is identified by an SCSID. This SCSID is used by a STA
|
|
to request creation, modification, or deletion of an SCS stream. AP send
|
|
SCS response back to the clinet once it succssefully processed the SCS
|
|
request.
|
|
|
|
Signed-off-by: Balamurugan Ramar <quic_bramar@quicinc.com>
|
|
---
|
|
hostapd/Makefile | 1 +
|
|
src/ap/Makefile | 3 +-
|
|
src/ap/ap_drv_ops.c | 58 +++-
|
|
src/ap/ap_drv_ops.h | 4 +
|
|
src/ap/beacon.c | 14 +-
|
|
src/ap/hostapd.h | 2 +
|
|
src/ap/ieee802_11.c | 11 +-
|
|
src/ap/ieee802_11_shared.c | 11 +-
|
|
src/ap/scs.c | 543 +++++++++++++++++++++++++++++++++++
|
|
src/ap/scs.h | 273 ++++++++++++++++++
|
|
src/ap/sta_info.c | 5 +
|
|
src/ap/sta_info.h | 11 +
|
|
src/common/ieee802_11_defs.h | 11 +-
|
|
src/common/qca-vendor.h | 7 +
|
|
src/drivers/driver.h | 15 +
|
|
src/drivers/driver_nl80211.c | 65 ++++-
|
|
16 files changed, 1023 insertions(+), 11 deletions(-)
|
|
create mode 100644 src/ap/scs.c
|
|
create mode 100644 src/ap/scs.h
|
|
|
|
--- a/hostapd/Makefile
|
|
+++ b/hostapd/Makefile
|
|
@@ -355,6 +355,7 @@ ifdef CONFIG_IEEE80211BE
|
|
CONFIG_IEEE80211AX=y
|
|
CFLAGS += -DCONFIG_IEEE80211BE
|
|
OBJS += ../src/ap/ieee802_11_eht.o
|
|
+OBJS += ../src/ap/scs.o
|
|
endif
|
|
|
|
ifdef CONFIG_IEEE80211AX
|
|
--- a/src/ap/Makefile
|
|
+++ b/src/ap/Makefile
|
|
@@ -56,6 +56,7 @@ LIB_OBJS= \
|
|
wpa_auth_glue.o \
|
|
wpa_auth_ie.o \
|
|
wps_hostapd.o \
|
|
- x_snoop.o
|
|
+ x_snoop.o \
|
|
+ scs.o
|
|
|
|
include ../lib.rules
|
|
--- a/src/ap/ap_drv_ops.c
|
|
+++ b/src/ap/ap_drv_ops.c
|
|
@@ -22,7 +22,9 @@
|
|
#include "hs20.h"
|
|
#include "wpa_auth.h"
|
|
#include "ap_drv_ops.h"
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#include "scs.h"
|
|
+#endif
|
|
|
|
u32 hostapd_sta_flags_to_drv(u32 flags)
|
|
{
|
|
@@ -71,7 +73,7 @@ int hostapd_build_ap_extra_ies(struct ho
|
|
struct wpabuf **assocresp_ret)
|
|
{
|
|
struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
|
|
- u8 buf[200], *pos;
|
|
+ u8 buf[208], *pos;
|
|
|
|
*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
|
|
|
|
@@ -116,6 +118,15 @@ int hostapd_build_ap_extra_ies(struct ho
|
|
goto fail;
|
|
#endif /* CONFIG_FILS */
|
|
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ pos = hostapd_add_scs_cap(buf, false, true);
|
|
+ if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
|
+ add_buf_data(&proberesp, buf, pos - buf) < 0 ||
|
|
+ add_buf_data(&assocresp, buf, pos - buf) < 0) {
|
|
+ goto fail;
|
|
+ }
|
|
+#endif
|
|
+
|
|
pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
|
|
if (add_buf_data(&assocresp, buf, pos - buf) < 0)
|
|
goto fail;
|
|
@@ -368,6 +379,49 @@ int hostapd_add_sta_node(struct hostapd_
|
|
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
|
|
}
|
|
|
|
+static int hostapd_get_scs_final_value(struct sta_info *sta,
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_m)
|
|
+{
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_db;
|
|
+ u8 index = 0;
|
|
+
|
|
+ while (index < sta->session_cnt && index < HOSTAPD_SCS_MAX_SIZE) {
|
|
+ scs_db = sta->scs_data[index];
|
|
+ if (scs_db->ac == scs_m->ac) {
|
|
+ scs_m->service_interval =
|
|
+ HOSTAPD_MIN(scs_db->service_interval, scs_m->service_interval);
|
|
+ scs_m->min_data_rate =
|
|
+ HOSTAPD_MAX(scs_db->min_data_rate, scs_m->min_data_rate);
|
|
+ scs_m->delay_bound =
|
|
+ HOSTAPD_MIN(scs_db->delay_bound, scs_m->delay_bound);
|
|
+ }
|
|
+ ++index;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+int hostapd_set_scs_params(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_m, u8 req_type)
|
|
+{
|
|
+ struct scs_latency_params scs_drv = {0};
|
|
+
|
|
+ if (hapd->driver == NULL || hapd->driver->set_scs == NULL)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ hostapd_get_scs_final_value(sta, scs_m);
|
|
+ scs_drv.service_interval = scs_m->service_interval / 1000;
|
|
+ scs_drv.user_priority = scs_m->up;
|
|
+ scs_drv.burst_size = scs_m->burst_size;
|
|
+ scs_drv.req_type = req_type;
|
|
+ scs_drv.delay_bound = scs_m->delay_bound / 1000;
|
|
+ scs_drv.min_data_rate = scs_m->min_data_rate;
|
|
+ scs_drv.ac = scs_m->ac;
|
|
+ scs_drv.direction = scs_m->direction;
|
|
+ os_memcpy(scs_drv.peer_mac, scs_m->peer_mac, 6);
|
|
+ return hapd->driver->set_scs(hapd->drv_priv, &scs_drv);
|
|
+}
|
|
+#endif
|
|
|
|
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
|
|
u16 seq, u16 status, const u8 *ie, size_t len)
|
|
--- a/src/ap/ap_drv_ops.h
|
|
+++ b/src/ap/ap_drv_ops.h
|
|
@@ -150,6 +150,10 @@ int hostapd_drv_set_secure_ranging_ctx(s
|
|
u8 ltf_keyseed_len,
|
|
const u8 *ltf_keyseed, u32 action);
|
|
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+int hostapd_set_scs_params(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_m, u8 req_type);
|
|
+#endif
|
|
|
|
#include "drivers/driver.h"
|
|
|
|
--- a/src/ap/beacon.c
|
|
+++ b/src/ap/beacon.c
|
|
@@ -32,7 +32,9 @@
|
|
#include "dfs.h"
|
|
#include "taxonomy.h"
|
|
#include "ieee802_11_auth.h"
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#include "scs.h"
|
|
+#endif
|
|
|
|
#ifdef NEED_AP_MLME
|
|
|
|
@@ -987,6 +989,7 @@ static u8 * hostapd_gen_probe_resp(struc
|
|
buflen += hostapd_mbo_ie_len(hapd);
|
|
buflen += hostapd_eid_owe_trans_len(hapd);
|
|
buflen += hostapd_eid_dpp_cc_len(hapd);
|
|
+ buflen += hostapd_scs_ie_len(hapd);
|
|
|
|
resp = os_zalloc(buflen);
|
|
if (resp == NULL)
|
|
@@ -1171,7 +1174,9 @@ static u8 * hostapd_gen_probe_resp(struc
|
|
|
|
/* Wi-Fi Alliance WMM */
|
|
pos = hostapd_eid_wmm(hapd, pos);
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ pos = hostapd_add_scs_cap(pos, false, true);
|
|
+#endif
|
|
#ifdef CONFIG_WPS
|
|
if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
|
|
os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
|
|
@@ -2202,6 +2207,7 @@ int ieee802_11_build_ap_params(struct ho
|
|
tail_len += hostapd_mbo_ie_len(hapd);
|
|
tail_len += hostapd_eid_owe_trans_len(hapd);
|
|
tail_len += hostapd_eid_dpp_cc_len(hapd);
|
|
+ tail_len += hostapd_scs_ie_len(hapd);
|
|
|
|
tailpos = tail = os_malloc(tail_len);
|
|
if (head == NULL || tail == NULL) {
|
|
@@ -2389,7 +2395,9 @@ int ieee802_11_build_ap_params(struct ho
|
|
|
|
/* Wi-Fi Alliance WMM */
|
|
tailpos = hostapd_eid_wmm(hapd, tailpos);
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ tailpos = hostapd_add_scs_cap(tailpos, false, true);
|
|
+#endif
|
|
#ifdef CONFIG_WPS
|
|
if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
|
|
os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
|
|
--- a/src/ap/hostapd.h
|
|
+++ b/src/ap/hostapd.h
|
|
@@ -506,6 +506,8 @@ struct hostapd_data {
|
|
|
|
/* Store the partner info for ML probe response */
|
|
struct mld_link_info partner_links[MAX_NUM_MLD_LINKS];
|
|
+
|
|
+ u8 session_cnt;
|
|
#endif /* CONFIG_IEEE80211BE */
|
|
};
|
|
|
|
--- a/src/ap/ieee802_11.c
|
|
+++ b/src/ap/ieee802_11.c
|
|
@@ -57,7 +57,9 @@
|
|
#include "gas_query_ap.h"
|
|
#include "comeback_token.h"
|
|
#include "pasn/pasn_common.h"
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#include "scs.h"
|
|
+#endif
|
|
|
|
#ifdef CONFIG_FILS
|
|
static struct wpabuf *
|
|
@@ -5049,7 +5051,9 @@ rsnxe_done:
|
|
|
|
if (sta && (sta->flags & WLAN_STA_WMM))
|
|
p = hostapd_eid_wmm(hapd, p);
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ p = hostapd_add_scs_cap(p, false, true);
|
|
+#endif
|
|
#ifdef CONFIG_WPS
|
|
if (sta &&
|
|
((sta->flags & WLAN_STA_WPS) ||
|
|
@@ -6041,6 +6045,9 @@ static int handle_action(struct hostapd_
|
|
return 1;
|
|
}
|
|
break;
|
|
+ case WLAN_ACTION_ROBUST_AV_STREAMING:
|
|
+ hostapd_handle_scs(hapd, (const u8 *)mgmt, len);
|
|
+ return 1;
|
|
case WLAN_ACTION_RADIO_MEASUREMENT:
|
|
hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
|
|
return 1;
|
|
--- a/src/ap/ieee802_11_shared.c
|
|
+++ b/src/ap/ieee802_11_shared.c
|
|
@@ -19,7 +19,9 @@
|
|
#include "wpa_auth.h"
|
|
#include "dpp_hostapd.h"
|
|
#include "ieee802_11.h"
|
|
-
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#include "scs.h"
|
|
+#endif
|
|
|
|
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
|
struct sta_info *sta, u8 *eid)
|
|
@@ -483,6 +485,13 @@ u8 * hostapd_eid_ext_capab(struct hostap
|
|
*pos |= hapd->conf->ext_capa[i];
|
|
}
|
|
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ if (i == HOSTAPD_SCS_EXTCAP_INDEX) {
|
|
+ *pos |= HOSTAPD_SCS_EXTCAP_SCS_DESC; // SCS Desc capability
|
|
+ *pos |= HOSTAPD_SCS_EXTCAP_ROBUST_AV; // Robust AV capability
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* Clear bits 83 and 22 if EMA and MBSSID are not enabled
|
|
* otherwise association fails with some clients */
|
|
if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED)
|
|
--- /dev/null
|
|
+++ b/src/ap/scs.c
|
|
@@ -0,0 +1,543 @@
|
|
+/*
|
|
+ * Copyright (c) 2023, 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 "utils/includes.h"
|
|
+
|
|
+#include "utils/common.h"
|
|
+#include "common/ieee802_11_defs.h"
|
|
+#include "common/ieee802_11_common.h"
|
|
+#include "hostapd.h"
|
|
+#include "ieee802_11.h"
|
|
+#include "sta_info.h"
|
|
+#include "ap_config.h"
|
|
+#include "ap_drv_ops.h"
|
|
+
|
|
+#include "scs.h"
|
|
+
|
|
+static u32 hostapd_get_access_cat(u8 tid)
|
|
+{
|
|
+ u32 ac;
|
|
+
|
|
+ if ((tid == 0) || (tid == 3))
|
|
+ ac = HOSTAPD_SCS_BEST_EFF;
|
|
+ else if ((tid == 1) || (tid == 2))
|
|
+ ac = HOSTAPD_SCS_BGROUND;
|
|
+ else if ((tid == 4) || (tid == 5))
|
|
+ ac = HOSTAPD_SCS_VIDEO;
|
|
+ else
|
|
+ ac = HOSTAPD_SCS_VOICE;
|
|
+
|
|
+ return ac;
|
|
+}
|
|
+
|
|
+static void hostapd_scs_dump(struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ wpa_printf(MSG_INFO, "scs info\n");
|
|
+ wpa_printf(MSG_INFO, "element Id %d\n", scs->elem.id);
|
|
+ wpa_printf(MSG_INFO, "element Len %d\n", scs->elem.len);
|
|
+ wpa_printf(MSG_INFO, "scs id %d\n", scs->desc.id);
|
|
+ wpa_printf(MSG_INFO, "request type %d\n", scs->desc.req_type);
|
|
+ wpa_printf(MSG_INFO, "scs intra access category info\n");
|
|
+ wpa_printf(MSG_INFO, "element Id %d\n", scs->ia.elem.id);
|
|
+ wpa_printf(MSG_INFO, "element Len %d\n", scs->ia.elem.len);
|
|
+ wpa_printf(MSG_INFO, "ia piority %d\n", scs->ia.priority);
|
|
+ wpa_printf(MSG_INFO, "scs tclass element\n");
|
|
+ wpa_printf(MSG_INFO, "element id %d\n", scs->tclas.elem.id);
|
|
+ wpa_printf(MSG_INFO, "element len %d\n", scs->tclas.elem.len);
|
|
+ wpa_printf(MSG_INFO, "scs qos attributes\n");
|
|
+ wpa_printf(MSG_INFO, "element id %d\n", scs->qos_attr.elem.id);
|
|
+ wpa_printf(MSG_INFO, "element len %d\n", scs->qos_attr.elem.len);
|
|
+ wpa_printf(MSG_INFO, "attribute id %d\n", scs->qos_attr.attr_id);
|
|
+ wpa_printf(MSG_INFO, "direction %d\n",
|
|
+ scs->qos_attr.ctrl_info.direction);
|
|
+ wpa_printf(MSG_INFO, "tid %d\n", scs->qos_attr.ctrl_info.tid);
|
|
+ wpa_printf(MSG_INFO, "user priority %d\n", scs->qos_attr.ctrl_info.up);
|
|
+ wpa_printf(MSG_INFO, "bitmap %d\n", scs->qos_attr.ctrl_info.bitmap);
|
|
+ wpa_printf(MSG_INFO, "link id %d\n", scs->qos_attr.ctrl_info.link_id);
|
|
+ wpa_printf(MSG_INFO, "access category %d\n",
|
|
+ scs->qos_attr.ctrl_info.access_cat);
|
|
+ wpa_printf(MSG_INFO, "minimum interval %d\n", scs->qos_attr.min_interval);
|
|
+ wpa_printf(MSG_INFO, "maximum interval %d\n", scs->qos_attr.max_interval);
|
|
+ wpa_printf(MSG_INFO, "final service interval %d\n", scs->qos_attr.final_serv_intvl);
|
|
+ wpa_printf(MSG_INFO, "minimum data rate %d\n", scs->qos_attr.min_data_rate);
|
|
+ wpa_printf(MSG_INFO, "delay bound %d\n", scs->qos_attr.delay_bound);
|
|
+ wpa_printf(MSG_INFO, "service start time %d\n", scs->qos_attr.serv_start_time);
|
|
+ wpa_printf(MSG_INFO, "mean data rate %d\n", scs->qos_attr.mean_data_rate);
|
|
+ wpa_printf(MSG_INFO, "burst size %d\n", scs->qos_attr.burst_size);
|
|
+ wpa_printf(MSG_INFO, "final burst size %d\n", scs->qos_attr.final_burst_size);
|
|
+ wpa_printf(MSG_INFO, "max msdu size %d\n", scs->qos_attr.max_msdu_size);
|
|
+ wpa_printf(MSG_INFO, "msdu life time %d\n", scs->qos_attr.msdu_life_time);
|
|
+ wpa_printf(MSG_INFO, "medium time %d\n", scs->qos_attr.medium_time);
|
|
+ wpa_printf(MSG_INFO, "service start time link id %d\n",
|
|
+ scs->qos_attr.serv_start_time_link_id);
|
|
+ wpa_printf(MSG_INFO, "msdu delivery ratio %d\n",
|
|
+ scs->qos_attr.msdu_delivery_ratio);
|
|
+ wpa_printf(MSG_INFO, "msdu count exponenet %d\n", scs->qos_attr.msdu_cnt_exp);
|
|
+}
|
|
+
|
|
+static u8 hostapd_get_scs_index(struct sta_info *sta, u8 scsid)
|
|
+{
|
|
+ u8 index = 0;
|
|
+
|
|
+ if (!sta || !sta->session_cnt)
|
|
+ return HOSTAPD_SCS_MAX_SIZE;
|
|
+
|
|
+ while (index < sta->session_cnt && index < HOSTAPD_SCS_MAX_SIZE) {
|
|
+ if (sta->scs_data[index] == NULL)
|
|
+ return HOSTAPD_SCS_MAX_SIZE;
|
|
+ if (scsid == sta->scs_data[index]->scsid)
|
|
+ return index;
|
|
+ ++index;
|
|
+ }
|
|
+ return HOSTAPD_SCS_MAX_SIZE;
|
|
+}
|
|
+
|
|
+static bool hostapd_is_scs_present(struct sta_info *sta, u8 scsid)
|
|
+{
|
|
+ u8 index = 0;
|
|
+
|
|
+ index = hostapd_get_scs_index(sta, scsid);
|
|
+
|
|
+ if (index >= HOSTAPD_SCS_MAX_SIZE)
|
|
+ return HOSTAPD_SCS_NOT_PRESENT;
|
|
+
|
|
+ return HOSTAPD_SCS_PRESENT;
|
|
+}
|
|
+
|
|
+static int hostapd_remove_scs(struct hostapd_data *hapd, struct sta_info *sta, u8 scsid)
|
|
+{
|
|
+ struct hostapd_qos_mandatory_scs_param scs_m = {0};
|
|
+ int ret;
|
|
+ u8 index = 0;
|
|
+
|
|
+ index = hostapd_get_scs_index(sta, scsid);
|
|
+ if (index >= HOSTAPD_SCS_MAX_SIZE)
|
|
+ goto decline;
|
|
+
|
|
+ os_memcpy(&scs_m, sta->scs_data[index], sizeof(struct hostapd_qos_mandatory_scs_param));
|
|
+ os_free(sta->scs_data[index]);
|
|
+
|
|
+ while (index < sta->session_cnt - 1) {
|
|
+ sta->scs_data[index] = sta->scs_data[index + 1];
|
|
+ ++index;
|
|
+ }
|
|
+
|
|
+ --sta->session_cnt;
|
|
+ sta->scs_data[index] = NULL;
|
|
+
|
|
+ if (sta->session_cnt) {
|
|
+ scs_m.min_data_rate = 0;
|
|
+ scs_m.delay_bound = -1;
|
|
+ scs_m.service_interval = -1;
|
|
+ } else {
|
|
+ scs_m.min_data_rate = 0;
|
|
+ scs_m.delay_bound = 0;
|
|
+ scs_m.service_interval = 0;
|
|
+ }
|
|
+ ret = hostapd_set_scs_params(hapd, sta, &scs_m, HOSTAPD_REM_RULE);
|
|
+ if (ret)
|
|
+ goto decline;
|
|
+
|
|
+ return HOSTAPD_SCS_REQ_TCLAS_PROCESSING_TERMINATED;
|
|
+
|
|
+decline:
|
|
+ return HOSTAPD_SCS_REQ_DECLINED;
|
|
+}
|
|
+
|
|
+static int copy_scs_mparam(struct hostapd_qos_mandatory_scs_param *scs_m,
|
|
+ struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ scs_m->service_interval = scs->qos_attr.final_serv_intvl;
|
|
+ scs_m->delay_bound = scs->qos_attr.delay_bound;
|
|
+ scs_m->burst_size = scs->qos_attr.burst_size;
|
|
+ scs_m->min_data_rate = scs->qos_attr.min_data_rate;
|
|
+ scs_m->scsid = scs->desc.id;
|
|
+ scs_m->ac = scs->qos_attr.ctrl_info.access_cat;
|
|
+ scs_m->up = scs->qos_attr.ctrl_info.up;
|
|
+ scs_m->direction = scs->qos_attr.ctrl_info.direction;
|
|
+ os_memcpy(scs_m->peer_mac, scs->peer_mac, ETH_ALEN);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int hostapd_add_scs(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_m = NULL, scs_t = {0};
|
|
+ int ret;
|
|
+
|
|
+ scs_m = os_zalloc(sizeof(struct hostapd_qos_mandatory_scs_param));
|
|
+ if (!scs_m)
|
|
+ goto decline;
|
|
+
|
|
+ copy_scs_mparam(scs_m, scs);
|
|
+ os_memcpy(&scs_t, scs_m, sizeof(struct hostapd_qos_mandatory_scs_param));
|
|
+ sta->scs_data[sta->session_cnt++] = scs_m;
|
|
+ ret = hostapd_set_scs_params(hapd, sta, &scs_t, HOSTAPD_ADD_RULE);
|
|
+ if (ret)
|
|
+ goto decline;
|
|
+
|
|
+ return HOSTAPD_SCS_REQ_SUCCESS;
|
|
+
|
|
+decline:
|
|
+ return HOSTAPD_SCS_REQ_DECLINED;
|
|
+}
|
|
+
|
|
+static int hostapd_change_scs(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = hostapd_remove_scs(hapd, sta, scs->desc.id);
|
|
+ if (ret != HOSTAPD_SCS_REQ_TCLAS_PROCESSING_TERMINATED)
|
|
+ return ret;
|
|
+
|
|
+ ret = hostapd_add_scs(hapd, sta, scs);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int hostapd_free_all_scs(struct hostapd_data *hapd, struct sta_info *sta)
|
|
+{
|
|
+ while (sta->session_cnt) {
|
|
+ if (sta->scs_data[0])
|
|
+ hostapd_remove_scs(hapd, sta, sta->scs_data[0]->scsid);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const u8 *hostapd_parse_intra_access(const u8 *payload, struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ scs->ia.elem.id = *payload;
|
|
+ if (scs->ia.elem.id == WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY) {
|
|
+ ++payload;
|
|
+ scs->ia.elem.len = *payload++;
|
|
+ scs->ia.priority = *payload++;
|
|
+ }
|
|
+ return payload;
|
|
+}
|
|
+
|
|
+static const u8 *hostapd_parse_tclas(const u8 *payload, struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ scs->tclas.elem.id = *payload;
|
|
+ if (scs->tclas.elem.id == WLAN_EID_TCLAS) {
|
|
+ payload += 3;
|
|
+ scs->tclas.elem.len = *payload;
|
|
+ }
|
|
+ return payload;
|
|
+}
|
|
+
|
|
+static const u8 *hostapd_parse_qos_attr(const u8 *payload, struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ u32 ctrl_det, final_serv_intvl, final_burst_size, temp_data_rate, temp_burst_size;
|
|
+
|
|
+ scs->qos_attr.elem.id = *payload;
|
|
+ if (scs->qos_attr.elem.id != WLAN_EID_EXTENSION)
|
|
+ return NULL;
|
|
+
|
|
+ ++payload;
|
|
+ scs->qos_attr.elem.len = *payload++;
|
|
+ scs->qos_attr.attr_id = *payload++;
|
|
+
|
|
+ HOSTAPD_GET_QOS_ATTR(ctrl_det, payload, CTRL_INFO, 32);
|
|
+ scs->qos_attr.ctrl_info.direction = HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, DIRECTION);
|
|
+
|
|
+ if (scs->qos_attr.ctrl_info.direction != WMM_TSPEC_DIRECTION_UPLINK) {
|
|
+ wpa_printf(MSG_ERROR, "%s: SCS down / direct link is not supported\n", __func__);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ scs->qos_attr.ctrl_info.tid = HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, TID);
|
|
+ scs->qos_attr.ctrl_info.up = HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, UP);
|
|
+ scs->qos_attr.ctrl_info.bitmap = HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, BMP);
|
|
+ scs->qos_attr.ctrl_info.link_id = HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, LINK_ID);
|
|
+ scs->qos_attr.ctrl_info.access_cat = hostapd_get_access_cat(scs->qos_attr.ctrl_info.tid);
|
|
+
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.min_interval, payload, SERVICE_INTERVAL, 32);
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.max_interval, payload, SERVICE_INTERVAL, 32);
|
|
+
|
|
+ scs->qos_attr.final_serv_intvl =
|
|
+ (scs->qos_attr.min_interval + scs->qos_attr.max_interval) >> 1;
|
|
+ final_serv_intvl = scs->qos_attr.final_serv_intvl / 1000;
|
|
+
|
|
+ memcpy(&scs->qos_attr.min_data_rate, payload, HOSTAPD_SCS_QOS_ATTR_MIN_DATA_RATE_LEN);
|
|
+ HOSTAPD_GET_QOS_ATTR_ACTUAL(scs->qos_attr.min_data_rate, payload,
|
|
+ &scs->qos_attr.min_data_rate,
|
|
+ MIN_DATA_RATE, 32);
|
|
+ temp_data_rate = scs->qos_attr.min_data_rate >> 3;
|
|
+ final_burst_size = final_serv_intvl * temp_data_rate;
|
|
+
|
|
+ memcpy(&scs->qos_attr.delay_bound, payload, HOSTAPD_SCS_QOS_ATTR_DELAY_BOULND_LEN);
|
|
+ HOSTAPD_GET_QOS_ATTR_ACTUAL(scs->qos_attr.delay_bound, payload, &scs->qos_attr.delay_bound,
|
|
+ DELAY_BOULND, 32);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MAX_MSDU_SIZE))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.max_msdu_size, payload, MAX_MSDU_SIZE, 16);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, SERVICE_START_TIME))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.serv_start_time, payload, SERVICE_START_TIME,
|
|
+ 32);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap,
|
|
+ SERVICE_START_TIME_LINK_ID))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.serv_start_time_link_id, payload,
|
|
+ SERVICE_START_TIME_LINK_ID, 8);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MEAN_DATA_RATE)) {
|
|
+ memcpy(&scs->qos_attr.mean_data_rate, payload,
|
|
+ HOSTAPD_SCS_QOS_ATTR_MEAN_DATA_RATE_LEN);
|
|
+ HOSTAPD_GET_QOS_ATTR_ACTUAL(scs->qos_attr.mean_data_rate, payload,
|
|
+ &scs->qos_attr.mean_data_rate, MEAN_DATA_RATE, 32);
|
|
+ temp_data_rate = scs->qos_attr.mean_data_rate >> 3;
|
|
+ temp_burst_size = final_serv_intvl * temp_data_rate;
|
|
+ final_burst_size = final_burst_size < temp_burst_size ?
|
|
+ final_burst_size : temp_burst_size;
|
|
+ }
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, BURST_SIZE)) {
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.burst_size, payload, BURST_SIZE, 32);
|
|
+ final_burst_size = final_burst_size > scs->qos_attr.burst_size ?
|
|
+ scs->qos_attr.burst_size : final_burst_size;
|
|
+ }
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MSDU_LIFETIME))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.msdu_life_time, payload, MSDU_LIFETIME, 16);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MSDU_DELIVERY_RATIO))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.msdu_delivery_ratio, payload,
|
|
+ MSDU_DELIVERY_RATIO, 8);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MSDU_COUNT_EXPONENT))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.msdu_cnt_exp, payload, MSDU_COUNT_EXPONENT, 8);
|
|
+
|
|
+ if (HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(scs->qos_attr.ctrl_info.bitmap, MEDIUM_TIME))
|
|
+ HOSTAPD_GET_QOS_ATTR(scs->qos_attr.medium_time, payload, MEDIUM_TIME, 16);
|
|
+
|
|
+ scs->qos_attr.final_burst_size = final_burst_size;
|
|
+ return payload;
|
|
+}
|
|
+
|
|
+static const u8 *hostapd_parse_scs_desc(const u8 *payload, struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ scs->elem.id = *payload++;
|
|
+ if (scs->elem.id != WLAN_EID_SCS_DESCRIPTOR) {
|
|
+ wpa_printf(MSG_ERROR, "%s scs elem %d is not available in this frame !!!\n",
|
|
+ __func__, WLAN_EID_SCS_DESCRIPTOR);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ scs->elem.len = *payload++;
|
|
+ scs->desc.id = *payload++;
|
|
+ scs->desc.req_type = *payload++;
|
|
+
|
|
+ return payload;
|
|
+}
|
|
+
|
|
+static int hostapd_process_scs_req(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ const u8 *payload, struct hostapd_scs_desc_list *scs)
|
|
+{
|
|
+ int ret = HOSTAPD_SCS_REQ_SUCCESS;
|
|
+ u8 scs_avail;
|
|
+
|
|
+ scs_avail = hostapd_is_scs_present(sta, scs->desc.id);
|
|
+ switch (scs->desc.req_type) {
|
|
+ case HOSTAPD_SCS_REQ_TYPE_ADD:
|
|
+ if (scs_avail == HOSTAPD_SCS_PRESENT) {
|
|
+ wpa_printf(MSG_ERROR, "%s:%d> scs id %d is already present\n",
|
|
+ __func__, __LINE__, scs->desc.id);
|
|
+ goto decline;
|
|
+ }
|
|
+
|
|
+ if (sta->session_cnt >= HOSTAPD_SCS_MAX_SIZE)
|
|
+ goto decline;
|
|
+
|
|
+ payload = hostapd_parse_intra_access(payload, scs);
|
|
+ payload = hostapd_parse_tclas(payload, scs);
|
|
+ payload = hostapd_parse_qos_attr(payload, scs);
|
|
+
|
|
+ if (!payload) {
|
|
+ wpa_printf(MSG_ERROR, "%s:%d> scs id %d qos is not present\n",
|
|
+ __func__, __LINE__, scs->desc.id);
|
|
+ goto decline;
|
|
+ }
|
|
+
|
|
+ ret = hostapd_add_scs(hapd, sta, scs);
|
|
+ break;
|
|
+ case HOSTAPD_SCS_REQ_TYPE_REMOVE:
|
|
+ if (scs_avail != HOSTAPD_SCS_PRESENT) {
|
|
+ wpa_printf(MSG_ERROR, "%s:%d> scs id %d is not preset\n",
|
|
+ __func__, __LINE__, scs->desc.id);
|
|
+ goto decline;
|
|
+ }
|
|
+ ret = hostapd_remove_scs(hapd, sta, scs->desc.id);
|
|
+ break;
|
|
+ case HOSTAPD_SCS_REQ_TYPE_CHANGE:
|
|
+ if (scs_avail != HOSTAPD_SCS_PRESENT) {
|
|
+ wpa_printf(MSG_ERROR, "%s:%d> scs id %d is not preset\n",
|
|
+ __func__, __LINE__, scs->desc.id);
|
|
+ goto decline;
|
|
+ }
|
|
+ ret = hostapd_change_scs(hapd, sta, scs);
|
|
+ break;
|
|
+ default:
|
|
+ goto decline;
|
|
+ }
|
|
+ return ret;
|
|
+
|
|
+decline:
|
|
+ wpa_printf(MSG_ERROR, "%s: Decline Request %d\n", __func__, scs->desc.req_type);
|
|
+ return HOSTAPD_SCS_REQ_DECLINED;
|
|
+}
|
|
+
|
|
+static void send_scs_response(struct hostapd_data *hapd, struct sta_info *sta,
|
|
+ const u8 *da, int dialog_token, u8 index)
|
|
+{
|
|
+ struct wpabuf *buf;
|
|
+ size_t len;
|
|
+ int i = 0;
|
|
+ u8 status;
|
|
+
|
|
+ len = IEEE80211_MGMT_MIN_LEN + sizeof(struct hostapd_scs_resp);
|
|
+ buf = wpabuf_alloc(len);
|
|
+ if (buf == NULL)
|
|
+ return;
|
|
+
|
|
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
|
|
+ wpabuf_put_u8(buf, ROBUST_AV_SCS_RESP);
|
|
+ wpabuf_put_u8(buf, (u8)dialog_token);
|
|
+ wpabuf_put_u8(buf, index);
|
|
+
|
|
+ while ((index != 0) && (i < HOSTAPD_SCS_MAX_SIZE)) {
|
|
+ wpabuf_put_u8(buf, sta->scs_resp->scsid[i]);
|
|
+ status = sta->scs_resp->status[i] & 0x000000ff;
|
|
+ wpabuf_put_u8(buf, status);
|
|
+ status = (sta->scs_resp->status[i] & 0x0000ff00) >> 8;
|
|
+ wpabuf_put_u8(buf, status);
|
|
+ index--;
|
|
+ i++;
|
|
+ }
|
|
+ len = wpabuf_len(buf);
|
|
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
|
|
+ wpabuf_head(buf), len);
|
|
+ wpa_printf(MSG_INFO, "%s: successfully sent SCS response frame len %d\n", __func__, (int)len);
|
|
+ wpabuf_free(buf);
|
|
+}
|
|
+
|
|
+static int hostapd_handle_scs_req(struct hostapd_data *hapd,
|
|
+ const u8 *buf, size_t len)
|
|
+{
|
|
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
|
+ struct hostapd_scs_desc_list scs = {0};
|
|
+ struct sta_info *sta;
|
|
+ const u8 *payload, *payload_start;
|
|
+ int ret = 0, par_len = 0;
|
|
+ u8 token, index = 0;
|
|
+
|
|
+ sta = ap_get_sta(hapd, mgmt->sa);
|
|
+
|
|
+ if (!sta)
|
|
+ return 0;
|
|
+
|
|
+ if (!sta->scs_resp)
|
|
+ sta->scs_resp =
|
|
+ (struct hostapd_scs_resp *)os_zalloc(sizeof(struct hostapd_scs_resp));
|
|
+
|
|
+ if (sta->scs_resp == NULL) {
|
|
+ wpa_printf(MSG_ERROR, "%s warn: mem alloc failure size %d\n", __func__,
|
|
+ (int)sizeof(struct hostapd_scs_resp));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ token = mgmt->u.action.u.scs.dialog_token;
|
|
+ payload_start = mgmt->u.action.u.scs.variable;
|
|
+
|
|
+ while ((par_len < len) && (index < HOSTAPD_SCS_MAX_SIZE)) {
|
|
+ payload = payload_start;
|
|
+ payload = hostapd_parse_scs_desc(payload, &scs);
|
|
+ if (!payload)
|
|
+ break;
|
|
+
|
|
+ os_memcpy(scs.peer_mac, mgmt->sa, ETH_ALEN);
|
|
+ ret = hostapd_process_scs_req(hapd, sta, payload, &scs);
|
|
+ sta->scs_resp->scsid[index] = scs.desc.id;
|
|
+ sta->scs_resp->status[index] = ret;
|
|
+
|
|
+ index++;
|
|
+ payload_start += (scs.elem.len + 2);
|
|
+ par_len += (scs.elem.len + 2);
|
|
+ hostapd_scs_dump(&scs);
|
|
+ }
|
|
+
|
|
+ send_scs_response(hapd, sta, mgmt->sa, token, index);
|
|
+ os_free(sta->scs_resp);
|
|
+ sta->scs_resp = NULL;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static uint8_t hostapd_scs_mgmt_fill_hdr(struct hostapd_scs_mgmt_hdr *hdr)
|
|
+{
|
|
+ hdr->elemid = WLAN_EID_VENDOR_SPECIFIC;
|
|
+ hdr->len = 0;
|
|
+ hdr->oui[0] = HOSTAPD_SCS_VENDOR_OUI1;
|
|
+ hdr->oui[1] = HOSTAPD_SCS_VENDOR_OUI2;
|
|
+ hdr->oui[2] = HOSTAPD_SCS_VENDOR_OUI3;
|
|
+ hdr->oui_type = QM_IE_OUI_TYPE;
|
|
+
|
|
+ return sizeof(struct hostapd_scs_mgmt_hdr);
|
|
+}
|
|
+
|
|
+uint8_t hostapd_scs_ie_len(struct hostapd_data *hapd) {
|
|
+ return (sizeof(struct hostapd_scs_mgmt_hdr) + HOSTAPD_SCS_ATTR_SIZE);
|
|
+}
|
|
+
|
|
+uint8_t *hostapd_add_scs_cap(uint8_t *frm, bool dscp_policy, bool scs)
|
|
+{
|
|
+ uint8_t scs_cap_attr = 0;
|
|
+ uint8_t ie_len = 0;
|
|
+ struct hostapd_scs_mgmt_hdr *hostapd_scs_mgmt_hdr = (struct hostapd_scs_mgmt_hdr *)frm;
|
|
+
|
|
+ ie_len += hostapd_scs_mgmt_fill_hdr(hostapd_scs_mgmt_hdr);
|
|
+ frm += ie_len;
|
|
+
|
|
+ *frm++ = HOSTAPD_SCS_NO_OF_ATTR;
|
|
+ scs_cap_attr |= (dscp_policy << HOSTAPD_DSCP_ACTION_CAP_BIT);
|
|
+ scs_cap_attr |= (scs << HOSTAPD_SCS_DESCR_CAP_BIT);
|
|
+ *frm++ = scs_cap_attr;
|
|
+ hostapd_scs_mgmt_hdr->oui_type = WFA_CAPA_OUI_TYPE;
|
|
+ ie_len += HOSTAPD_SCS_ATTR_SIZE;
|
|
+
|
|
+ hostapd_scs_mgmt_hdr->len = ie_len - HOSTAPD_SCS_ATTR_SIZE;
|
|
+ return frm;
|
|
+}
|
|
+
|
|
+void hostapd_handle_scs(struct hostapd_data *hapd, const u8 *buf, size_t len)
|
|
+{
|
|
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
|
+
|
|
+ if (len < IEEE80211_HDRLEN + 3) {
|
|
+ wpa_printf(MSG_ERROR, "%s SCS frame length error, len %lu from", __func__, len);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ switch (mgmt->u.action.u.scs.action) {
|
|
+ case ROBUST_AV_SCS_REQ:
|
|
+ hostapd_handle_scs_req(hapd, buf, len);
|
|
+ break;
|
|
+ case ROBUST_AV_SCS_RESP:
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
--- /dev/null
|
|
+++ b/src/ap/scs.h
|
|
@@ -0,0 +1,273 @@
|
|
+/*
|
|
+ * Copyright (c) 2023, 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.
|
|
+ */
|
|
+
|
|
+struct hostapd_data;
|
|
+struct sta_info;
|
|
+
|
|
+#ifndef SCS_H
|
|
+#define SCS_H
|
|
+
|
|
+#define HOSTAPD_MIN(x, y) ((x > y) ? y : x)
|
|
+#define HOSTAPD_MAX(x, y) ((x > y) ? x : y)
|
|
+
|
|
+#define HOSTAPD_DSCP_ACTION_CAP_BIT 0
|
|
+#define HOSTAPD_SCS_DESCR_CAP_BIT 2
|
|
+
|
|
+/* WME stream classes */
|
|
+#define HOSTAPD_SCS_BEST_EFF 0 /* best effort */
|
|
+#define HOSTAPD_SCS_BGROUND 1 /* background */
|
|
+#define HOSTAPD_SCS_VIDEO 2 /* video */
|
|
+#define HOSTAPD_SCS_VOICE 3 /* voice */
|
|
+#define HOSTAPD_SCS_MAX_AC 4 /* MAX AC Value */
|
|
+
|
|
+#define HOSTAPD_SCS_EXTCAP_INDEX 6
|
|
+#define HOSTAPD_SCS_EXTCAP_SCS_DESC 0x40
|
|
+#define HOSTAPD_SCS_EXTCAP_ROBUST_AV 0x08
|
|
+
|
|
+#define HOSTAPD_SCS_VENDOR_OUI1 0x50
|
|
+#define HOSTAPD_SCS_VENDOR_OUI2 0x6f
|
|
+#define HOSTAPD_SCS_VENDOR_OUI3 0x9a
|
|
+
|
|
+#define HOSTAPD_SCS_NO_OF_ATTR 1
|
|
+#define HOSTAPD_SCS_ATTR_SIZE 2
|
|
+
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_DIRECTION_MASK 0x3
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_DIRECTION_SHIFT 0
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_TID_MASK 0x3C
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_TID_SHIFT 2
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_UP_MASK 0x1C0
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_UP_SHIFT 6
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_BMP_MASK 0x1FFFE00
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_BMP_SHIFT 9
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_LINK_ID_MASK 0x1E000000
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_LINK_ID_SHIFT 25
|
|
+
|
|
+#define HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_LEN 4
|
|
+#define HOSTAPD_SCS_QOS_ATTR_SERVICE_INTERVAL_LEN 4
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MIN_DATA_RATE_LEN 3
|
|
+#define HOSTAPD_SCS_QOS_ATTR_DELAY_BOULND_LEN 3
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MAX_MSDU_SIZE_LEN 2
|
|
+#define HOSTAPD_SCS_QOS_ATTR_SERVICE_START_TIME_LEN 4
|
|
+#define HOSTAPD_SCS_QOS_ATTR_SERVICE_START_TIME_LINK_ID_LEN 1
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MEAN_DATA_RATE_LEN 3
|
|
+#define HOSTAPD_SCS_QOS_ATTR_BURST_SIZE_LEN 4
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_LIFETIME_LEN 2
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_DELIVERY_RATIO_LEN 1
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_COUNT_EXPONENT_LEN 1
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MEDIUM_TIME_LEN 2
|
|
+
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MAX_MSDU_SIZE_MASK 0x0001
|
|
+#define HOSTAPD_SCS_QOS_ATTR_SERVICE_START_TIME_MASK 0x0002
|
|
+#define HOSTAPD_SCS_QOS_ATTR_SERVICE_START_TIME_LINK_ID_MASK 0x0004
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MEAN_DATA_RATE_MASK 0x0008
|
|
+#define HOSTAPD_SCS_QOS_ATTR_BURST_SIZE_MASK 0x0010
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_LIFETIME_MASK 0x0020
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_DELIVERY_RATIO_MASK 0x0040
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MSDU_COUNT_EXPONENT_MASK 0x0080
|
|
+#define HOSTAPD_SCS_QOS_ATTR_MEDIUM_TIME_MASK 0x0100
|
|
+
|
|
+#define HOSTAPD_SCS_REQ_TYPE_ADD 0
|
|
+#define HOSTAPD_SCS_REQ_TYPE_REMOVE 1
|
|
+#define HOSTAPD_SCS_REQ_TYPE_CHANGE 2
|
|
+
|
|
+#define HOSTAPD_ADD_RULE 1
|
|
+#define HOSTAPD_REM_RULE 2
|
|
+
|
|
+#define HOSTAPD_SCS_REQ_SUCCESS 0
|
|
+#define HOSTAPD_SCS_REQ_DECLINED 37
|
|
+#define HOSTAPD_SCS_REQ_REJECTED_WITH_SUGGESTED_CHANGES 39
|
|
+#define HOSTAPD_SCS_REQ_REQUESTED_TCLAS_NOT_SUPPORTED 56
|
|
+#define HOSTAPD_SCS_REQ_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES 57
|
|
+#define HOSTAPD_SCS_REQ_TCLAS_PROCESSING_TERMINATED 97
|
|
+
|
|
+#define HOSTAPD_SCS_PRESENT 1
|
|
+#define HOSTAPD_SCS_NOT_PRESENT 0
|
|
+#define HOSTAPD_SCS_MEM_NOT_AVAILABLE 2
|
|
+
|
|
+
|
|
+#define le8toh(x) x
|
|
+
|
|
+#define HOSTAPD_GET_QOS_ATTR_CTRL_INFO(ctrl_det, PARAM) \
|
|
+ ((ctrl_det & HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_##PARAM##_MASK) >> \
|
|
+ HOSTAPD_SCS_QOS_ATTR_CTRL_INFO_##PARAM##_SHIFT)
|
|
+
|
|
+#define HOSTAPD_GET_QOS_ATTR_ACTUAL(var, payload, temp_payload, PARAM, bit) \
|
|
+ do { \
|
|
+ var = (le##bit##toh(*((u##bit *)temp_payload))); \
|
|
+ payload += HOSTAPD_SCS_QOS_ATTR_##PARAM##_LEN; \
|
|
+ } while (0)
|
|
+
|
|
+#define HOSTAPD_GET_QOS_ATTR(var, payload, PARAM, bit) \
|
|
+ do { \
|
|
+ var = (le##bit##toh(*((u##bit *)payload))); \
|
|
+ payload += HOSTAPD_SCS_QOS_ATTR_##PARAM##_LEN; \
|
|
+ } while (0)
|
|
+
|
|
+#define HOSTAPD_GET_QOS_ATTR_16(var, payload, PARAM) \
|
|
+ do { \
|
|
+ var = (le16toh(*((u16 *)payload))); \
|
|
+ payload += HOSTAPD_SCS_QOS_ATTR_##PARAM##_LEN; \
|
|
+ while (0)
|
|
+
|
|
+#define HOSTAPD_SCS_IS_QOS_ATTR_PRESENT(PARAM1, PARAM2) \
|
|
+ (PARAM1 & HOSTAPD_SCS_QOS_ATTR_##PARAM2##_MASK)
|
|
+
|
|
+enum ip_version {
|
|
+ IPV4 = 4,
|
|
+ IPV6 = 6,
|
|
+};
|
|
+
|
|
+struct hostapd_ipv4_params {
|
|
+ struct in_addr src_ip;
|
|
+ struct in_addr dst_ip;
|
|
+ u16 src_port;
|
|
+ u16 dst_port;
|
|
+ u8 dscp;
|
|
+ u8 protocol;
|
|
+};
|
|
+
|
|
+struct hostapd_ipv6_params {
|
|
+ struct in6_addr src_ip;
|
|
+ struct in6_addr dst_ip;
|
|
+ u16 src_port;
|
|
+ u16 dst_port;
|
|
+ u8 dscp;
|
|
+ u8 next_header;
|
|
+ u8 flow_label[3];
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_type4_params {
|
|
+ u8 classifier_mask;
|
|
+ enum ip_version ip_version;
|
|
+ union {
|
|
+ struct hostapd_ipv4_params v4;
|
|
+ struct hostapd_ipv6_params v6;
|
|
+ } ip_params;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_type10_params {
|
|
+ u8 prot_instance;
|
|
+ u8 prot_number;
|
|
+ u8 *filter_value;
|
|
+ u8 *filter_mask;
|
|
+ size_t filter_len;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+
|
|
+struct tclas_element {
|
|
+ u8 elem_id;
|
|
+ u8 len;
|
|
+ u8 up;
|
|
+ u8 type;
|
|
+ u8 mask;
|
|
+ union {
|
|
+ struct hostapd_type4_params type4_param;
|
|
+ struct hostapd_type10_params type10_param;
|
|
+ } frame_classifier;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+/* Final struct*/
|
|
+struct hostapd_element {
|
|
+ u8 id;
|
|
+ u8 len;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_scs_desc {
|
|
+ u8 id;
|
|
+ u8 req_type;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_intra_access_cat {
|
|
+ struct hostapd_element elem;
|
|
+ u8 priority;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_tclas {
|
|
+ struct hostapd_element elem;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_qos_attr_ctrl_info {
|
|
+ u32 direction:2;
|
|
+ u32 tid:4;
|
|
+ u32 up:3;
|
|
+ u32 bitmap:16;
|
|
+ u32 link_id:4;
|
|
+ u32 reserved:3;
|
|
+ u8 access_cat;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_qos_mandatory_scs_param {
|
|
+ u32 service_interval;
|
|
+ u32 delay_bound;
|
|
+ u32 burst_size;
|
|
+ u32 min_data_rate;
|
|
+ u8 peer_mac[ETH_ALEN];
|
|
+ u8 scsid;
|
|
+ u8 ac;
|
|
+ u8 up;
|
|
+ u8 direction;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_qos_attr {
|
|
+ struct hostapd_element elem;
|
|
+ struct hostapd_qos_attr_ctrl_info ctrl_info;
|
|
+ u32 min_interval;
|
|
+ u32 max_interval;
|
|
+ u32 final_serv_intvl;
|
|
+ u32 min_data_rate;
|
|
+ u32 delay_bound;
|
|
+ u32 serv_start_time;
|
|
+ u32 mean_data_rate;
|
|
+ u32 burst_size;
|
|
+ u32 final_burst_size;
|
|
+ u16 max_msdu_size;
|
|
+ u16 msdu_life_time;
|
|
+ u16 medium_time;
|
|
+ u8 attr_id;
|
|
+ u8 serv_start_time_link_id;
|
|
+ u8 msdu_delivery_ratio;
|
|
+ u8 msdu_cnt_exp;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_scs_desc_list {
|
|
+ struct hostapd_element elem;
|
|
+ struct hostapd_scs_desc desc;
|
|
+ struct hostapd_intra_access_cat ia;
|
|
+ struct hostapd_tclas tclas;
|
|
+ struct hostapd_qos_attr qos_attr;
|
|
+ u8 peer_mac[ETH_ALEN];
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_scs_mgmt_hdr {
|
|
+ uint8_t elemid;
|
|
+ uint8_t len;
|
|
+ uint8_t oui[3];
|
|
+ uint8_t oui_type;
|
|
+} STRUCT_PACKED;
|
|
+
|
|
+struct hostapd_scs_resp {
|
|
+ u8 scsid[HOSTAPD_SCS_MAX_SIZE];
|
|
+ u8 status[HOSTAPD_SCS_MAX_SIZE];
|
|
+};
|
|
+
|
|
+void hostapd_handle_scs(struct hostapd_data *hapd, const u8 *buf, size_t len);
|
|
+
|
|
+uint8_t *hostapd_add_scs_cap(uint8_t *frm, bool dscp_policy, bool scs);
|
|
+
|
|
+int hostapd_free_all_scs(struct hostapd_data *hapd, struct sta_info *sta);
|
|
+
|
|
+uint8_t hostapd_scs_ie_len(struct hostapd_data *hapd);
|
|
+#endif
|
|
--- a/src/ap/sta_info.c
|
|
+++ b/src/ap/sta_info.c
|
|
@@ -39,6 +39,9 @@
|
|
#include "sta_info.h"
|
|
#include "vlan.h"
|
|
#include "wps_hostapd.h"
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#include "scs.h"
|
|
+#endif
|
|
|
|
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
|
struct sta_info *sta);
|
|
@@ -192,6 +195,7 @@ void ap_free_sta(struct hostapd_data *ha
|
|
struct hostapd_data *vlan_bss = hapd;
|
|
int set_beacon = 0;
|
|
|
|
+ hostapd_free_all_scs(hapd, sta);
|
|
accounting_sta_stop(hapd, sta);
|
|
|
|
/* just in case */
|
|
@@ -848,6 +852,7 @@ static int ap_sta_remove(struct hostapd_
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
|
|
hapd->conf->iface, MAC2STR(sta->addr));
|
|
+ hostapd_free_all_scs(hapd, sta);
|
|
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
|
|
sta->flags & WLAN_STA_ASSOC) {
|
|
wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
|
|
--- a/src/ap/sta_info.h
|
|
+++ b/src/ap/sta_info.h
|
|
@@ -18,6 +18,8 @@
|
|
#include "crypto/sha384.h"
|
|
#include "pasn/pasn_common.h"
|
|
|
|
+#define HOSTAPD_SCS_MAX_SIZE 10
|
|
+#define HOSTAPD_SCS_AC_MAX 4
|
|
/* STA flags */
|
|
#define WLAN_STA_AUTH BIT(0)
|
|
#define WLAN_STA_ASSOC BIT(1)
|
|
@@ -55,6 +57,8 @@
|
|
|
|
struct hostapd_data;
|
|
struct mld_link_info;
|
|
+struct hostapd_scs_desc_list;
|
|
+struct hostapd_qos_mandatory_scs_param;
|
|
|
|
struct mbo_non_pref_chan_info {
|
|
struct mbo_non_pref_chan_info *next;
|
|
@@ -284,6 +288,7 @@ struct sta_info {
|
|
u8 fils_snonce[FILS_NONCE_LEN];
|
|
u8 fils_session[FILS_SESSION_LEN];
|
|
u8 fils_erp_pmkid[PMKID_LEN];
|
|
+
|
|
u8 *fils_pending_assoc_req;
|
|
size_t fils_pending_assoc_req_len;
|
|
unsigned int fils_pending_assoc_is_reassoc:1;
|
|
@@ -342,6 +347,12 @@ struct sta_info {
|
|
#endif /* CONFIG_IEEE80211BE */
|
|
struct ieee80211_240mhz_vendor_oper *eht_240mhz_capab;
|
|
size_t eht_240mhz_len;
|
|
+
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ struct hostapd_qos_mandatory_scs_param *scs_data[HOSTAPD_SCS_AC_MAX];
|
|
+ struct hostapd_scs_resp *scs_resp;
|
|
+ u8 session_cnt;
|
|
+#endif
|
|
};
|
|
|
|
|
|
--- a/src/common/ieee802_11_defs.h
|
|
+++ b/src/common/ieee802_11_defs.h
|
|
@@ -943,7 +943,8 @@ struct ieee80211_hdr {
|
|
#define IEEE80211_BSSID_FROMDS addr2
|
|
#define IEEE80211_SA_FROMDS addr3
|
|
|
|
-#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
|
|
+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
|
|
+#define IEEE80211_MGMT_MIN_LEN 16
|
|
|
|
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
|
|
|
|
@@ -1121,6 +1122,11 @@ struct ieee80211_mgmt {
|
|
u8 dialog_token;
|
|
u8 variable[];
|
|
} STRUCT_PACKED rrm;
|
|
+ struct {
|
|
+ u8 action;
|
|
+ u8 dialog_token;
|
|
+ u8 variable[];
|
|
+ } STRUCT_PACKED scs;
|
|
} u;
|
|
} STRUCT_PACKED action;
|
|
} u;
|
|
@@ -2585,6 +2591,9 @@ struct ieee80211_eht_operation {
|
|
EHT_PHYCAP_MU_BEAMFORMER_160MHZ | \
|
|
EHT_PHYCAP_MU_BEAMFORMER_320MHZ)
|
|
|
|
+#define EHT_PHYCAP_SCS_DESC_IDX 5
|
|
+#define EHT_PHYCAP_SCS_DESC_BIT ((u8) BIT(1))
|
|
+
|
|
/* Figure 9-1002ah: Supported EHT-MCS and NSS Set field format */
|
|
#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY 4
|
|
#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS 3
|
|
--- a/src/common/qca-vendor.h
|
|
+++ b/src/common/qca-vendor.h
|
|
@@ -14664,6 +14664,13 @@ enum qca_wlan_vendor_attr_scs_rule_confi
|
|
QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_SERVICE_CLASS_ID = 19,
|
|
QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DST_MAC_ADDR = 20,
|
|
QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_NETDEV_IF_INDEX = 21,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_SERVICE_INTERVAL = 22,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_BURST_SIZE = 23,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DELAY_BOUND = 24,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_MINIMUM_DATA_RATE = 25,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_USER_PRIORITY = 26,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_ACCESS_CATEGORY = 27,
|
|
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DIRECTION = 28,
|
|
|
|
/* Keep last */
|
|
QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_AFTER_LAST,
|
|
--- a/src/drivers/driver.h
|
|
+++ b/src/drivers/driver.h
|
|
@@ -107,6 +107,18 @@ struct hostapd_wmm_rule {
|
|
int max_txop;
|
|
};
|
|
|
|
+struct scs_latency_params {
|
|
+ u32 service_interval;
|
|
+ u32 burst_size;
|
|
+ u32 delay_bound;
|
|
+ u32 min_data_rate;
|
|
+ u8 user_priority;
|
|
+ u8 req_type;
|
|
+ u8 ac;
|
|
+ u8 direction;
|
|
+ u8 peer_mac[ETH_ALEN];
|
|
+};
|
|
+
|
|
/**
|
|
* struct hostapd_channel_data - Channel information
|
|
*/
|
|
@@ -5278,6 +5290,9 @@ struct wpa_driver_ops {
|
|
*/
|
|
struct hostapd_multi_hw_info * (*get_multi_hw_info)(void *priv,
|
|
u8 *num_multi_hws);
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+ int (*set_scs)(void *priv, struct scs_latency_params *scs_drv);
|
|
+#endif
|
|
};
|
|
|
|
/**
|
|
--- a/src/drivers/driver_nl80211.c
|
|
+++ b/src/drivers/driver_nl80211.c
|
|
@@ -74,6 +74,7 @@ enum nlmsgerr_attrs {
|
|
#endif /* ANDROID */
|
|
|
|
|
|
+
|
|
static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg)
|
|
{
|
|
struct nl_sock *handle;
|
|
@@ -2695,6 +2696,9 @@ static int nl80211_action_subscribe_ap(s
|
|
if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
|
|
ret = -1;
|
|
#endif /* CONFIG_FST */
|
|
+ /* Robust AV */
|
|
+ if (nl80211_register_action_frame(bss, (u8 *) "\x13", 1) < 0)
|
|
+ ret = -1;
|
|
/* Vendor-specific */
|
|
if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
|
|
ret = -1;
|
|
@@ -11875,7 +11879,6 @@ fail:
|
|
return -1;
|
|
}
|
|
|
|
-
|
|
static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
|
|
{
|
|
struct i802_bss *bss = priv;
|
|
@@ -14156,6 +14159,63 @@ wpa_driver_get_multi_hw_info(void *priv,
|
|
return nl80211_get_multi_hw_info(priv, num_multi_hws);
|
|
}
|
|
|
|
+#ifdef CONFIG_IEEE80211BE
|
|
+#define NL_VENDOR_SET_QOS_ATTR(msg, attr, val, bit) \
|
|
+ do { \
|
|
+ int ret; \
|
|
+ ret = nla_put_u##bit(msg, QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_##attr, val); \
|
|
+ if (ret) \
|
|
+ goto fail; \
|
|
+ } while (0)
|
|
+
|
|
+static int nl80211_set_scs(void *priv, struct scs_latency_params *scs_drv)
|
|
+{
|
|
+ struct i802_bss *bss = priv;
|
|
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
|
+ struct nl_msg *msg;
|
|
+ struct nlattr *params;
|
|
+ int ret;
|
|
+
|
|
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
|
|
+ if (!msg)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ret = nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
|
|
+ if (ret)
|
|
+ goto fail;
|
|
+
|
|
+ ret = nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
|
|
+ QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG);
|
|
+ if (ret)
|
|
+ goto fail;
|
|
+
|
|
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
|
|
+ if (!params)
|
|
+ goto fail;
|
|
+
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, SERVICE_INTERVAL, scs_drv->service_interval, 32);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, BURST_SIZE, scs_drv->burst_size, 32);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, DELAY_BOUND, scs_drv->delay_bound, 32);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, MINIMUM_DATA_RATE, scs_drv->min_data_rate, 32);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, REQUEST_TYPE, scs_drv->req_type, 8);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, USER_PRIORITY, scs_drv->user_priority, 8);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, ACCESS_CATEGORY, scs_drv->ac, 8);
|
|
+ NL_VENDOR_SET_QOS_ATTR(msg, DIRECTION, scs_drv->direction, 8);
|
|
+
|
|
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DST_MAC_ADDR,
|
|
+ ETH_ALEN, scs_drv->peer_mac);
|
|
+
|
|
+ nla_nest_end(msg, params);
|
|
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
|
|
+ return ret;
|
|
+
|
|
+fail:
|
|
+ nlmsg_free(msg);
|
|
+ wpa_printf(MSG_ERROR, "%s failed to set qos attr\n", __func__);
|
|
+ return -EINVAL;
|
|
+}
|
|
+#endif
|
|
+
|
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|
.name = "nl80211",
|
|
.desc = "Linux nl80211/cfg80211",
|
|
@@ -14314,6 +14374,7 @@ const struct wpa_driver_ops wpa_driver_n
|
|
.if_link_remove = driver_nl80211_if_link_remove,
|
|
.get_drv_shared_status = wpa_driver_get_shared_status,
|
|
.can_share_drv = wpa_driver_nl80211_can_share_drv,
|
|
+ .set_scs = nl80211_set_scs,
|
|
#endif /* CONFIG_IEEE80211BE */
|
|
.get_multi_hw_info = wpa_driver_get_multi_hw_info,
|
|
};
|