diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 44e8f39eb9f..1d6eac68e78 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -12,6 +12,8 @@ #ifndef ZEPHYR_INCLUDE_NET_WIFI_H_ #define ZEPHYR_INCLUDE_NET_WIFI_H_ +#define WIFI_COUNTRY_CODE_LEN 2 + /* Not having support for legacy types is deliberate to enforce * higher security. */ diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 924f4630d30..f916b497ed8 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -40,6 +40,7 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_PS_MODE, NET_REQUEST_WIFI_CMD_TWT, NET_REQUEST_WIFI_CMD_PS_CONFIG, + NET_REQUEST_WIFI_CMD_REG_DOMAIN, }; #define NET_REQUEST_WIFI_SCAN \ @@ -91,6 +92,10 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_TWT); (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_PS_CONFIG) NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG); +#define NET_REQUEST_WIFI_REG_DOMAIN \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_REG_DOMAIN) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN); enum net_event_wifi_cmd { NET_EVENT_WIFI_CMD_SCAN_RESULT = 1, @@ -231,6 +236,19 @@ struct wifi_ps_config { char num_twt_flows; }; +/* Generic get/set operation for any command*/ +enum wifi_mgmt_op { + WIFI_MGMT_GET = 0, + WIFI_MGMT_SET = 1, +}; + +struct wifi_reg_domain { + enum wifi_mgmt_op oper; + /* Ignore all other regulatory hints */ + bool force; + uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; +}; + #include typedef void (*scan_result_cb_t)(struct net_if *iface, int status, @@ -268,6 +286,7 @@ struct net_wifi_mgmt_offload { int (*set_power_save_mode)(const struct device *dev, struct wifi_ps_mode_params *params); int (*set_twt)(const struct device *dev, struct wifi_twt_params *params); int (*get_power_save_config)(const struct device *dev, struct wifi_ps_config *config); + int (*reg_domain)(const struct device *dev, struct wifi_reg_domain *reg_domain); }; /* Make sure that the network interface API is properly setup inside diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index dceafc81dec..20ca63d9d5f 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -293,3 +293,24 @@ void wifi_mgmt_raise_twt_event(struct net_if *iface, struct wifi_twt_params *twt iface, twt_params, sizeof(struct wifi_twt_params)); } + +static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + struct net_wifi_mgmt_offload *off_api = + (struct net_wifi_mgmt_offload *) dev->api; + struct wifi_reg_domain *reg_domain = data; + + if (off_api == NULL || off_api->reg_domain == NULL) { + return -ENOTSUP; + } + + if (!data || len != sizeof(*reg_domain)) { + return -EINVAL; + } + + return off_api->reg_domain(dev, reg_domain); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN, wifi_reg_domain); diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 3e6a61529b6..7ee271a6d96 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -735,6 +735,67 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, return 0; } + +static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, + char *argv[]) +{ + struct net_if *iface = net_if_get_default(); + struct wifi_reg_domain regd = {0}; + int ret; + + if (argc == 1) { + regd.oper = WIFI_MGMT_GET; + } else if (argc >= 2 && argc <= 3) { + regd.oper = WIFI_MGMT_SET; + if (strlen(argv[1]) != 2) { + shell_fprintf(sh, SHELL_WARNING, + "Invalid reg domain: Length should be two letters/digits\n"); + return -ENOEXEC; + } + + /* Two letter country code with special case of 00 for WORLD */ + if (((argv[1][0] < 'A' || argv[1][0] > 'Z') || + (argv[1][1] < 'A' || argv[1][1] > 'Z')) && + (argv[1][0] != '0' || argv[1][1] != '0')) { + shell_fprintf(sh, SHELL_WARNING, "Invalid reg domain %c%c\n", argv[1][0], + argv[1][1]); + return -ENOEXEC; + } + regd.country_code[0] = argv[1][0]; + regd.country_code[1] = argv[1][1]; + + if (argc == 3) { + if (strncmp(argv[2], "-f", 2) == 0) { + regd.force = true; + } else { + shell_fprintf(sh, SHELL_WARNING, "Invalid option %s\n", argv[2]); + return -ENOEXEC; + } + } + } else { + shell_help(sh); + return -ENOEXEC; + } + + ret = net_mgmt(NET_REQUEST_WIFI_REG_DOMAIN, iface, + ®d, sizeof(regd)); + if (ret) { + shell_fprintf(sh, SHELL_WARNING, "Cannot %s Regulatory domain: %d\n", + regd.oper == WIFI_MGMT_GET ? "get" : "set", ret); + return -ENOEXEC; + } + + if (regd.oper == WIFI_MGMT_GET) { + shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain is: %c%c\n", + regd.country_code[0], regd.country_code[1]); + } else { + shell_fprintf(sh, SHELL_NORMAL, "Wi-Fi Regulatory domain set to: %c%c\n", + regd.country_code[0], regd.country_code[1]); + } + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_CMD(disable, NULL, "Disable Access Point mode", @@ -785,6 +846,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats), SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status), SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), + SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL), + SHELL_CMD(reg_domain, NULL, + "Set or Get Wi-Fi regulatory domain\n" + "Usage: wifi reg_domain [ISO/IEC 3166-1 alpha2] [-f]\n" + "-f: Force to use this regulatory hint over any other regulatory hints\n" + "Note: This may cause regulatory compliance issues, use it at your own risk.", + cmd_wifi_reg_domain), SHELL_SUBCMD_SET_END );