mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-11-01 19:07:47 +00:00
ipq807x_v5.4: backport AFC support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
committed by
John Crispin
parent
3ca02ca424
commit
49560ef3d3
@@ -92,6 +92,7 @@ DRIVER_MAKEOPTS= \
|
||||
CONFIG_IEEE80211N=$(HOSTAPD_IEEE80211N) \
|
||||
CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
|
||||
CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
|
||||
CONFIG_AFC=$(HOSTAPD_IEEE80211AX) \
|
||||
CONFIG_DRIVER_WEXT=$(CONFIG_DRIVER_WEXT_SUPPORT) \
|
||||
CONFIG_UCODE=y
|
||||
|
||||
@@ -138,6 +139,13 @@ endif
|
||||
|
||||
DRV_DEPENDS:=+PACKAGE_kmod-cfg80211:libnl-tiny
|
||||
|
||||
define Package/afcd
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=WirelessAPD
|
||||
TITLE:=AFC communication daemon
|
||||
DEPENDS:=+ucode +ucode-mod-uclient +ucode-mod-uloop
|
||||
endef
|
||||
|
||||
define Package/hostapd/Default
|
||||
SECTION:=net
|
||||
@@ -506,7 +514,7 @@ TARGET_CPPFLAGS := \
|
||||
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
|
||||
|
||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus -lucode -lblobmsg_json
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus -lucode -lblobmsg_json -ljson-c
|
||||
|
||||
ifdef CONFIG_PACKAGE_kmod-cfg80211
|
||||
TARGET_LDFLAGS += -lm -lnl-tiny
|
||||
@@ -589,6 +597,12 @@ define Build/Compile
|
||||
$(Build/Compile/$(BUILD_VARIANT))
|
||||
endef
|
||||
|
||||
define Package/afcd/install
|
||||
$(INSTALL_DIR) $(1)/usr/share/hostap $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/afcd.init $(1)/etc/init.d/afcd
|
||||
$(INSTALL_DATA) ./files/afcd.uc $(1)/usr/share/hostap/
|
||||
endef
|
||||
|
||||
define Install/hostapd
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
|
||||
$(INSTALL_DATA) ./files/hostapd.uc $(1)/usr/share/hostap/
|
||||
@@ -692,6 +706,7 @@ ifeq ($(BUILD_VARIANT),supplicant-full-wolfssl)
|
||||
endef
|
||||
endif
|
||||
|
||||
$(eval $(call BuildPackage,afcd))
|
||||
$(eval $(call BuildPackage,hostapd))
|
||||
$(eval $(call BuildPackage,hostapd-basic))
|
||||
$(eval $(call BuildPackage,hostapd-basic-openssl))
|
||||
|
||||
30
feeds/ipq807x_v5.4/hostapd/files/afcd.init
Normal file
30
feeds/ipq807x_v5.4/hostapd/files/afcd.init
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=19
|
||||
|
||||
USE_PROCD=1
|
||||
NAME=afcd
|
||||
|
||||
add_afc() {
|
||||
config_get_bool disabled "$1" disabled 0
|
||||
[ "$disabled" -gt 0 ] && return
|
||||
|
||||
config_get url "$1" url
|
||||
config_get cert "$1" cert
|
||||
[ -n "$cert" -a -n "$url" ] || return
|
||||
|
||||
procd_open_instance afcd
|
||||
procd_set_param command /usr/bin/ucode /usr/share/hostap/afcd.uc -u "$url" -c "$cert"
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load wireless
|
||||
config_foreach add_afc afc-server
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger wireless
|
||||
}
|
||||
132
feeds/ipq807x_v5.4/hostapd/files/afcd.uc
Normal file
132
feeds/ipq807x_v5.4/hostapd/files/afcd.uc
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env ucode
|
||||
'use strict';
|
||||
import { basename } from "fs";
|
||||
let uclient = require("uclient");
|
||||
let uloop = require("uloop");
|
||||
let libubus = require("ubus");
|
||||
let opts = {};
|
||||
let reqs = [];
|
||||
|
||||
const usage_message = `Usage: ${basename(sourcepath())} <options>
|
||||
Options:
|
||||
-u <url>: AFC server URL (required)
|
||||
-c <path>: AFC server CA certificate
|
||||
|
||||
`;
|
||||
|
||||
function usage() {
|
||||
warn(usage_message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (substr(ARGV[0], 0, 1) == "-") {
|
||||
let opt = substr(shift(ARGV), 1);
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
opts.url = shift(ARGV);
|
||||
break;
|
||||
case 'c':
|
||||
opts.cert = shift(ARGV);
|
||||
if (!opts.cert)
|
||||
usage();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.url)
|
||||
usage();
|
||||
|
||||
function request_done(cb, error)
|
||||
{
|
||||
if (!cb.req)
|
||||
return;
|
||||
|
||||
if (error)
|
||||
delete cb.data;
|
||||
|
||||
cb.req.reply({ data: cb.data }, error);
|
||||
|
||||
delete cb.req;
|
||||
delete cb.client;
|
||||
}
|
||||
|
||||
const cb_proto = {
|
||||
data_read: function(cb) {
|
||||
let cur;
|
||||
while (length(cur = this.read()) > 0)
|
||||
cb.data += cur;
|
||||
},
|
||||
data_eof: function(cb) {
|
||||
request_done(cb, 0);
|
||||
},
|
||||
error: function(cb, code) {
|
||||
request_done(cb, libubus.STATUS_UNKNOWN_ERROR);
|
||||
},
|
||||
};
|
||||
|
||||
function handle_request(req)
|
||||
{
|
||||
let cb = proto({ data: "" }, cb_proto);
|
||||
|
||||
let cl = uclient.new(opts.url, null, cb);
|
||||
|
||||
if (!cl.ssl_init({ verify: true, ca_files: [ opts.cert ] })) {
|
||||
warn(`Failed to initialize SSL\n`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cl.connect()) {
|
||||
warn(`Failed to connect\n`);
|
||||
return false;
|
||||
}
|
||||
|
||||
let meta = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
post_data: req.args.data
|
||||
};
|
||||
|
||||
if (!cl.request("POST", meta)) {
|
||||
warn(`Failed to send request\n`);
|
||||
return false;
|
||||
}
|
||||
|
||||
cb.client = cl;
|
||||
cb.req = req;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function add_ubus(ubus) {
|
||||
return ubus.publish("afc", {
|
||||
request: {
|
||||
call: function(req) {
|
||||
if (!req.args.data)
|
||||
return libubus.STATUS_INVALID_ARGUMENT;
|
||||
|
||||
let ret = handle_request(req);
|
||||
if (!ret)
|
||||
return libubus.STATUS_UNKNOWN_ERROR;
|
||||
|
||||
req.defer();
|
||||
},
|
||||
args: {
|
||||
data: "",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
uloop.init();
|
||||
|
||||
let ubus = libubus.connect();
|
||||
if (!add_ubus(ubus)) {
|
||||
warn("Failed to publish ubus object\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uloop.run();
|
||||
uloop.done();
|
||||
@@ -126,9 +126,30 @@ hostapd_common_add_device_config() {
|
||||
|
||||
config_add_boolean multiple_bssid rnr_beacon he_co_locate ema
|
||||
|
||||
config_add_boolean afc
|
||||
config_add_string \
|
||||
afc_request_version afc_request_id afc_serial_number \
|
||||
afc_location_type afc_location afc_height afc_height_type
|
||||
config_add_array afc_cert_ids afc_freq_range afc_op_class
|
||||
config_add_int \
|
||||
afc_min_power afc_major_axis afc_minor_axis afc_orientation \
|
||||
afc_vertical_tolerance
|
||||
|
||||
hostapd_add_log_config
|
||||
}
|
||||
|
||||
|
||||
hostapd_get_list() {
|
||||
local var="$1"
|
||||
local field="$2"
|
||||
|
||||
local cur __val_list
|
||||
json_get_values __val_list "$field"
|
||||
for cur in $__val_list; do
|
||||
append "$var" "$cur" ","
|
||||
done
|
||||
}
|
||||
|
||||
hostapd_prepare_device_config() {
|
||||
local config="$1"
|
||||
local driver="$2"
|
||||
@@ -139,7 +160,7 @@ hostapd_prepare_device_config() {
|
||||
acs_chan_bias local_pwr_constraint spectrum_mgmt_required airtime_mode cell_density \
|
||||
rts_threshold beacon_rate rssi_reject_assoc_rssi rssi_ignore_probe_request maxassoc \
|
||||
multiple_bssid he_co_locate rnr_beacon ema acs_exclude_dfs \
|
||||
maxassoc_ignore_probe
|
||||
maxassoc_ignore_probe band
|
||||
|
||||
hostapd_set_log_options base_cfg
|
||||
|
||||
@@ -252,6 +273,45 @@ hostapd_prepare_device_config() {
|
||||
[ "$multiple_bssid" -gt 0 ] && append base_cfg "multiple_bssid=$multiple_bssid" "$N"
|
||||
[ "$ema" -gt 0 ] && append base_cfg "ema=$ema" "$N"
|
||||
[ "$acs_exclude_dfs" -gt 0 ] && append base_cfg "acs_exclude_dfs=$acs_exclude_dfs" "$N"
|
||||
if [ "$band" = "6g" ]; then
|
||||
json_get_vars afc he_6ghz_reg_pwr_type
|
||||
else
|
||||
afc=0
|
||||
he_6ghz_reg_pwr_type=
|
||||
fi
|
||||
set_default afc 0
|
||||
[ "$afc" -gt 0 ] && {
|
||||
for v in afc_request_version afc_request_id afc_serial_number afc_min_power afc_height afc_height_type afc_vertical_tolerance \
|
||||
afc_major_axis afc_minor_axis afc_orientation; do
|
||||
json_get_var val $v
|
||||
append base_cfg "$v=$val" "$N"
|
||||
done
|
||||
|
||||
for v in afc_cert_ids afc_op_class afc_freq_range; do
|
||||
val=
|
||||
hostapd_get_list val $v
|
||||
append base_cfg "$v=$val" "$N"
|
||||
done
|
||||
|
||||
json_get_vars afc_location_type afc_location
|
||||
case "$afc_location_type" in
|
||||
ellipse)
|
||||
append base_cfg "afc_location_type=0" "$N"
|
||||
append base_cfg "afc_linear_polygon=$afc_location" "$N"
|
||||
;;
|
||||
linear_polygon)
|
||||
append base_cfg "afc_location_type=1" "$N"
|
||||
append base_cfg "afc_linear_polygon=$afc_location" "$N"
|
||||
;;
|
||||
radial_polygon)
|
||||
append base_cfg "afc_location_type=2" "$N"
|
||||
append base_cfg "afc_radial_polygon=$afc_location" "$N"
|
||||
;;
|
||||
esac
|
||||
|
||||
he_6ghz_reg_pwr_type=1
|
||||
}
|
||||
[ -n "$he_6ghz_reg_pwr_type" ] && append base_cfg "he_6ghz_reg_pwr_type=$he_6ghz_reg_pwr_type" "$N"
|
||||
|
||||
json_get_values opts hostapd_options
|
||||
for val in $opts; do
|
||||
|
||||
@@ -800,6 +800,12 @@ return {
|
||||
iface_set_config(phy, null);
|
||||
hostapd.ubus.disconnect();
|
||||
},
|
||||
afc_request: function(iface, data) {
|
||||
let ret = ubus.call("afc", "request", { data });
|
||||
if (type(ret) != "object")
|
||||
return;
|
||||
return ret.data;
|
||||
},
|
||||
bss_add: function(name, obj) {
|
||||
bss_event("add", name);
|
||||
},
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
"access": {
|
||||
"service": {
|
||||
"methods": [ "event" ]
|
||||
},
|
||||
"wpa_supplicant": {
|
||||
"methods": [ "phy_set_state", "phy_set_macaddr_list", "phy_status" ]
|
||||
},
|
||||
"hostapd": {
|
||||
"methods": [ "apsta_state" ]
|
||||
},
|
||||
"afc": {
|
||||
"methods": [ "request" ]
|
||||
}
|
||||
},
|
||||
"publish": [ "hostapd", "hostapd.*", "wpa_supplicant", "wpa_supplicant.*" ],
|
||||
|
||||
@@ -0,0 +1,575 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Sat, 17 Feb 2024 11:24:44 +0100
|
||||
Subject: [PATCH] hostapd: afcd: add AFC daemon support
|
||||
|
||||
Introduce Automated Frequency Coordination Daemon (AFCD) support
|
||||
for UNII-5 and UNII-7 6GHz bands.
|
||||
AFCD will be used by hostapd AFC client in order to forward the AFC
|
||||
request to the AFC coordinator and decouple AFC connection management
|
||||
from hostapd.
|
||||
AFC is required for Standard Power Devices (SPDs) to determine a lists
|
||||
of channels and EIRP/PSD powers that are available in the 6GHz spectrum.
|
||||
AFCD is tested with AFC DUT Test Harness [0].
|
||||
Add afc-reply.json as reference for replies from the AFC coordinator.
|
||||
|
||||
[0] https://github.com/Wi-FiTestSuite/AFC-DUT/tree/main
|
||||
|
||||
Tested-by: Allen Ye <allen.ye@mediatek.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
---
|
||||
create mode 100644 afc/.gitignore
|
||||
create mode 100644 afc/Makefile
|
||||
create mode 100644 afc/afc-reply.json
|
||||
create mode 100644 afc/afcd.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/afc/.gitignore
|
||||
@@ -0,0 +1 @@
|
||||
+afcd
|
||||
--- /dev/null
|
||||
+++ b/afc/Makefile
|
||||
@@ -0,0 +1,31 @@
|
||||
+ALL=afcd
|
||||
+
|
||||
+include ../src/build.rules
|
||||
+
|
||||
+CFLAGS += -I../src/utils
|
||||
+CFLAGS += -I../src
|
||||
+
|
||||
+OBJS=afcd.o
|
||||
+OBJS += ../src/utils/common.o
|
||||
+OBJS += ../src/utils/wpa_debug.o
|
||||
+OBJS += ../src/utils/wpabuf.o
|
||||
+
|
||||
+ifndef CONFIG_OS
|
||||
+ifdef CONFIG_NATIVE_WINDOWS
|
||||
+CONFIG_OS=win32
|
||||
+else
|
||||
+CONFIG_OS=unix
|
||||
+endif
|
||||
+endif
|
||||
+OBJS += ../src/utils/os_$(CONFIG_OS).o
|
||||
+
|
||||
+LIBS += -lcurl
|
||||
+
|
||||
+_OBJS_VAR := OBJS
|
||||
+include ../src/objs.mk
|
||||
+afcd: $(OBJS)
|
||||
+ $(Q)$(LDO) $(LDFLAGS) -o afcd $(OBJS) $(LIBS)
|
||||
+ @$(E) " LD " $@
|
||||
+
|
||||
+clean: common-clean
|
||||
+ rm -f core *~
|
||||
--- /dev/null
|
||||
+++ b/afc/afc-reply.json
|
||||
@@ -0,0 +1,215 @@
|
||||
+{
|
||||
+ "availableSpectrumInquiryResponses":[
|
||||
+ {
|
||||
+ "availabilityExpireTime":"2023-02-23T12:53:18Z",
|
||||
+ "availableChannelInfo":[
|
||||
+ {
|
||||
+ "channelCfi":[
|
||||
+ 1,
|
||||
+ 5,
|
||||
+ 9,
|
||||
+ 13,
|
||||
+ 17,
|
||||
+ 21,
|
||||
+ 25,
|
||||
+ 29,
|
||||
+ 33,
|
||||
+ 37,
|
||||
+ 41,
|
||||
+ 45,
|
||||
+ 49,
|
||||
+ 53,
|
||||
+ 57,
|
||||
+ 61,
|
||||
+ 65,
|
||||
+ 69,
|
||||
+ 73,
|
||||
+ 77,
|
||||
+ 81,
|
||||
+ 85,
|
||||
+ 89,
|
||||
+ 93,
|
||||
+ 117,
|
||||
+ 121,
|
||||
+ 125,
|
||||
+ 129,
|
||||
+ 133,
|
||||
+ 137,
|
||||
+ 141,
|
||||
+ 145,
|
||||
+ 149,
|
||||
+ 153,
|
||||
+ 157,
|
||||
+ 161,
|
||||
+ 165,
|
||||
+ 169,
|
||||
+ 173,
|
||||
+ 177,
|
||||
+ 181
|
||||
+ ],
|
||||
+ "globalOperatingClass":131,
|
||||
+ "maxEirp":[
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5
|
||||
+ ]
|
||||
+ },
|
||||
+ {
|
||||
+ "channelCfi":[
|
||||
+ 3,
|
||||
+ 11,
|
||||
+ 19,
|
||||
+ 27,
|
||||
+ 35,
|
||||
+ 43,
|
||||
+ 51,
|
||||
+ 59,
|
||||
+ 67,
|
||||
+ 75,
|
||||
+ 83,
|
||||
+ 91,
|
||||
+ 123,
|
||||
+ 131,
|
||||
+ 139,
|
||||
+ 147,
|
||||
+ 155,
|
||||
+ 163,
|
||||
+ 171,
|
||||
+ 179
|
||||
+ ],
|
||||
+ "globalOperatingClass":132,
|
||||
+ "maxEirp":[
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5
|
||||
+ ]
|
||||
+ },
|
||||
+ {
|
||||
+ "channelCfi":[
|
||||
+ 7,
|
||||
+ 23,
|
||||
+ 39,
|
||||
+ 55,
|
||||
+ 71,
|
||||
+ 87,
|
||||
+ 135,
|
||||
+ 151,
|
||||
+ 167
|
||||
+ ],
|
||||
+ "globalOperatingClass":133,
|
||||
+ "maxEirp":[
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5
|
||||
+ ]
|
||||
+ },
|
||||
+ {
|
||||
+ "channelCfi":[
|
||||
+ 15,
|
||||
+ 47,
|
||||
+ 79,
|
||||
+ 143
|
||||
+ ],
|
||||
+ "globalOperatingClass":134,
|
||||
+ "maxEirp":[
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5,
|
||||
+ 5
|
||||
+ ]
|
||||
+ },
|
||||
+ {
|
||||
+ "channelCfi":[
|
||||
+ ],
|
||||
+ "globalOperatingClass":135,
|
||||
+ "maxEirp":[
|
||||
+ ]
|
||||
+ }
|
||||
+ ],
|
||||
+ "availableFrequencyInfo":[
|
||||
+ {
|
||||
+ "frequencyRange":{
|
||||
+ "highFrequency":6425,
|
||||
+ "lowFrequency":5925
|
||||
+ },
|
||||
+ "maxPSD":3.98970004336019
|
||||
+ },
|
||||
+ {
|
||||
+ "frequencyRange":{
|
||||
+ "highFrequency":6865,
|
||||
+ "lowFrequency":6525
|
||||
+ },
|
||||
+ "maxPSD":3.98970004336019
|
||||
+ }
|
||||
+ ],
|
||||
+ "requestId":"11235814",
|
||||
+ "response":{
|
||||
+ "responseCode":0,
|
||||
+ "shortDescription":"Success"
|
||||
+ },
|
||||
+ "rulesetId":"US_47_CFR_PART_15_SUBPART_E"
|
||||
+ }
|
||||
+ ],
|
||||
+ "version":"1.1"
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/afc/afcd.c
|
||||
@@ -0,0 +1,292 @@
|
||||
+/*
|
||||
+ * Automated Frequency Coordination Daemon
|
||||
+ * Copyright (c) 2024, Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ *
|
||||
+ * This software may be distributed under the terms of the BSD license.
|
||||
+ * See README for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <curl/curl.h>
|
||||
+#include <sys/un.h>
|
||||
+#include <sys/stat.h>
|
||||
+
|
||||
+#include "utils/includes.h"
|
||||
+#include "utils/common.h"
|
||||
+
|
||||
+#define CURL_TIMEOUT 60
|
||||
+#define AFCD_SOCK "afcd.sock"
|
||||
+
|
||||
+struct curl_ctx {
|
||||
+ char *buf;
|
||||
+ size_t buf_len;
|
||||
+};
|
||||
+
|
||||
+static volatile bool exiting;
|
||||
+
|
||||
+static char *path = "/var/run";
|
||||
+static char *bearer_token;
|
||||
+static char *url;
|
||||
+static int port = 443;
|
||||
+
|
||||
+
|
||||
+static size_t afcd_curl_cb_write(void *ptr, size_t size, size_t nmemb,
|
||||
+ void *userdata)
|
||||
+{
|
||||
+ struct curl_ctx *ctx = userdata;
|
||||
+ char *buf;
|
||||
+
|
||||
+ buf = os_realloc(ctx->buf, ctx->buf_len + size * nmemb + 1);
|
||||
+ if (!buf)
|
||||
+ return 0;
|
||||
+
|
||||
+ ctx->buf = buf;
|
||||
+ os_memcpy(buf + ctx->buf_len, ptr, size * nmemb);
|
||||
+ buf[ctx->buf_len + size * nmemb] = '\0';
|
||||
+ ctx->buf_len += size * nmemb;
|
||||
+
|
||||
+ return size * nmemb;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int afcd_send_request(struct curl_ctx *ctx, unsigned char *request)
|
||||
+{
|
||||
+ struct curl_slist *headers = NULL;
|
||||
+ CURL *curl;
|
||||
+ int ret;
|
||||
+
|
||||
+ wpa_printf(MSG_DEBUG, "Sending AFC request to %s", url);
|
||||
+
|
||||
+ curl_global_init(CURL_GLOBAL_ALL);
|
||||
+ curl = curl_easy_init();
|
||||
+ if (!curl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ headers = curl_slist_append(headers, "Accept: application/json");
|
||||
+ headers = curl_slist_append(headers,
|
||||
+ "Content-Type: application/json");
|
||||
+ headers = curl_slist_append(headers, "charset: utf-8");
|
||||
+
|
||||
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
+ curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
+ curl_easy_setopt(curl, CURLOPT_PORT, port);
|
||||
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
||||
+ afcd_curl_cb_write);
|
||||
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
|
||||
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
|
||||
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
|
||||
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||
+ if (bearer_token)
|
||||
+ curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, bearer_token);
|
||||
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
|
||||
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
|
||||
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
|
||||
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
|
||||
+
|
||||
+ ret = curl_easy_perform(curl);
|
||||
+ if (ret != CURLE_OK)
|
||||
+ wpa_printf(MSG_ERROR, "curl_easy_perform failed: %s",
|
||||
+ curl_easy_strerror(ret));
|
||||
+
|
||||
+ curl_easy_cleanup(curl);
|
||||
+ curl_global_cleanup();
|
||||
+
|
||||
+ return ret == CURLE_OK ? 0 : -EINVAL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void handle_term(int sig)
|
||||
+{
|
||||
+ wpa_printf(MSG_ERROR, "Received signal %d", sig);
|
||||
+ exiting = true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void usage(void)
|
||||
+{
|
||||
+ wpa_printf(MSG_ERROR,
|
||||
+ "%s:\n"
|
||||
+ "afcd -u<url> [-p<port>][-t<token>][-D<unix-sock dir>][-P<PID file>][-dB]",
|
||||
+ __func__);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+#define BUFSIZE 8192
|
||||
+static int afcd_server_run(void)
|
||||
+{
|
||||
+ size_t len = os_strlen(path) + 1 + os_strlen(AFCD_SOCK);
|
||||
+ struct sockaddr_un addr = {
|
||||
+ .sun_family = AF_UNIX,
|
||||
+#ifdef __FreeBSD__
|
||||
+ .sun_len = sizeof(addr),
|
||||
+#endif /* __FreeBSD__ */
|
||||
+ };
|
||||
+ int sockfd, ret = 0;
|
||||
+ char *fname = NULL;
|
||||
+ unsigned char *buf;
|
||||
+ fd_set read_set;
|
||||
+
|
||||
+ if (len >= sizeof(addr.sun_path))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (mkdir(path, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ buf = os_malloc(BUFSIZE);
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ fname = os_malloc(len + 1);
|
||||
+ if (!fname) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto free_buf;
|
||||
+ }
|
||||
+
|
||||
+ os_snprintf(fname, len + 1, "%s/%s", path, AFCD_SOCK);
|
||||
+ fname[len] = '\0';
|
||||
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
|
||||
+
|
||||
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
+ if (sockfd < 0) {
|
||||
+ wpa_printf(MSG_ERROR, "Failed creating socket");
|
||||
+ ret = -errno;
|
||||
+ goto unlink;
|
||||
+ }
|
||||
+
|
||||
+ if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
+ wpa_printf(MSG_ERROR, "Failed to bind socket");
|
||||
+ ret = -errno;
|
||||
+ goto close;
|
||||
+ }
|
||||
+
|
||||
+ if (listen(sockfd, 10) < 0) {
|
||||
+ wpa_printf(MSG_ERROR, "Failed to listen on socket");
|
||||
+ ret = -errno;
|
||||
+ goto close;
|
||||
+ }
|
||||
+
|
||||
+ FD_ZERO(&read_set);
|
||||
+ while (!exiting) {
|
||||
+ socklen_t addr_len = sizeof(addr);
|
||||
+ struct sockaddr_in6 c_addr;
|
||||
+ struct timeval timeout = {
|
||||
+ .tv_sec = 1,
|
||||
+ };
|
||||
+ struct curl_ctx ctx = {};
|
||||
+ int fd;
|
||||
+
|
||||
+ FD_SET(sockfd, &read_set);
|
||||
+ if (select(sockfd + 1, &read_set, NULL, NULL, &timeout) < 0) {
|
||||
+ if (errno != EINTR) {
|
||||
+ wpa_printf(MSG_ERROR,
|
||||
+ "Select failed on socket");
|
||||
+ ret = -errno;
|
||||
+ break;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!FD_ISSET(sockfd, &read_set))
|
||||
+ continue;
|
||||
+
|
||||
+ fd = accept(sockfd, (struct sockaddr *)&c_addr,
|
||||
+ &addr_len);
|
||||
+ if (fd < 0) {
|
||||
+ if (errno != EINTR) {
|
||||
+ wpa_printf(MSG_ERROR,
|
||||
+ "Failed accepting connections");
|
||||
+ ret = -errno;
|
||||
+ break;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ os_memset(buf, 0, BUFSIZE);
|
||||
+ if (recv(fd, buf, BUFSIZE - 1, 0) <= 0) {
|
||||
+ close(fd);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ wpa_printf(MSG_DEBUG, "Received request: %s", buf);
|
||||
+ if (!afcd_send_request(&ctx, buf)) {
|
||||
+ wpa_printf(MSG_DEBUG, "Received reply: %s", ctx.buf);
|
||||
+ send(fd, ctx.buf, ctx.buf_len, MSG_NOSIGNAL);
|
||||
+ free(ctx.buf);
|
||||
+ }
|
||||
+ close(fd);
|
||||
+ }
|
||||
+close:
|
||||
+ close(sockfd);
|
||||
+unlink:
|
||||
+ unlink(fname);
|
||||
+ os_free(fname);
|
||||
+free_buf:
|
||||
+ os_free(buf);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int main(int argc, char **argv)
|
||||
+{
|
||||
+ bool daemonize = false;
|
||||
+ char *pid_file = NULL;
|
||||
+
|
||||
+ if (os_program_init())
|
||||
+ return -1;
|
||||
+
|
||||
+ for (;;) {
|
||||
+ int c = getopt(argc, argv, "u:p:t:D:P:hdB");
|
||||
+
|
||||
+ if (c < 0)
|
||||
+ break;
|
||||
+
|
||||
+ switch (c) {
|
||||
+ case 'h':
|
||||
+ usage();
|
||||
+ return 0;
|
||||
+ case 'B':
|
||||
+ daemonize = true;
|
||||
+ break;
|
||||
+ case 'D':
|
||||
+ path = optarg;
|
||||
+ break;
|
||||
+ case 'P':
|
||||
+ os_free(pid_file);
|
||||
+ pid_file = os_rel2abs_path(optarg);
|
||||
+ break;
|
||||
+ case 'u':
|
||||
+ url = optarg;
|
||||
+ break;
|
||||
+ case 'p':
|
||||
+ port = atoi(optarg);
|
||||
+ break;
|
||||
+ case 'd':
|
||||
+ if (wpa_debug_level > 0)
|
||||
+ wpa_debug_level--;
|
||||
+ break;
|
||||
+ case 't':
|
||||
+ bearer_token = optarg;
|
||||
+ break;
|
||||
+ default:
|
||||
+ usage();
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!url) {
|
||||
+ usage();
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (daemonize && os_daemonize(pid_file)) {
|
||||
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ signal(SIGTERM, handle_term);
|
||||
+ signal(SIGINT, handle_term);
|
||||
+
|
||||
+ return afcd_server_run();
|
||||
+}
|
||||
@@ -0,0 +1,44 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Sat, 16 Mar 2024 12:35:24 +0100
|
||||
Subject: [PATCH] hostapd: export hostapd_is_usable_chans utility routine
|
||||
|
||||
This is a preliminary patch to introduce AFC support.
|
||||
|
||||
Tested-by: Allen Ye <allen.ye@mediatek.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
---
|
||||
|
||||
--- a/src/ap/hw_features.c
|
||||
+++ b/src/ap/hw_features.c
|
||||
@@ -953,7 +953,7 @@ static int hostapd_is_usable_edmg(struct
|
||||
}
|
||||
|
||||
|
||||
-static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
+int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
int secondary_freq;
|
||||
struct hostapd_channel_data *pri_chan;
|
||||
--- a/src/ap/hw_features.h
|
||||
+++ b/src/ap/hw_features.h
|
||||
@@ -28,6 +28,8 @@ int hostapd_prepare_rates(struct hostapd
|
||||
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
|
||||
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode);
|
||||
+int hostapd_is_usable_chans(struct hostapd_iface *iface);
|
||||
+
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline void
|
||||
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
@@ -91,6 +93,11 @@ static inline int hostapd_check_he_6ghz_
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static inline int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
+{
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#endif /* HW_FEATURES_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Wed, 7 Feb 2024 00:08:18 +0100
|
||||
Subject: [PATCH] hostapd: update TPE IE according to AFC
|
||||
|
||||
Update Transmit Power Envelope (TPE) IE according to the reply from AFC
|
||||
coordinator on UNII-5 or UNII-7 6GHz bands.
|
||||
|
||||
Tested-by: Allen Ye <allen.ye@mediatek.com>
|
||||
---
|
||||
|
||||
--- a/src/ap/afc.c
|
||||
+++ b/src/ap/afc.c
|
||||
@@ -977,3 +977,40 @@ void hostap_afc_disable_channels(struct
|
||||
chan->flag |= HOSTAPD_CHAN_DISABLED;
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+int hostap_afc_get_chan_max_eirp_power(struct hostapd_iface *iface, bool psd,
|
||||
+ int *power)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (!he_reg_is_sp(iface->conf->he_6ghz_reg_pwr_type))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!iface->afc.data_valid)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (psd) {
|
||||
+ for (i = 0; i < iface->afc.num_freq_range; i++) {
|
||||
+ struct afc_freq_range_elem *f;
|
||||
+
|
||||
+ f = &iface->afc.freq_range[i];
|
||||
+ if (iface->freq >= f->low_freq &&
|
||||
+ iface->freq <= f->high_freq) {
|
||||
+ *power = 2 * f->max_psd;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (i = 0; i < iface->afc.num_chan_info; i++) {
|
||||
+ struct afc_chan_info_elem *c;
|
||||
+
|
||||
+ c = &iface->afc.chan_info_list[i];
|
||||
+ if (c->chan == iface->conf->channel) {
|
||||
+ *power = 2 * c->power;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
--- a/src/ap/hostapd.h
|
||||
+++ b/src/ap/hostapd.h
|
||||
@@ -666,10 +666,19 @@ struct hostapd_iface {
|
||||
|
||||
/* hostapd.c */
|
||||
#ifdef CONFIG_AFC
|
||||
+int hostap_afc_get_chan_max_eirp_power(struct hostapd_iface *iface, bool psd,
|
||||
+ int *power);
|
||||
int hostapd_afc_handle_request(struct hostapd_iface *iface);
|
||||
void hostapd_afc_stop(struct hostapd_iface *iface);
|
||||
void hostap_afc_disable_channels(struct hostapd_iface *iface);
|
||||
#else
|
||||
+static inline int
|
||||
+hostap_afc_get_chan_max_eirp_power(struct hostapd_iface *iface, bool psd,
|
||||
+ int *power)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
static inline int hostapd_afc_handle_request(struct hostapd_iface *iface)
|
||||
{
|
||||
return 1;
|
||||
--- a/src/ap/ieee802_11.c
|
||||
+++ b/src/ap/ieee802_11.c
|
||||
@@ -6970,6 +6970,8 @@ u8 * hostapd_eid_txpower_envelope(struct
|
||||
* Unit interpretation = Regulatory client EIRP PSD
|
||||
*/
|
||||
if (is_6ghz_op_class(iconf->op_class)) {
|
||||
+ int err, max_eirp_psd;
|
||||
+
|
||||
ap_type = hostapd_get_he_6ghz_reg_pwr_type(iconf);
|
||||
|
||||
tx_pwr_count = DEFAULT_MAX_TX_POWER_COUNT_6G;
|
||||
@@ -6978,14 +6980,20 @@ u8 * hostapd_eid_txpower_envelope(struct
|
||||
/* Indoor access point must include additional
|
||||
* TPE for subordinate device
|
||||
*/
|
||||
+ err = hostap_afc_get_chan_max_eirp_power(iface, true,
|
||||
+ &max_eirp_psd);
|
||||
if (ap_type == AP_TYPE_6GHZ_INDOOR_AP) {
|
||||
tx_pwr_cat = REG_SUBORDINATE_CLIENT;
|
||||
psd = mode->psd_values[NL80211_REG_SUBORDINATE_CLIENT_LPI + ap_type];
|
||||
+ if (err < 0) {
|
||||
#ifdef REG_DOM_SUPPORT_TX_POWER
|
||||
- tx_pwr = psd * 2;
|
||||
+ tx_pwr = psd * 2;
|
||||
#else
|
||||
- tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
||||
+ tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
||||
#endif /* REG_DOM_SUPPORT_TX_POWER */
|
||||
+ } else {
|
||||
+ tx_pwr = max_eirp_psd;
|
||||
+ }
|
||||
eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
|
||||
tx_pwr_cat, tx_pwr);
|
||||
}
|
||||
@@ -6993,11 +7001,15 @@ u8 * hostapd_eid_txpower_envelope(struct
|
||||
/* Default Tx Power envelope for Global Operating class */
|
||||
tx_pwr_cat = REG_DEFAULT_CLIENT;
|
||||
psd = mode->psd_values[NL80211_REG_REGULAR_CLIENT_LPI + ap_type];
|
||||
+ if (err < 0) {
|
||||
#ifdef REG_DOM_SUPPORT_TX_POWER
|
||||
- tx_pwr = psd * 2;
|
||||
+ tx_pwr = psd * 2;
|
||||
#else
|
||||
- tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
||||
+ tx_pwr = (hostapd_get_6g_tx_power(hapd, ap_type, tx_pwr_cat) * 2);
|
||||
#endif /* REG_DOM_SUPPORT_TX_POWER */
|
||||
+ } else {
|
||||
+ tx_pwr = max_eirp_psd;
|
||||
+ }
|
||||
eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn, tx_pwr_cat, tx_pwr);
|
||||
|
||||
return eid;
|
||||
@@ -0,0 +1,23 @@
|
||||
--- a/src/ap/afc.c
|
||||
+++ b/src/ap/afc.c
|
||||
@@ -737,6 +737,20 @@ static int hostapd_afc_send_receive(stru
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifdef UCODE_SUPPORT
|
||||
+ request_obj = hostapd_afc_build_request(iface);
|
||||
+ if (!request_obj)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ request = json_object_to_json_string(request_obj);
|
||||
+ ret = hostapd_ucode_afc_request(iface, request, buf, sizeof(buf));
|
||||
+ json_object_put(request_obj);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return hostapd_afc_parse_reply(iface, buf);
|
||||
+#endif
|
||||
+
|
||||
if (!iconf->afc.socket) {
|
||||
wpa_printf(MSG_ERROR, "Missing AFC socket string");
|
||||
return -EINVAL;
|
||||
@@ -51,7 +51,7 @@ hostapd_ucode_update_bss_list(struct hostapd_iface *iface, uc_value_t *if_bss, u
|
||||
int i;
|
||||
|
||||
list = ucv_array_new(vm);
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
for (i = 0; iface->bss && i < iface->num_bss; i++) {
|
||||
struct hostapd_data *hapd = iface->bss[i];
|
||||
uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
|
||||
|
||||
@@ -764,6 +764,34 @@ void hostapd_ucode_free_iface(struct hostapd_iface *iface)
|
||||
wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
|
||||
}
|
||||
|
||||
int hostapd_ucode_afc_request(struct hostapd_iface *iface, const char *request,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
uc_value_t *val;
|
||||
size_t ret_len;
|
||||
int ret = -1;
|
||||
|
||||
if (wpa_ucode_call_prepare("afc_request"))
|
||||
return -1;
|
||||
|
||||
uc_value_push(ucv_get(ucv_string_new(iface->phy)));
|
||||
uc_value_push(ucv_get(ucv_string_new(request)));
|
||||
val = wpa_ucode_call(2);
|
||||
if (ucv_type(val) != UC_STRING)
|
||||
goto out;
|
||||
|
||||
ret_len = ucv_string_length(val);
|
||||
if (ret_len >= len)
|
||||
goto out;
|
||||
|
||||
memcpy(buf, ucv_string_get(val), ret_len + 1);
|
||||
ret = (int)ret_len;
|
||||
|
||||
out:
|
||||
ucv_put(val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hostapd_ucode_add_bss(struct hostapd_data *hapd)
|
||||
{
|
||||
uc_value_t *val;
|
||||
|
||||
@@ -26,6 +26,8 @@ void hostapd_ucode_free_iface(struct hostapd_iface *iface);
|
||||
void hostapd_ucode_add_bss(struct hostapd_data *hapd);
|
||||
void hostapd_ucode_free_bss(struct hostapd_data *hapd);
|
||||
void hostapd_ucode_reload_bss(struct hostapd_data *hapd);
|
||||
int hostapd_ucode_afc_request(struct hostapd_iface *iface, const char *request,
|
||||
char *buf, size_t len);
|
||||
|
||||
#else
|
||||
|
||||
|
||||
Reference in New Issue
Block a user