Skip to content

Commit fadb1fd

Browse files
Krishna Tfabiobaltieri
authored andcommitted
net: wifi: Add support for regulatory domain configuration
Wi-Fi bands are regulated by a governing body depending on operating country, add support for the user to provide a country of operation as a hint to the Wi-Fi chipset. Ideally if the chipset supports this is all handled internally, in that case "get" is useful but for testing and other usecases add a "set" as well, similar to "iw reg set" or "country_code=" configuration in hostapd/wpa_supplicant in Linux world. This add a new offload API operation "reg_domain" that can be used to either get or set the regulatory information. The validation is left to the underlying chipset, shell only does basic validation, (XY/00). This is just a regulatory hint to the chipset, there could be other regulatory hints e.g., beacon that can override this configuration, so, an additional option to force this setting despite other hints is also given for testing purposes. FYI, the standard database used is [1]. [1] - https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git/tree/db.txt Signed-off-by: Krishna T <[email protected]>
1 parent 324a455 commit fadb1fd

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

include/zephyr/net/wifi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#ifndef ZEPHYR_INCLUDE_NET_WIFI_H_
1313
#define ZEPHYR_INCLUDE_NET_WIFI_H_
1414

15+
#define WIFI_COUNTRY_CODE_LEN 2
16+
1517
/* Not having support for legacy types is deliberate to enforce
1618
* higher security.
1719
*/

include/zephyr/net/wifi_mgmt.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ enum net_request_wifi_cmd {
4040
NET_REQUEST_WIFI_CMD_PS_MODE,
4141
NET_REQUEST_WIFI_CMD_TWT,
4242
NET_REQUEST_WIFI_CMD_PS_CONFIG,
43+
NET_REQUEST_WIFI_CMD_REG_DOMAIN,
4344
};
4445

4546
#define NET_REQUEST_WIFI_SCAN \
@@ -91,6 +92,10 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_TWT);
9192
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS_CONFIG)
9293

9394
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG);
95+
#define NET_REQUEST_WIFI_REG_DOMAIN \
96+
(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_REG_DOMAIN)
97+
98+
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN);
9499

95100
enum net_event_wifi_cmd {
96101
NET_EVENT_WIFI_CMD_SCAN_RESULT = 1,
@@ -231,6 +236,19 @@ struct wifi_ps_config {
231236
char num_twt_flows;
232237
};
233238

239+
/* Generic get/set operation for any command*/
240+
enum wifi_mgmt_op {
241+
WIFI_MGMT_GET = 0,
242+
WIFI_MGMT_SET = 1,
243+
};
244+
245+
struct wifi_reg_domain {
246+
enum wifi_mgmt_op oper;
247+
/* Ignore all other regulatory hints */
248+
bool force;
249+
uint8_t country_code[WIFI_COUNTRY_CODE_LEN];
250+
};
251+
234252
#include <zephyr/net/net_if.h>
235253

236254
typedef void (*scan_result_cb_t)(struct net_if *iface, int status,
@@ -268,6 +286,7 @@ struct net_wifi_mgmt_offload {
268286
int (*set_power_save_mode)(const struct device *dev, struct wifi_ps_mode_params *params);
269287
int (*set_twt)(const struct device *dev, struct wifi_twt_params *params);
270288
int (*get_power_save_config)(const struct device *dev, struct wifi_ps_config *config);
289+
int (*reg_domain)(const struct device *dev, struct wifi_reg_domain *reg_domain);
271290
};
272291

273292
/* Make sure that the network interface API is properly setup inside

subsys/net/l2/wifi/wifi_mgmt.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,24 @@ void wifi_mgmt_raise_twt_event(struct net_if *iface, struct wifi_twt_params *twt
293293
iface, twt_params,
294294
sizeof(struct wifi_twt_params));
295295
}
296+
297+
static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface,
298+
void *data, size_t len)
299+
{
300+
const struct device *dev = net_if_get_device(iface);
301+
struct net_wifi_mgmt_offload *off_api =
302+
(struct net_wifi_mgmt_offload *) dev->api;
303+
struct wifi_reg_domain *reg_domain = data;
304+
305+
if (off_api == NULL || off_api->reg_domain == NULL) {
306+
return -ENOTSUP;
307+
}
308+
309+
if (!data || len != sizeof(*reg_domain)) {
310+
return -EINVAL;
311+
}
312+
313+
return off_api->reg_domain(dev, reg_domain);
314+
}
315+
316+
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN, wifi_reg_domain);

subsys/net/l2/wifi/wifi_shell.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,67 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc,
735735
return 0;
736736
}
737737

738+
739+
static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc,
740+
char *argv[])
741+
{
742+
struct net_if *iface = net_if_get_default();
743+
struct wifi_reg_domain regd = {0};
744+
int ret;
745+
746+
if (argc == 1) {
747+
regd.oper = WIFI_MGMT_GET;
748+
} else if (argc >= 2 && argc <= 3) {
749+
regd.oper = WIFI_MGMT_SET;
750+
if (strlen(argv[1]) != 2) {
751+
shell_fprintf(sh, SHELL_WARNING,
752+
"Invalid reg domain: Length should be two letters/digits\n");
753+
return -ENOEXEC;
754+
}
755+
756+
/* Two letter country code with special case of 00 for WORLD */
757+
if (((argv[1][0] < 'A' || argv[1][0] > 'Z') ||
758+
(argv[1][1] < 'A' || argv[1][1] > 'Z')) &&
759+
(argv[1][0] != '0' || argv[1][1] != '0')) {
760+
shell_fprintf(sh, SHELL_WARNING, "Invalid reg domain %c%c\n", argv[1][0],
761+
argv[1][1]);
762+
return -ENOEXEC;
763+
}
764+
regd.country_code[0] = argv[1][0];
765+
regd.country_code[1] = argv[1][1];
766+
767+
if (argc == 3) {
768+
if (strncmp(argv[2], "-f", 2) == 0) {
769+
regd.force = true;
770+
} else {
771+
shell_fprintf(sh, SHELL_WARNING, "Invalid option %s\n", argv[2]);
772+
return -ENOEXEC;
773+
}
774+
}
775+
} else {
776+
shell_help(sh);
777+
return -ENOEXEC;
778+
}
779+
780+
ret = net_mgmt(NET_REQUEST_WIFI_REG_DOMAIN, iface,
781+
&regd, sizeof(regd));
782+
if (ret) {
783+
shell_fprintf(sh, SHELL_WARNING, "Cannot %s Regulatory domain: %d\n",
784+
regd.oper == WIFI_MGMT_GET ? "get" : "set", ret);
785+
return -ENOEXEC;
786+
}
787+
788+
if (regd.oper == WIFI_MGMT_GET) {
789+
shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain is: %c%c\n",
790+
regd.country_code[0], regd.country_code[1]);
791+
} else {
792+
shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain set to: %c%c\n",
793+
regd.country_code[0], regd.country_code[1]);
794+
}
795+
796+
return 0;
797+
}
798+
738799
SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap,
739800
SHELL_CMD(disable, NULL,
740801
"Disable Access Point mode",
@@ -785,6 +846,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands,
785846
SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats),
786847
SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status),
787848
SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL),
849+
SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL),
850+
SHELL_CMD(reg_domain, NULL,
851+
"Set or Get Wi-Fi regulatory domain\n"
852+
"Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n"
853+
"-f: Force to use this regulatory hint over any other regulatory hints\n"
854+
"Note: This may cause regulatory compliance issues, use it at your own risk.",
855+
cmd_wifi_reg_domain),
788856
SHELL_SUBCMD_SET_END
789857
);
790858

0 commit comments

Comments
 (0)