diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 3c385994b3b5f..48dde6cb30df3 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Intel Corporation. + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,6 +92,8 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_RTS_THRESHOLD, /** Configure AP parameter */ NET_REQUEST_WIFI_CMD_AP_CONFIG_PARAM, + /** DPP actions */ + NET_REQUEST_WIFI_CMD_DPP, /** @cond INTERNAL_HIDDEN */ NET_REQUEST_WIFI_CMD_MAX /** @endcond */ @@ -198,6 +201,12 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_RTS_THRESHOLD); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_CONFIG_PARAM); +/** Request a Wi-Fi DPP operation */ +#define NET_REQUEST_WIFI_DPP \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_DPP) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_DPP); + /** @brief Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -768,6 +777,178 @@ struct wifi_ap_config_params { uint32_t max_num_sta; }; +/** @brief Wi-Fi DPP configuration parameter */ +/** Wi-Fi DPP QR-CODE in string max len for SHA512 */ +#define WIFI_DPP_QRCODE_MAX_LEN 255 + +/** Wi-Fi DPP operations */ +enum wifi_dpp_op { + /** Unset invalid operation */ + WIFI_DPP_OP_INVALID = 0, + /** Add configurator */ + WIFI_DPP_CONFIGURATOR_ADD, + /** Start DPP auth as configurator or enrollee */ + WIFI_DPP_AUTH_INIT, + /** Scan qr_code as parameter */ + WIFI_DPP_QR_CODE, + /** Start DPP chirp to send DPP announcement */ + WIFI_DPP_CHIRP, + /** Listen on specific frequency */ + WIFI_DPP_LISTEN, + /** Generate a bootstrap like qrcode */ + WIFI_DPP_BOOTSTRAP_GEN, + /** Get a bootstrap uri for external device to scan */ + WIFI_DPP_BOOTSTRAP_GET_URI, + /** Set configurator parameters */ + WIFI_DPP_SET_CONF_PARAM, + /** Set DPP rx response wait timeout */ + WIFI_DPP_SET_WAIT_RESP_TIME +}; + +/** Wi-Fi DPP crypto Elliptic Curves */ +enum wifi_dpp_curves { + /** Unset default use P-256 */ + WIFI_DPP_CURVES_DEFAULT = 0, + /** prime256v1 */ + WIFI_DPP_CURVES_P_256, + /** secp384r1 */ + WIFI_DPP_CURVES_P_384, + /** secp521r1 */ + WIFI_DPP_CURVES_P_512, + /** brainpoolP256r1 */ + WIFI_DPP_CURVES_BP_256, + /** brainpoolP384r1 */ + WIFI_DPP_CURVES_BP_384, + /** brainpoolP512r1 */ + WIFI_DPP_CURVES_BP_512 +}; + +/** Wi-Fi DPP role */ +enum wifi_dpp_role { + /** Unset role */ + WIFI_DPP_ROLE_UNSET = 0, + /** Configurator passes AP config to enrollee */ + WIFI_DPP_ROLE_CONFIGURATOR, + /** Enrollee gets AP config and connect to AP */ + WIFI_DPP_ROLE_ENROLLEE, + /** Both configurator and enrollee might be chosen */ + WIFI_DPP_ROLE_EITHER +}; + +/** Wi-Fi DPP security type + * + * current only support DPP only AKM + */ +enum wifi_dpp_conf { + /** Unset conf */ + WIFI_DPP_CONF_UNSET = 0, + /** conf=sta-dpp, AKM DPP only for sta */ + WIFI_DPP_CONF_STA, + /** conf=ap-dpp, AKM DPP only for ap */ + WIFI_DPP_CONF_AP, + /** conf=query, query for AKM */ + WIFI_DPP_CONF_QUERY +}; + +/** Wi-Fi DPP bootstrap type + * + * current default and only support QR-CODE + */ +enum wifi_dpp_bootstrap_type { + /** Unset type */ + WIFI_DPP_BOOTSTRAP_TYPE_UNSET = 0, + /** qrcode */ + WIFI_DPP_BOOTSTRAP_TYPE_QRCODE, + /** pkex */ + WIFI_DPP_BOOTSTRAP_TYPE_PKEX, + /** nfc */ + WIFI_DPP_BOOTSTRAP_TYPE_NFC_URI +}; + +/** Wi-Fi DPP params for various operations + */ +struct wifi_dpp_params { + /** Operation enum */ + int action; + union { + /** Params to add DPP configurator */ + struct wifi_dpp_configurator_add_params { + /** ECP curves for private key */ + int curve; + /** ECP curves for net access key */ + int net_access_key_curve; + } configurator_add; + /** Params to initiate a DPP auth procedure */ + struct wifi_dpp_auth_init_params { + /** Peer bootstrap id */ + int peer; + /** Configuration parameter id */ + int configurator; + /** Role configurator or enrollee */ + int role; + /** Security type */ + int conf; + /** SSID in string */ + char ssid[WIFI_SSID_MAX_LEN + 1]; + } auth_init; + /** Params to do DPP chirp */ + struct wifi_dpp_chirp_params { + /** Own bootstrap id */ + int id; + /** Chirp on frequency */ + int freq; + } chirp; + /** Params to do DPP listen */ + struct wifi_dpp_listen_params { + /** Listen on frequency */ + int freq; + /** Role configurator or enrollee */ + int role; + } listen; + /** Params to generate a DPP bootstrap */ + struct wifi_dpp_bootstrap_gen_params { + /** Bootstrap type */ + int type; + /** Own operating class */ + int op_class; + /** Own working channel */ + int chan; + /** ECP curves */ + int curve; + /** Own mac address */ + uint8_t mac[WIFI_MAC_ADDR_LEN]; + } bootstrap_gen; + /** Params to set specific DPP configurator */ + struct wifi_dpp_configurator_set_params { + /** Peer bootstrap id */ + int peer; + /** Configuration parameter id */ + int configurator; + /** Role configurator or enrollee */ + int role; + /** Security type */ + int conf; + /** ECP curves for private key */ + int curve; + /** ECP curves for net access key */ + int net_access_key_curve; + /** Own mac address */ + char ssid[WIFI_SSID_MAX_LEN + 1]; + } configurator_set; + /** Bootstrap get uri id */ + int id; + /** Timeout for DPP frame response rx */ + int dpp_resp_wait_time; + /** DPP QR-CODE, max for SHA512 */ + uint8_t dpp_qr_code[WIFI_DPP_QRCODE_MAX_LEN + 1]; + /** Request response reusing request buffer. + * So once a request is sent, buffer will be + * fulfilled by response + */ + char resp[WIFI_DPP_QRCODE_MAX_LEN + 1]; + }; +}; + #include /** Scan result callback @@ -949,6 +1130,14 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*ap_config_params)(const struct device *dev, struct wifi_ap_config_params *params); + /** Dispatch DPP operations by action enum, with or without arguments in string format + * + * @param dev Pointer to the device structure for the driver instance + * @param params DPP action enum and parameters in string + * + * @return 0 if ok, < 0 if error + */ + int (*dpp_dispatch)(const struct device *dev, struct wifi_dpp_params *params); }; /** Wi-Fi management offload API */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index e43e69a4f59aa..f90c938b76667 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -1,5 +1,6 @@ /** * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -1012,3 +1013,269 @@ int supplicant_ap_sta_disconnect(const struct device *dev, return ret; } #endif /* CONFIG_AP */ + +static const char *dpp_params_to_args_curve(int curve) +{ + switch (curve) { + case WIFI_DPP_CURVES_P_256: + return "P-256"; + case WIFI_DPP_CURVES_P_384: + return "P-384"; + case WIFI_DPP_CURVES_P_512: + return "P-521"; + case WIFI_DPP_CURVES_BP_256: + return "BP-256"; + case WIFI_DPP_CURVES_BP_384: + return "BP-384"; + case WIFI_DPP_CURVES_BP_512: + return "BP-512"; + default: + return "P-256"; + } +} + +static const char *dpp_params_to_args_conf(int conf) +{ + switch (conf) { + case WIFI_DPP_CONF_STA: + return "sta-dpp"; + case WIFI_DPP_CONF_AP: + return "ap-dpp"; + case WIFI_DPP_CONF_QUERY: + return "query"; + default: + return "sta-dpp"; + } +} + +static const char *dpp_params_to_args_role(int role) +{ + switch (role) { + case WIFI_DPP_ROLE_CONFIGURATOR: + return "configurator"; + case WIFI_DPP_ROLE_ENROLLEE: + return "enrollee"; + case WIFI_DPP_ROLE_EITHER: + return "either"; + default: + return "either"; + } +} + +static void dpp_ssid_bin2str(char *dst, uint8_t *src, int max_len) +{ + uint8_t *end = src + strlen(src); + + /* do 4 bytes convert first */ + for (; (src + 4) < end; src += 4) { + snprintf(dst, max_len, "%02x%02x%02x%02x", + src[0], src[1], src[2], src[3]); + dst += 8; + } + + /* then do 1 byte convert */ + for (; src < end; src++) { + snprintf(dst, max_len, "%02x", src[0]); + dst += 2; + } +} + +#define SUPPLICANT_DPP_CMD_BUF_SIZE 384 +#define STR_CUR_TO_END(cur) (cur) = (&(cur)[0] + strlen((cur))) + +int supplicant_dpp_dispatch(const struct device *dev, + struct wifi_dpp_params *params) +{ + char *pos; + static char dpp_cmd_buf[SUPPLICANT_DPP_CMD_BUF_SIZE] = {0}; + char *end = &dpp_cmd_buf[SUPPLICANT_DPP_CMD_BUF_SIZE - 2]; + + memset(dpp_cmd_buf, 0x0, SUPPLICANT_DPP_CMD_BUF_SIZE); + + pos = &dpp_cmd_buf[0]; + + switch (params->action) { + case WIFI_DPP_CONFIGURATOR_ADD: + strncpy(pos, "DPP_CONFIGURATOR_ADD", end - pos); + STR_CUR_TO_END(pos); + + if (params->configurator_add.curve) { + snprintf(pos, end - pos, " curve=%s", + dpp_params_to_args_curve(params->configurator_add.curve)); + STR_CUR_TO_END(pos); + } + + if (params->configurator_add.net_access_key_curve) { + snprintf(pos, end - pos, " net_access_key_curve=%s", + dpp_params_to_args_curve( + params->configurator_add.net_access_key_curve)); + } + break; + case WIFI_DPP_AUTH_INIT: + strncpy(pos, "DPP_AUTH_INIT", end - pos); + STR_CUR_TO_END(pos); + + if (params->auth_init.peer) { + snprintf(pos, end - pos, " peer=%d", params->auth_init.peer); + STR_CUR_TO_END(pos); + } + + if (params->auth_init.conf) { + snprintf(pos, end - pos, " conf=%s", + dpp_params_to_args_conf( + params->auth_init.conf)); + STR_CUR_TO_END(pos); + } + + if (params->auth_init.ssid[0]) { + strncpy(pos, " ssid=", end - pos); + STR_CUR_TO_END(pos); + dpp_ssid_bin2str(pos, params->auth_init.ssid, + WIFI_SSID_MAX_LEN * 2); + STR_CUR_TO_END(pos); + } + + if (params->auth_init.configurator) { + snprintf(pos, end - pos, " configurator=%d", + params->auth_init.configurator); + STR_CUR_TO_END(pos); + } + + if (params->auth_init.role) { + snprintf(pos, end - pos, " role=%s", + dpp_params_to_args_role( + params->auth_init.role)); + } + break; + case WIFI_DPP_QR_CODE: + strncpy(pos, "DPP_QR_CODE", end - pos); + STR_CUR_TO_END(pos); + + if (params->dpp_qr_code[0]) { + snprintf(pos, end - pos, " %s", params->dpp_qr_code); + } + break; + case WIFI_DPP_CHIRP: + strncpy(pos, "DPP_CHIRP", end - pos); + STR_CUR_TO_END(pos); + + if (params->chirp.id) { + snprintf(pos, end - pos, " own=%d", params->chirp.id); + STR_CUR_TO_END(pos); + } + + if (params->chirp.freq) { + snprintf(pos, end - pos, " listen=%d", params->chirp.freq); + } + break; + case WIFI_DPP_LISTEN: + strncpy(pos, "DPP_LISTEN", end - pos); + STR_CUR_TO_END(pos); + + if (params->listen.freq) { + snprintf(pos, end - pos, " %d", params->listen.freq); + STR_CUR_TO_END(pos); + } + + if (params->listen.role) { + snprintf(pos, end - pos, " role=%s", + dpp_params_to_args_role( + params->listen.role)); + } + break; + case WIFI_DPP_BOOTSTRAP_GEN: + strncpy(pos, "DPP_BOOTSTRAP_GEN", end - pos); + STR_CUR_TO_END(pos); + + if (params->bootstrap_gen.type) { + strncpy(pos, " type=qrcode", end - pos); + STR_CUR_TO_END(pos); + } + + if (params->bootstrap_gen.op_class && + params->bootstrap_gen.chan) { + snprintf(pos, end - pos, " chan=%d/%d", + params->bootstrap_gen.op_class, + params->bootstrap_gen.chan); + STR_CUR_TO_END(pos); + } + + /* mac is mandatory, even if it is zero mac address */ + snprintf(pos, end - pos, " mac=%02x:%02x:%02x:%02x:%02x:%02x", + params->bootstrap_gen.mac[0], params->bootstrap_gen.mac[1], + params->bootstrap_gen.mac[2], params->bootstrap_gen.mac[3], + params->bootstrap_gen.mac[4], params->bootstrap_gen.mac[5]); + STR_CUR_TO_END(pos); + + if (params->bootstrap_gen.curve) { + snprintf(pos, end - pos, " curve=%s", + dpp_params_to_args_curve(params->bootstrap_gen.curve)); + } + break; + case WIFI_DPP_BOOTSTRAP_GET_URI: + snprintf(pos, end - pos, "DPP_BOOTSTRAP_GET_URI %d", params->id); + break; + case WIFI_DPP_SET_CONF_PARAM: + strncpy(pos, "SET dpp_configurator_params", end - pos); + STR_CUR_TO_END(pos); + + if (params->configurator_set.peer) { + snprintf(pos, end - pos, " peer=%d", params->configurator_set.peer); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.conf) { + snprintf(pos, end - pos, " conf=%s", + dpp_params_to_args_conf( + params->configurator_set.conf)); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.ssid[0]) { + strncpy(pos, " ssid=", end - pos); + STR_CUR_TO_END(pos); + dpp_ssid_bin2str(pos, params->configurator_set.ssid, + WIFI_SSID_MAX_LEN * 2); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.configurator) { + snprintf(pos, end - pos, " configurator=%d", + params->configurator_set.configurator); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.role) { + snprintf(pos, end - pos, " role=%s", + dpp_params_to_args_role( + params->configurator_set.role)); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.curve) { + snprintf(pos, end - pos, " curve=%s", + dpp_params_to_args_curve(params->configurator_set.curve)); + STR_CUR_TO_END(pos); + } + + if (params->configurator_set.net_access_key_curve) { + snprintf(pos, end - pos, " net_access_key_curve=%s", + dpp_params_to_args_curve( + params->configurator_set.net_access_key_curve)); + } + break; + case WIFI_DPP_SET_WAIT_RESP_TIME: + snprintf(pos, end - pos, "SET dpp_resp_wait_time %d", + params->dpp_resp_wait_time); + break; + default: + wpa_printf(MSG_ERROR, "Unknown DPP action"); + return -1; + } + + wpa_printf(MSG_DEBUG, "%s", dpp_cmd_buf); + if (zephyr_wpa_cli_cmd_resp(dpp_cmd_buf, params->resp)) { + return -1; + } + return 0; +} diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index e4f92e0b96992..8c95bb02f16b5 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -165,4 +166,14 @@ int supplicant_ap_sta_disconnect(const struct device *dev, const uint8_t *mac_addr); #endif /* CONFIG_AP */ + +/** + * @brief Dispatch DPP operations + * + * @param dev Wi-Fi interface name to use + * @param dpp_params DPP action enum and params in string + * @return 0 for OK; -1 for ERROR + */ +int supplicant_dpp_dispatch(const struct device *dev, + struct wifi_dpp_params *params); #endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index 64383eb24f977..5a655033fcdbb 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Nordic Semiconductor ASA. + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,6 +65,7 @@ static const struct wifi_mgmt_ops mgmt_ops = { .ap_disable = supplicant_ap_disable, .ap_sta_disconnect = supplicant_ap_sta_disconnect, #endif /* CONFIG_AP */ + .dpp_dispatch = supplicant_dpp_dispatch, }; DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops); diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index c329db7f8f3a4..18e38d35275e9 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016 Intel Corporation. + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -774,6 +775,22 @@ static int wifi_set_rts_threshold(uint32_t mgmt_request, struct net_if *iface, NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_RTS_THRESHOLD, wifi_set_rts_threshold); +static int wifi_dpp(uint32_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + struct wifi_dpp_params *params = data; + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->dpp_dispatch == NULL) { + return -ENOTSUP; + } + + return wifi_mgmt_api->dpp_dispatch(dev, params); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_DPP, wifi_dpp); + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_result) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 82b958c263840..139e919f46cfe 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -1934,6 +1935,408 @@ static int cmd_wifi_version(const struct shell *sh, size_t argc, char *argv[]) return 0; } +static int parse_dpp_args_auth_init(const struct shell *sh, size_t argc, char *argv[], + struct wifi_dpp_params *params) +{ + int opt; + int opt_index = 0; + struct getopt_state *state; + static struct option long_options[] = {{"peer", required_argument, 0, 'p'}, + {"role", required_argument, 0, 'r'}, + {"configurator", required_argument, 0, 'c'}, + {"mode", required_argument, 0, 'm'}, + {"ssid", required_argument, 0, 's'}, + {0, 0, 0, 0}}; + int ret = 0; + + while ((opt = getopt_long(argc, argv, "p:r:c:m:s:", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'p': + params->auth_init.peer = shell_strtol(optarg, 10, &ret); + break; + case 'r': + params->auth_init.role = shell_strtol(optarg, 10, &ret); + break; + case 'c': + params->auth_init.configurator = shell_strtol(optarg, 10, &ret); + break; + case 'm': + params->auth_init.conf = shell_strtol(optarg, 10, &ret); + break; + case 's': + strncpy(params->auth_init.ssid, optarg, WIFI_SSID_MAX_LEN); + break; + default: + PR_ERROR("Invalid option %c\n", optopt); + return -EINVAL; + } + + if (ret) { + PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret); + return -EINVAL; + } + } + + return 0; +} + +static int parse_dpp_args_chirp(const struct shell *sh, size_t argc, char *argv[], + struct wifi_dpp_params *params) +{ + int opt; + int opt_index = 0; + struct getopt_state *state; + static struct option long_options[] = {{"own", required_argument, 0, 'i'}, + {"freq", required_argument, 0, 'f'}, + {0, 0, 0, 0}}; + int ret = 0; + + while ((opt = getopt_long(argc, argv, "i:f:", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'i': + params->chirp.id = shell_strtol(optarg, 10, &ret); + break; + case 'f': + params->chirp.freq = shell_strtol(optarg, 10, &ret); + break; + default: + PR_ERROR("Invalid option %c\n", optopt); + return -EINVAL; + } + + if (ret) { + PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret); + return -EINVAL; + } + } + + return 0; +} + +static int parse_dpp_args_listen(const struct shell *sh, size_t argc, char *argv[], + struct wifi_dpp_params *params) +{ + int opt; + int opt_index = 0; + struct getopt_state *state; + static struct option long_options[] = {{"role", required_argument, 0, 'r'}, + {"freq", required_argument, 0, 'f'}, + {0, 0, 0, 0}}; + int ret = 0; + + while ((opt = getopt_long(argc, argv, "r:f:", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'r': + params->listen.role = shell_strtol(optarg, 10, &ret); + break; + case 'f': + params->listen.freq = shell_strtol(optarg, 10, &ret); + break; + default: + PR_ERROR("Invalid option %c\n", optopt); + return -EINVAL; + } + + if (ret) { + PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret); + return -EINVAL; + } + } + + return 0; +} + +static int parse_dpp_args_btstrap_gen(const struct shell *sh, size_t argc, char *argv[], + struct wifi_dpp_params *params) +{ + int opt; + int opt_index = 0; + struct getopt_state *state; + static struct option long_options[] = {{"type", required_argument, 0, 't'}, + {"opclass", required_argument, 0, 'o'}, + {"channel", required_argument, 0, 'h'}, + {"mac", required_argument, 0, 'a'}, + {0, 0, 0, 0}}; + int ret = 0; + + while ((opt = getopt_long(argc, argv, "t:o:h:a:", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 't': + params->bootstrap_gen.type = shell_strtol(optarg, 10, &ret); + break; + case 'o': + params->bootstrap_gen.op_class = shell_strtol(optarg, 10, &ret); + break; + case 'h': + params->bootstrap_gen.chan = shell_strtol(optarg, 10, &ret); + break; + case 'a': + ret = net_bytes_from_str(params->bootstrap_gen.mac, + WIFI_MAC_ADDR_LEN, optarg); + break; + default: + PR_ERROR("Invalid option %c\n", optopt); + return -EINVAL; + } + + if (ret) { + PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret); + return -EINVAL; + } + } + + /* DPP bootstrap type currently only support qr_code */ + if (params->bootstrap_gen.type == 0) { + params->bootstrap_gen.type = WIFI_DPP_BOOTSTRAP_TYPE_QRCODE; + } + + if (params->bootstrap_gen.type != WIFI_DPP_BOOTSTRAP_TYPE_QRCODE) { + PR_ERROR("DPP bootstrap type currently only support qr_code\n"); + return -ENOTSUP; + } + + /* operating class should be set alongside with channel */ + if ((params->bootstrap_gen.op_class && !params->bootstrap_gen.chan) || + (!params->bootstrap_gen.op_class && params->bootstrap_gen.chan)) { + PR_ERROR("Operating class should be set alongside with channel\n"); + return -EINVAL; + } + + return 0; +} + +static int parse_dpp_args_set_config_param(const struct shell *sh, size_t argc, char *argv[], + struct wifi_dpp_params *params) +{ + int opt; + int opt_index = 0; + struct getopt_state *state; + static struct option long_options[] = {{"configurator", required_argument, 0, 'c'}, + {"mode", required_argument, 0, 'm'}, + {"ssid", required_argument, 0, 's'}, + {0, 0, 0, 0}}; + int ret = 0; + + while ((opt = getopt_long(argc, argv, "p:r:c:m:s:", + long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 'c': + params->configurator_set.configurator = shell_strtol(optarg, 10, &ret); + break; + case 'm': + params->configurator_set.conf = shell_strtol(optarg, 10, &ret); + break; + case 's': + strncpy(params->configurator_set.ssid, optarg, WIFI_SSID_MAX_LEN); + break; + default: + PR_ERROR("Invalid option %c\n", optopt); + return -EINVAL; + } + + if (ret) { + PR_ERROR("Invalid argument %d ret %d\n", opt_index, ret); + return -EINVAL; + } + } + + return 0; +} + +static int cmd_wifi_dpp_configurator_add(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_CONFIGURATOR_ADD; + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_auth_init(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_AUTH_INIT; + + ret = parse_dpp_args_auth_init(sh, argc, argv, ¶ms); + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_qr_code(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_QR_CODE; + + if (argc >= 2) { + strncpy(params.dpp_qr_code, argv[1], WIFI_DPP_QRCODE_MAX_LEN); + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_chirp(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_CHIRP; + + ret = parse_dpp_args_chirp(sh, argc, argv, ¶ms); + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_listen(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_LISTEN; + + ret = parse_dpp_args_listen(sh, argc, argv, ¶ms); + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_btstrap_gen(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_BOOTSTRAP_GEN; + + ret = parse_dpp_args_btstrap_gen(sh, argc, argv, ¶ms); + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_btstrap_get_uri(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret = 0; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_BOOTSTRAP_GET_URI; + + if (argc >= 2) { + params.id = shell_strtol(argv[1], 10, &ret); + } + + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_configurator_set(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_SET_CONF_PARAM; + + ret = parse_dpp_args_set_config_param(sh, argc, argv, ¶ms); + if (ret) { + PR_ERROR("parse DPP args fail\n"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + +static int cmd_wifi_dpp_resp_timeout_set(const struct shell *sh, size_t argc, char *argv[]) +{ + int ret = 0; + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_dpp_params params = {0}; + + params.action = WIFI_DPP_SET_WAIT_RESP_TIME; + + if (argc >= 2) { + params.dpp_resp_wait_time = shell_strtol(argv[1], 10, &ret); + } + + if (ret) { + PR_ERROR("parse DPP args fail"); + return -EINVAL; + } + + if (net_mgmt(NET_REQUEST_WIFI_DPP, iface, ¶ms, sizeof(params))) { + PR_WARNING("Failed to request DPP action\n"); + return -ENOEXEC; + } + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(wifi_cmd_ap, SHELL_CMD_ARG(disable, NULL, "Disable Access Point mode.\n", @@ -1996,6 +2399,59 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_twt_ops, SHELL_SUBCMD_SET_END ); +SHELL_STATIC_SUBCMD_SET_CREATE( + wifi_cmd_dpp, + SHELL_CMD_ARG(configurator_add, NULL, + " Add DPP configurator\n", + cmd_wifi_dpp_configurator_add, 1, 0), + SHELL_CMD_ARG(auth_init, NULL, + "DPP start auth request:\n" + "-p --peer \n" + "[-r --role <1/2>]: DPP role default 1. 1: configurator, 2: enrollee\n" + "Optional args for configurator:\n" + "[-c --configurator ]\n" + "[-m --mode <1/2>]: Peer mode. 1: STA, 2: AP\n" + "[-s --ssid ]: SSID\n", + cmd_wifi_dpp_auth_init, 3, 8), + SHELL_CMD_ARG(qr_code, NULL, + " Input QR code:\n" + "\n", + cmd_wifi_dpp_qr_code, 2, 0), + SHELL_CMD_ARG(chirp, NULL, + " DPP chirp:\n" + "-i --own \n" + "-f --freq \n", + cmd_wifi_dpp_chirp, 5, 0), + SHELL_CMD_ARG(listen, NULL, + " DPP listen:\n" + "-f --freq \n" + "-r --role <1/2>: DPP role. 1: configurator, 2: enrollee\n", + cmd_wifi_dpp_listen, 5, 0), + SHELL_CMD_ARG(btstrap_gen, NULL, + " DPP bootstrap generate:\n" + "[-t --type <1/2/3>]: Bootstrap type. 1: qr_code, 2: pkex, 3: nfc." + " Currently only support qr_code\n" + "[-o --opclass ]\n" + "[-h --channel ]\n" + "[-a --mac ]\n", + cmd_wifi_dpp_btstrap_gen, 1, 8), + SHELL_CMD_ARG(btstrap_get_uri, NULL, + " Get DPP bootstrap uri by id:\n" + "\n", + cmd_wifi_dpp_btstrap_get_uri, 2, 0), + SHELL_CMD_ARG(configurator_set, NULL, + " Set DPP configurator parameters:\n" + "-c --configurator \n" + "[-m --mode <1/2>]: Peer mode. 1: STA, 2: AP\n" + "[-s --ssid ]: SSID\n", + cmd_wifi_dpp_configurator_set, 3, 4), + SHELL_CMD_ARG(resp_timeout_set, NULL, + " Set DPP RX response wait timeout ms:\n" + "\n", + cmd_wifi_dpp_resp_timeout_set, 2, 0), + SHELL_SUBCMD_SET_END +); + SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, SHELL_CMD_ARG(version, NULL, "Print Wi-Fi Driver and Firmware versions\n", cmd_wifi_version, @@ -2123,6 +2579,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, cmd_wifi_set_rts_threshold, 2, 0), + SHELL_CMD(dpp, &wifi_cmd_dpp, "DPP actions\n", NULL), SHELL_SUBCMD_SET_END );