diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..4e3069ec6 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,8 @@ +# CODEOWNERS for autoreview assigning in github + +# https://help.github.com/en/articles/about-code-owners#codeowners-syntax +# Order is important; the last matching pattern takes the most +# precedence. + +# Root folder +* @krish2718 @rado17 @rlubos @sachinthegreen diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 5b74ddcdf..c642264b6 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1556,7 +1556,7 @@ int supp_rates_11b_only(struct ieee802_11_elems *elems) return 0; for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) { - if (is_11b(elems->supp_rates[i])) + if (is_11b(elems->supp_rates[i] & 0x7f)) num_11b++; else num_others++; @@ -1564,7 +1564,7 @@ int supp_rates_11b_only(struct ieee802_11_elems *elems) for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len; i++) { - if (is_11b(elems->ext_supp_rates[i])) + if (is_11b(elems->ext_supp_rates[i] & 0x7f)) num_11b++; else num_others++; diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 40a979531..afdd93697 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -13,7 +13,9 @@ #ifdef CONFIG_CTRL_IFACE_UNIX #include #include +#ifndef CONFIG_ZEPHYR #include +#endif #include #include #endif /* CONFIG_CTRL_IFACE_UNIX */ @@ -35,8 +37,7 @@ #include "wpa_ctrl.h" #include "common.h" - -#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) +#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_ZEPHYR) #define CTRL_IFACE_SOCKET #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ @@ -72,6 +73,9 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +#ifdef CONFIG_CTRL_IFACE_ZEPHYR + int s; +#endif /* CONFIG_CTRL_IFACE_ZEPHYR */ }; @@ -579,6 +583,34 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, } #endif /* CTRL_IFACE_SOCKET */ +#ifdef CONFIG_CTRL_IFACE_ZEPHYR +struct wpa_ctrl * wpa_ctrl_open(const int sock) +{ + struct wpa_ctrl *ctrl; + + if (sock < 0) { + wpa_printf(MSG_ERROR, "Invalid socket : %d\n", sock); + return NULL; + } + + ctrl = os_zalloc(sizeof(*ctrl)); + if (ctrl == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate memory: %d\n", sizeof(*ctrl)); + return NULL; + } + + /* We use one of the socketpair opened in ctrl_iface_zephyr.c */ + ctrl->s = sock; + + return ctrl; +} + +void wpa_ctrl_close(struct wpa_ctrl *ctrl) +{ + close(ctrl->s); + os_free(ctrl); +} +#endif static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) { diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 3d3a62a17..efa85fa82 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -12,6 +12,8 @@ #ifdef __cplusplus extern "C" { #endif +extern struct wpa_ctrl *ctrl_conn; +extern char *ifname_prefix; /* wpa_supplicant control interface - fixed message prefixes */ @@ -476,6 +478,17 @@ enum wpa_vendor_elem_frame { /* wpa_supplicant/hostapd control interface access */ +#ifdef CONFIG_CTRL_IFACE_ZEPHYR +/** + * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd + * @sock: one of the pair of UNIX domain socket (socketpair) + * Returns: Pointer to abstract control interface data or %NULL on failure + * + * This function is used to open a control interface to wpa_supplicant/hostapd + * using a connected socketpair. + */ +struct wpa_ctrl * wpa_ctrl_open(const int sock); +#else /** * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. @@ -487,6 +500,7 @@ enum wpa_vendor_elem_frame { * interface need to use matching path configuration. */ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); +#endif /** * wpa_ctrl_open2 - Open a control interface to wpa_supplicant/hostapd @@ -634,6 +648,8 @@ void wpa_ctrl_cleanup(void); char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); #endif /* CONFIG_CTRL_IFACE_UDP */ +int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd); +int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]); #ifdef __cplusplus } diff --git a/src/crypto/crypto_mbedtls-bignum.c b/src/crypto/crypto_mbedtls-bignum.c new file mode 100644 index 000000000..7c0358e6f --- /dev/null +++ b/src/crypto/crypto_mbedtls-bignum.c @@ -0,0 +1,335 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto.h" +#include "random.h" +#include "sha256.h" +#include "mbedtls/pk.h" +#include "mbedtls/ctr_drbg.h" + +static int f_rng(void *p_rng, unsigned char *buf, size_t len) +{ + return random_get_bytes(buf, len); +} + +struct crypto_bignum *crypto_bignum_init(void) +{ + + mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); + if (bn == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate BN\n", __func__); + return NULL; + } + + mbedtls_mpi_init(bn); + + return (struct crypto_bignum *)bn; +} + +struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len) +{ + int ret = 0; + mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); + if (bn == NULL) { + return NULL; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len)); + return (struct crypto_bignum *)bn; + +cleanup: + os_free(bn); + return NULL; +} + +int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m) +{ + return mbedtls_mpi_random( + (mbedtls_mpi *)r, 0, (mbedtls_mpi *)m, f_rng, NULL); +} + +struct crypto_bignum *crypto_bignum_init_uint(unsigned int val) +{ + // MbedTLS works with BigEndian format + val = host_to_be32(val); + + return crypto_bignum_init_set((const u8 *)&val, sizeof(val)); +} + +void crypto_bignum_deinit(struct crypto_bignum *n, int clear) +{ + mbedtls_mpi_free((mbedtls_mpi *)n); + os_free((mbedtls_mpi *)n); +} + +int crypto_bignum_to_bin( + const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen) +{ + int num_bytes, offset; + int ret = 0; + + if (padlen > buflen) { + return -1; + } + + num_bytes = mbedtls_mpi_size((mbedtls_mpi *)a); + + if ((size_t)num_bytes > buflen) { + return -1; + } + if (padlen > (size_t)num_bytes) { + offset = padlen - num_bytes; + } else { + offset = 0; + } + + os_memset(buf, 0, offset); + MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary( + (mbedtls_mpi *)a, buf + offset, + mbedtls_mpi_size((mbedtls_mpi *)a))); + + return num_bytes + offset; +cleanup: + return ret; +} + +int crypto_bignum_add( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_add_mpi( + (mbedtls_mpi *)c, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) + ? -1 + : 0; +} + +int crypto_bignum_mod( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_mod_mpi( + (mbedtls_mpi *)c, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) + ? -1 + : 0; +} + +int crypto_bignum_exptmod( + const struct crypto_bignum *a, const struct crypto_bignum *b, + const struct crypto_bignum *c, struct crypto_bignum *d) +{ + int ret; + + mbedtls_mpi res; + + mbedtls_mpi_init(&res); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + (mbedtls_mpi *)&res, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b, (const mbedtls_mpi *)c, NULL)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy((mbedtls_mpi *)d, (const mbedtls_mpi *)&res)); + +cleanup: + mbedtls_mpi_free(&res); + return ret; + +} + +int crypto_bignum_inverse( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_inv_mod( + (mbedtls_mpi *)c, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) + ? -1 + : 0; +} + +int crypto_bignum_sub( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + return mbedtls_mpi_sub_mpi( + (mbedtls_mpi *)c, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b) + ? -1 + : 0; +} + +int crypto_bignum_div( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + int ret; + + mbedtls_mpi res; + mbedtls_mpi_init(&res); + + MBEDTLS_MPI_CHK(mbedtls_mpi_div_mpi( + (mbedtls_mpi *)&res, NULL, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy((mbedtls_mpi *)c, (const mbedtls_mpi *)&res)); + +cleanup: + mbedtls_mpi_free(&res); + return ret; +} + +int crypto_bignum_mulmod( + const struct crypto_bignum *a, const struct crypto_bignum *b, + const struct crypto_bignum *c, struct crypto_bignum *d) +{ + int ret; + + mbedtls_mpi temp; + mbedtls_mpi_init(&temp); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi( + &temp, (const mbedtls_mpi *)a, (const mbedtls_mpi *)b)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi((mbedtls_mpi *)d, &temp, (mbedtls_mpi *)c)); + mbedtls_mpi_free(&temp); + +cleanup: + return ret; +} + +int crypto_bignum_cmp( + const struct crypto_bignum *a, const struct crypto_bignum *b) +{ + return mbedtls_mpi_cmp_mpi( + (const mbedtls_mpi *)a, (const mbedtls_mpi *)b); +} + +int crypto_bignum_bits(const struct crypto_bignum *a) +{ + return mbedtls_mpi_bitlen((const mbedtls_mpi *)a); +} + +int crypto_bignum_is_zero(const struct crypto_bignum *a) +{ + return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 0) == 0); +} + +int crypto_bignum_is_one(const struct crypto_bignum *a) +{ + return (mbedtls_mpi_cmp_int((const mbedtls_mpi *)a, 1) == 0); +} + +int crypto_bignum_sqrmod( + const struct crypto_bignum *a, const struct crypto_bignum *b, + struct crypto_bignum *c) +{ + struct crypto_bignum *two = crypto_bignum_init_uint(2); + int ret; + + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + (mbedtls_mpi *)c, (mbedtls_mpi *)a, (mbedtls_mpi *)two, + (mbedtls_mpi *)b, NULL)); + +cleanup: + crypto_bignum_deinit(two, 1); + return ret; +} + +int crypto_bignum_rshift( + const struct crypto_bignum *a, int n, struct crypto_bignum *r) +{ + int ret; + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy((mbedtls_mpi *)r, (const mbedtls_mpi *)a)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r((mbedtls_mpi *)r, n)); + +cleanup: + return ret; +} + +int crypto_bignum_legendre( + const struct crypto_bignum *a, const struct crypto_bignum *p) +{ + mbedtls_mpi exp, tmp; + int res = -2, ret; + + mbedtls_mpi_init(&exp); + mbedtls_mpi_init(&tmp); + + /* exp = (p-1) / 2 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *)p, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + &tmp, (const mbedtls_mpi *)a, &exp, (const mbedtls_mpi *)p, NULL)); + + if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) { + res = 1; + } else if ( + mbedtls_mpi_cmp_int(&tmp, 0) == 0 + /* The below check is workaround for the case where HW + * does not behave properly for X ^ A mod M when X is + * power of M. Instead of returning value 0, value M is + * returned.*/ + || mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) { + res = 0; + } else { + res = -1; + } + +cleanup: + mbedtls_mpi_free(&tmp); + mbedtls_mpi_free(&exp); + return res; +} + +int crypto_bignum_to_string( + const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen) +{ + int num_bytes, offset; + size_t outlen; + + if (padlen > buflen) { + return -1; + } + + num_bytes = mbedtls_mpi_size((mbedtls_mpi *)a); + + if (padlen > (size_t)num_bytes) { + offset = padlen - num_bytes; + } else { + offset = 0; + } + + os_memset(buf, 0, offset); + mbedtls_mpi_write_string( + (mbedtls_mpi *)a, 16, (char *)(buf + offset), + mbedtls_mpi_size((mbedtls_mpi *)a), &outlen); + + return outlen; +} + +int crypto_bignum_addmod( + const struct crypto_bignum *a, const struct crypto_bignum *b, + const struct crypto_bignum *c, struct crypto_bignum *d) +{ + struct crypto_bignum *tmp = crypto_bignum_init(); + int ret; + + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi( + (mbedtls_mpi *)tmp, (const mbedtls_mpi *)a, + (const mbedtls_mpi *)b)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi( + (mbedtls_mpi *)d, (const mbedtls_mpi *)tmp, + (const mbedtls_mpi *)c)); + +cleanup: + crypto_bignum_deinit(tmp, 0); + return ret; +} + +void crypto_free_buffer(unsigned char *buf) { os_free(buf); } diff --git a/src/crypto/crypto_mbedtls-ec.c b/src/crypto/crypto_mbedtls-ec.c new file mode 100644 index 000000000..f79be2486 --- /dev/null +++ b/src/crypto/crypto_mbedtls-ec.c @@ -0,0 +1,956 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto.h" +#include "sha256.h" +#include "crypto/random.h" + +#include "mbedtls/ecp.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +#include "mbedtls/pk.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/sha256.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/error.h" +#include "mbedtls/oid.h" +#define IANA_SECP256R1 19 +#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES + +#ifdef CONFIG_ECC +static int f_rng(void *p_rng, unsigned char *buf, size_t len) +{ + return random_get_bytes(buf, len); +} +struct crypto_ec +{ + /* To WAR MbedTLS optimization as A is stored 0 but assumed "-3 mod P" internally*/ + mbedtls_mpi A; + mbedtls_ecp_group group; +}; + +int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len) +{ + return random_get_bytes(buf, len); +} + +const struct crypto_bignum *crypto_ec_get_a(struct crypto_ec *e) +{ + int ret; + mbedtls_mpi minus_three, one; + + mbedtls_mpi_init(&e->A); + mbedtls_mpi_init(&minus_three); + mbedtls_mpi_init(&one); + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&minus_three, -3)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1)); + /* A = -3 mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&e->A, &minus_three, &one, &e->group.P, NULL)); +cleanup: + return (const struct crypto_bignum *)&e->A; +} + +const struct crypto_bignum *crypto_ec_get_b(struct crypto_ec *e) +{ + return (const struct crypto_bignum *)&e->group.B; +} + +size_t crypto_ec_order_len(struct crypto_ec *e) +{ + return (mbedtls_mpi_bitlen(&e->group.N) + 7) / 8; +} + +struct crypto_ec *crypto_ec_init(int group) +{ + struct crypto_ec *e; + + mbedtls_ecp_group_id grp_id; + + /* IANA registry to mbedtls internal mapping*/ + switch (group) { + case IANA_SECP256R1: + /* For now just support NIST-P256. + * This is of type "short Weierstrass". + */ + grp_id = MBEDTLS_ECP_DP_SECP256R1; + break; + default: + return NULL; + } + e = os_zalloc(sizeof(*e)); + if (e == NULL) { + return NULL; + } + + mbedtls_ecp_group_init(&e->group); + + if (mbedtls_ecp_group_load(&e->group, grp_id)) { + crypto_ec_deinit(e); + e = NULL; + } + + return e; +} + +void crypto_ec_deinit(struct crypto_ec *e) +{ + if (e == NULL) { + return; + } + + mbedtls_ecp_group_free(&e->group); + os_free(e); +} + +struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e) +{ + mbedtls_ecp_point *pt; + if (e == NULL) { + return NULL; + } + + pt = os_zalloc(sizeof(mbedtls_ecp_point)); + + if (pt == NULL) { + return NULL; + } + + mbedtls_ecp_point_init(pt); + + return (struct crypto_ec_point *)pt; +} + +size_t crypto_ec_prime_len(struct crypto_ec *e) +{ + return mbedtls_mpi_size(&e->group.P); +} + +size_t crypto_ec_prime_len_bits(struct crypto_ec *e) +{ + return mbedtls_mpi_bitlen(&e->group.P); +} +struct crypto_ec_group *crypto_ec_get_group_byname(const char *name) +{ + struct crypto_ec *e; + const mbedtls_ecp_curve_info *curve = + mbedtls_ecp_curve_info_from_name(name); + + e = os_zalloc(sizeof(*e)); + if (e == NULL) { + return NULL; + } + + mbedtls_ecp_group_init(&e->group); + + if (mbedtls_ecp_group_load(&e->group, curve->grp_id)) { + crypto_ec_deinit(e); + e = NULL; + } + + return (struct crypto_ec_group *)&e->group; +} + +const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e) +{ + return (const struct crypto_bignum *)&e->group.P; +} + +const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e) +{ + return (const struct crypto_bignum *)&e->group.N; +} + +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) +{ + mbedtls_ecp_point_free((mbedtls_ecp_point *)p); + os_free(p); +} + +int crypto_ec_point_to_bin( + struct crypto_ec *e, const struct crypto_ec_point *point, u8 *x, u8 *y) +{ + int len = mbedtls_mpi_size(&e->group.P); + + if (x) { + if (crypto_bignum_to_bin( + (struct crypto_bignum *)&((mbedtls_ecp_point *)point) + ->MBEDTLS_PRIVATE(X), + x, len, len) < 0) { + return -1; + } + } + + if (y) { + if (crypto_bignum_to_bin( + (struct crypto_bignum *)&((mbedtls_ecp_point *)point) + ->MBEDTLS_PRIVATE(Y), + y, len, len) < 0) { + return -1; + } + } + + return 0; +} + +int crypto_ec_get_affine_coordinates( + struct crypto_ec *e, struct crypto_ec_point *pt, struct crypto_bignum *x, + struct crypto_bignum *y) +{ + int ret = -1; + mbedtls_ecp_point *point = (mbedtls_ecp_point *)pt; + + if (!mbedtls_ecp_is_zero(point) && + (mbedtls_mpi_cmp_int(&point->MBEDTLS_PRIVATE(Z), 1) == 0)) { + // Affine coordinates mean that z should be 1, + wpa_printf(MSG_ERROR, "Z coordinate is neither 0 or 1"); + return -1; + } + + if (x) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy( + (mbedtls_mpi *)x, + &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(X))); + } + if (y) { + MBEDTLS_MPI_CHK(mbedtls_mpi_copy( + (mbedtls_mpi *)y, + &((mbedtls_ecp_point *)point)->MBEDTLS_PRIVATE(Y))); + } + return 0; +cleanup: + return ret; +} + +int crypto_ec_point_x( + struct crypto_ec *e, const struct crypto_ec_point *p, + struct crypto_bignum *x) +{ + int ret = 0; + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy( + (mbedtls_mpi *)x, &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X))); + + return 0; +cleanup: + return ret; +} + +struct crypto_ec_point * +crypto_ec_point_from_bin(struct crypto_ec *e, const u8 *val) +{ + mbedtls_ecp_point *pt; + int len, ret; + + if (e == NULL) { + return NULL; + } + + len = mbedtls_mpi_size(&e->group.P); + + pt = os_zalloc(sizeof(mbedtls_ecp_point)); + if (!pt) { + return NULL; + } + mbedtls_ecp_point_init(pt); + + MBEDTLS_MPI_CHK( + mbedtls_mpi_read_binary(&pt->MBEDTLS_PRIVATE(X), val, len)); + MBEDTLS_MPI_CHK( + mbedtls_mpi_read_binary(&pt->MBEDTLS_PRIVATE(Y), val + len, len)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset((&pt->MBEDTLS_PRIVATE(Z)), 1)); + + return (struct crypto_ec_point *)pt; + +cleanup: + mbedtls_ecp_point_free(pt); + os_free(pt); + return NULL; +} + +int crypto_ec_point_add( + struct crypto_ec *e, const struct crypto_ec_point *a, + const struct crypto_ec_point *b, struct crypto_ec_point *c) +{ + int ret = 0; + mbedtls_mpi one; + + mbedtls_mpi_init(&one); + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&one, 1)); + MBEDTLS_MPI_CHK(mbedtls_ecp_muladd( + &e->group, (mbedtls_ecp_point *)c, &one, + (const mbedtls_ecp_point *)a, &one, (const mbedtls_ecp_point *)b)); + +cleanup: + mbedtls_mpi_free(&one); + return ret ? -1 : 0; +} + +int crypto_ec_point_mul( + struct crypto_ec *e, const struct crypto_ec_point *p, + const struct crypto_bignum *b, struct crypto_ec_point *res) +{ + int ret = 0; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed( + &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0)); + + MBEDTLS_MPI_CHK(mbedtls_ecp_mul( + &e->group, (mbedtls_ecp_point *)res, (const mbedtls_mpi *)b, + (const mbedtls_ecp_point *)p, mbedtls_ctr_drbg_random, &ctr_drbg)); +cleanup: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + if (ret) { + wpa_printf(MSG_ERROR, "%s: Failed with %d\n", __func__, ret); + } + return ret ? -1 : 0; +} + +/* Currently mbedtls does not have any function for inverse + * This function calculates inverse of a point. + * Set R = -P + */ +static int ecp_opp( + const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P) +{ + int ret = 0; + + /* Copy */ + if (R != P) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + } + + /* In-place opposite */ + if (mbedtls_mpi_cmp_int(&R->MBEDTLS_PRIVATE(Y), 0) != 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi( + &R->MBEDTLS_PRIVATE(Y), &grp->P, &R->MBEDTLS_PRIVATE(Y))); + } + +cleanup: + return (ret); +} + +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p) +{ + return ecp_opp( + &e->group, (mbedtls_ecp_point *)p, (mbedtls_ecp_point *)p) + ? -1 + : 0; +} + +int crypto_ec_point_solve_y_coord( + struct crypto_ec *e, struct crypto_ec_point *p, + const struct crypto_bignum *x, int y_bit) +{ + mbedtls_mpi temp, temp_no_alias; + mbedtls_mpi *y_sqr, *y; + mbedtls_mpi_init(&temp); + mbedtls_mpi_init(&temp_no_alias); + int ret = 0; + + y = &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y); + + /* Faster way to find sqrt + * Works only with curves having prime p + * such that p ≡ 3 (mod 4) + * y_ = (y2 ^ ((p+1)/4)) mod p + * + * if LSB of both x and y are same: y = y_ + * else y = p - y_ + * y_bit is LSB of x + */ + y_bit = (y_bit != 0); + + y_sqr = (mbedtls_mpi *)crypto_ec_point_compute_y_sqr(e, x); + + if (y_sqr) { + + MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&temp, &e->group.P, 1)); + MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp_no_alias, NULL, &temp, 4)); + MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&temp_no_alias, &temp)); + MBEDTLS_MPI_CHK( + mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL)); + + if (y_bit != mbedtls_mpi_get_bit(y, 0)) + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_copy( + &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), + (const mbedtls_mpi *)x)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset( + &((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Z), 1)); + } else { + ret = 1; + } +cleanup: + mbedtls_mpi_free(&temp); + mbedtls_mpi_free(y_sqr); + os_free(y_sqr); + return ret ? -1 : 0; +} + +int crypto_get_order(struct crypto_ec_group *group, struct crypto_bignum *x) +{ + return mbedtls_mpi_copy( + (mbedtls_mpi *)x, &((mbedtls_ecp_group *)group)->N); +} + +struct crypto_bignum *crypto_ec_point_compute_y_sqr( + struct crypto_ec *e, const struct crypto_bignum *x) +{ + mbedtls_mpi temp, temp2, num; + int ret = 0; + + mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi)); + if (y_sqr == NULL) { + return NULL; + } + + mbedtls_mpi_init(&temp); + mbedtls_mpi_init(&temp2); + mbedtls_mpi_init(&num); + mbedtls_mpi_init(y_sqr); + + /* y^2 = x^3 + ax + b mod P*/ + /* mbedtls does not have mod-add or mod-mul apis. + * + */ + + /* Calculate x^3 mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, 3)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + &temp, (const mbedtls_mpi *)x, &num, &e->group.P, NULL)); + + /* Calculate ax mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, -3)); + MBEDTLS_MPI_CHK( + mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *)x, &num)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P)); + + /* Calculate ax + b mod P. Note that b is already < P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &e->group.B)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P)); + + /* Calculate x^3 + ax + b mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp)); + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &e->group.P)); + +cleanup: + mbedtls_mpi_free(&temp); + mbedtls_mpi_free(&temp2); + mbedtls_mpi_free(&num); + if (ret) { + mbedtls_mpi_free(y_sqr); + os_free(y_sqr); + return NULL; + } else { + return (struct crypto_bignum *)y_sqr; + } +} + +int crypto_ec_point_is_at_infinity( + struct crypto_ec *e, const struct crypto_ec_point *p) +{ + return mbedtls_ecp_is_zero((mbedtls_ecp_point *)p); +} + +int crypto_ec_point_is_on_curve( + struct crypto_ec *e, const struct crypto_ec_point *p) +{ + mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two; + int ret = 0, on_curve = 0; + + mbedtls_mpi_init(&y_sqr_lhs); + mbedtls_mpi_init(&two); + + /* Calculate y^2 mod P*/ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&two, 2)); + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + &y_sqr_lhs, &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), + &two, &e->group.P, NULL)); + + y_sqr_rhs = (mbedtls_mpi *)crypto_ec_point_compute_y_sqr( + e, (const struct crypto_bignum *)&((const mbedtls_ecp_point *)p) + ->MBEDTLS_PRIVATE(X)); + + if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) { + on_curve = 1; + } + +cleanup: + mbedtls_mpi_free(&y_sqr_lhs); + mbedtls_mpi_free(&two); + mbedtls_mpi_free(y_sqr_rhs); + os_free(y_sqr_rhs); + return (ret == 0) && (on_curve == 1); +} + +int crypto_ec_point_cmp( + const struct crypto_ec *e, const struct crypto_ec_point *a, + const struct crypto_ec_point *b) +{ + return mbedtls_ecp_point_cmp( + (const mbedtls_ecp_point *)a, (const mbedtls_ecp_point *)b); +} + +void crypto_debug_print_point( + const char *title, struct crypto_ec *e, const struct crypto_ec_point *point) +{ + u8 x[32], y[32]; + + if (crypto_ec_point_to_bin(e, point, x, y) < 0) { + wpa_printf(MSG_ERROR, "error: failed to get corrdinates\n"); + return; + } + + wpa_hexdump(MSG_ERROR, "x:", x, 32); + wpa_hexdump(MSG_ERROR, "y:", y, 32); +} + +static struct crypto_key *crypto_alloc_key(void) +{ + mbedtls_pk_context *key = os_malloc(sizeof(*key)); + + if (!key) { + wpa_printf( + MSG_ERROR, "%s: memory allocation failed\n", __func__); + return NULL; + } + mbedtls_pk_init(key); + + return (struct crypto_key *)key; +} + +void crypto_ec_free_key(struct crypto_key *key) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + mbedtls_pk_free(pkey); + os_free(key); +} + +struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + + return (struct crypto_ec_point *)&mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE( + Q); +} + +int crypto_ec_get_priv_key_der( + struct crypto_key *key, unsigned char **key_data, int *key_len) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + char der_data[ECP_PRV_DER_MAX_BYTES]; + + *key_len = mbedtls_pk_write_key_der( + pkey, (unsigned char *)der_data, ECP_PRV_DER_MAX_BYTES); + if (*key_len <= 0) + return -1; + + *key_data = os_malloc(*key_len); + + if (!*key_data) { + wpa_printf(MSG_ERROR, "memory allocation failed\n"); + return -1; + } + os_memcpy(*key_data, der_data, *key_len); + + return 0; +} + +struct crypto_ec_group *crypto_ec_get_group_from_key(struct crypto_key *key) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + + return (struct crypto_ec_group *)&( + mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE(grp)); +} + +struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + + return ((struct crypto_bignum *)&( + mbedtls_pk_ec(*pkey)->MBEDTLS_PRIVATE(d))); +} + +int crypto_ec_get_publickey_buf(struct crypto_key *key, u8 *key_buf, int len) +{ + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE + 10]; /* tag, length + MPI */ + unsigned char *c = buf + sizeof(buf); + int pk_len = 0; + + memset(buf, 0, sizeof(buf)); + pk_len = mbedtls_pk_write_pubkey(&c, buf, pkey); + + if (pk_len < 0) + return -1; + + if (len == 0) + return pk_len; + + os_memcpy(key_buf, buf + MBEDTLS_MPI_MAX_SIZE + 10 - pk_len, pk_len); + + return pk_len; +} + +int crypto_write_pubkey_der(struct crypto_key *key, unsigned char **key_buf) +{ + unsigned char output_buf[1600] = {0}; + int len = mbedtls_pk_write_pubkey_der( + (mbedtls_pk_context *)key, output_buf, 1600); + if (len <= 0) + return 0; + + *key_buf = os_malloc(len); + if (!*key_buf) { + return 0; + } + os_memcpy(*key_buf, output_buf + 1600 - len, len); + + return len; +} + +struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len) +{ + int ret = 0; + mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key(); + + if (!kctx) { + wpa_printf(MSG_ERROR, "memory allocation failed\n"); + return NULL; + } + ret = mbedtls_pk_parse_key( + kctx, privkey, privkey_len, NULL, 0, f_rng, NULL); + + if (ret < 0) { + // crypto_print_error_string(ret); + goto fail; + } + + return (struct crypto_key *)kctx; + +fail: + mbedtls_pk_free(kctx); + os_free(kctx); + return NULL; +} + +unsigned int crypto_ec_get_mbedtls_to_nist_group_id(int id) +{ + unsigned int nist_grpid = 0; + switch (id) { + case MBEDTLS_ECP_DP_SECP256R1: + nist_grpid = 19; + break; + case MBEDTLS_ECP_DP_SECP384R1: + nist_grpid = 20; + break; + case MBEDTLS_ECP_DP_SECP521R1: + nist_grpid = 21; + break; + case MBEDTLS_ECP_DP_BP256R1: + nist_grpid = 28; + break; + case MBEDTLS_ECP_DP_BP384R1: + nist_grpid = 29; + break; + case MBEDTLS_ECP_DP_BP512R1: + nist_grpid = 30; + break; + default: + break; + } + + return nist_grpid; +} + +int crypto_ec_get_curve_id(const struct crypto_ec_group *group) +{ + mbedtls_ecp_group *grp = (mbedtls_ecp_group *)group; + return (crypto_ec_get_mbedtls_to_nist_group_id(grp->id)); +} + +int crypto_ecdh( + struct crypto_key *key_own, struct crypto_key *key_peer, u8 *secret, + size_t *secret_len) +{ + mbedtls_ecdh_context *ctx; + mbedtls_pk_context *own = (mbedtls_pk_context *)key_own; + mbedtls_pk_context *peer = (mbedtls_pk_context *)key_peer; + + int ret = -1; + + *secret_len = 0; + ctx = os_malloc(sizeof(*ctx)); + if (!ctx) { + wpa_printf( + MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s", __func__); + return -1; + } + + mbedtls_ecdh_init(ctx); + /* No need to setup, done through mbedtls_ecdh_get_params */ + + /* set params from our key */ + if (mbedtls_ecdh_get_params( + ctx, mbedtls_pk_ec(*own), MBEDTLS_ECDH_OURS) < 0) { + wpa_printf(MSG_ERROR, "failed to set our ecdh params\n"); + goto fail; + } + +#ifndef DPP_MAX_SHARED_SECRET_LEN +#define DPP_MAX_SHARED_SECRET_LEN 66 +#endif + /* set params from peers key */ + if (mbedtls_ecdh_get_params( + ctx, mbedtls_pk_ec(*peer), MBEDTLS_ECDH_THEIRS) < 0) { + wpa_printf(MSG_ERROR, "failed to set peer's ecdh params\n"); + goto fail; + } + + if (mbedtls_ecdh_calc_secret( + ctx, secret_len, secret, DPP_MAX_SHARED_SECRET_LEN, NULL, + NULL) < 0) { + wpa_printf(MSG_ERROR, "failed to calculate secret\n"); + goto fail; + } + + if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) { + wpa_printf( + MSG_ERROR, "secret len=%d is too big\n", *secret_len); + goto fail; + } + + ret = 0; + +fail: + mbedtls_ecdh_free(ctx); + os_free(ctx); + return ret; +} + +void crypto_debug_print_ec_key(const char *title, struct crypto_key *key) +{ +#ifdef DEBUG_PRINT + mbedtls_pk_context *pkey = (mbedtls_pk_context *)key; + mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(*pkey); + u8 x[32], y[32], d[32]; + wpa_printf( + MSG_ERROR, "curve: %s\n", + mbedtls_ecp_curve_info_from_grp_id(ecp->grp.id)->name); + int len = mbedtls_mpi_size((mbedtls_mpi *)crypto_ec_get_prime( + (struct crypto_ec *)crypto_ec_get_group_from_key(key))); + + wpa_printf(MSG_ERROR, "prime len is %d\n", len); + crypto_ec_point_to_bin( + (struct crypto_ec *)crypto_ec_get_group_from_key(key), + crypto_ec_get_public_key(key), x, y); + crypto_bignum_to_bin(crypto_ec_get_private_key(key), d, len, len); + wpa_hexdump(MSG_ERROR, "Q_x:", x, 32); + wpa_hexdump(MSG_ERROR, "Q_y:", y, 32); + wpa_hexdump(MSG_ERROR, "d: ", d, 32); +#endif +} + +struct crypto_key * +crypto_ec_parse_subpub_key(const unsigned char *p, size_t len) +{ + int ret = 0; + mbedtls_pk_context *pkey = (mbedtls_pk_context *)crypto_alloc_key(); + ret = mbedtls_pk_parse_subpubkey((unsigned char **)&p, p + len, pkey); + + if (ret < 0) { + os_free(pkey); + return NULL; + } + + return (struct crypto_key *)pkey; +} + +int crypto_is_ec_key(struct crypto_key *key) +{ + int ret = + mbedtls_pk_can_do((mbedtls_pk_context *)key, MBEDTLS_PK_ECKEY); + return ret; +} + +struct crypto_key *crypto_ec_gen_keypair(u16 ike_group) +{ + mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key(); + + if (!kctx) { + wpa_printf( + MSG_ERROR, "%s: memory allocation failed\n", __func__); + return NULL; + } + + if (mbedtls_pk_setup( + kctx, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0) + goto fail; + + mbedtls_ecp_gen_key( + MBEDTLS_ECP_DP_SECP256R1, + mbedtls_pk_ec(*kctx), // get this from argument + crypto_rng_wrapper, NULL); + + return (struct crypto_key *)kctx; +fail: + mbedtls_pk_free(kctx); + os_free(kctx); + return NULL; +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( + unsigned char **p, unsigned char *start, mbedtls_ecp_keypair *ec) +{ + int ret = 0; + size_t len = 0; + const char *oid; + size_t oid_len; + + if ((ret = mbedtls_oid_get_oid_by_ec_grp( + ec->MBEDTLS_PRIVATE(grp).id, &oid, &oid_len)) != 0) + return (ret); + + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_oid(p, start, oid, oid_len)); + + return ((int)len); +} + +static int pk_write_ec_pubkey_formatted( + unsigned char **p, unsigned char *start, mbedtls_ecp_keypair *ec, + int format) +{ + int ret = 0; + size_t len = 0; + unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; + + if ((ret = mbedtls_ecp_point_write_binary( + &ec->MBEDTLS_PRIVATE(grp), &ec->MBEDTLS_PRIVATE(Q), format, + &len, buf, sizeof(buf))) != 0) { + return (ret); + } + + if (*p < start || (size_t)(*p - start) < len) + return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL); + + *p -= len; + memcpy(*p, buf, len); + + return ((int)len); +} + +int mbedtls_pk_write_pubkey_formatted( + unsigned char **p, unsigned char *start, const mbedtls_pk_context *key, + int format) +{ + int ret = 0; + size_t len = 0; + + if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) + MBEDTLS_ASN1_CHK_ADD( + len, pk_write_ec_pubkey_formatted( + p, start, mbedtls_pk_ec(*key), format)); + else + return (MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE); + + return ((int)len); +} + +int crypto_pk_write_formatted_pubkey_der( + mbedtls_pk_context *key, unsigned char *buf, size_t size, int format) +{ + int ret = 0; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + const char *oid; + + if (size == 0) + return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL); + + c = buf + size; + + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_pk_write_pubkey_formatted(&c, buf, key, format)); + + if (c - buf < 1) + return (MBEDTLS_ERR_ASN1_BUF_TOO_SMALL); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_BIT_STRING)); + + if ((ret = mbedtls_oid_get_oid_by_pk_alg( + mbedtls_pk_get_type(key), &oid, &oid_len)) != 0) { + return (ret); + } + + if (mbedtls_pk_get_type(key) == MBEDTLS_PK_ECKEY) { + MBEDTLS_ASN1_CHK_ADD( + par_len, pk_write_ec_param(&c, buf, mbedtls_pk_ec(*key))); + } + + MBEDTLS_ASN1_CHK_ADD( + len, mbedtls_asn1_write_algorithm_identifier( + &c, buf, oid, oid_len, par_len)); + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); + MBEDTLS_ASN1_CHK_ADD( + len, + mbedtls_asn1_write_tag( + &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return ((int)len); +} + +int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf) +{ + unsigned char output_buf[1600] = {0}; + int len = crypto_pk_write_formatted_pubkey_der( + (mbedtls_pk_context *)key, output_buf, 1600, 1); + if (len <= 0) + return 0; + + *key_buf = os_malloc(len); + if (!*key_buf) { + wpa_printf( + MSG_ERROR, "%s: memory allocation failed\n", __func__); + return 0; + } + os_memcpy(*key_buf, output_buf + 1600 - len, len); + + return len; +} +#endif /* CONFIG_ECC */ diff --git a/src/crypto/crypto_mbedtls.c b/src/crypto/crypto_mbedtls.c new file mode 100644 index 000000000..3b800a0e7 --- /dev/null +++ b/src/crypto/crypto_mbedtls.c @@ -0,0 +1,911 @@ +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto.h" +#include "random.h" +#include "sha256.h" + +#include "mbedtls/ecp.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/md.h" +#include "mbedtls/aes.h" +#include "mbedtls/bignum.h" +#include "mbedtls/pkcs5.h" +#include "mbedtls/cmac.h" +#include "mbedtls/nist_kw.h" +#include "mbedtls/des.h" +#include "mbedtls/ccm.h" +#ifdef MBEDTLS_ARC4_C +#include "mbedtls/arc4.h" +#endif + +#include "common.h" +#include "utils/wpabuf.h" +#include "dh_group5.h" +#include "sha1.h" +#include "sha256.h" +#include "md5.h" +#include "aes_wrap.h" +#include "crypto.h" + +static int digest_vector( + mbedtls_md_type_t md_type, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + size_t i; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret = 0; + + mbedtls_md_init(&md_ctx); + + md_info = mbedtls_md_info_from_type(md_type); + if (!md_info) { + wpa_printf(MSG_ERROR, "mbedtls_md_info_from_type() failed"); + return -1; + } + + ret = mbedtls_md_setup(&md_ctx, md_info, 0); + if (ret != 0) { + wpa_printf(MSG_ERROR, "mbedtls_md_setup() returned error"); + goto cleanup; + } + + ret = mbedtls_md_starts(&md_ctx); + if (ret != 0) { + wpa_printf(MSG_ERROR, "mbedtls_md_starts returned error"); + goto cleanup; + } + + for (i = 0; i < num_elem; i++) { + ret = mbedtls_md_update(&md_ctx, addr[i], len[i]); + if (ret != 0) { + wpa_printf(MSG_ERROR, "mbedtls_md_update ret=%d", ret); + goto cleanup; + } + } + + ret = mbedtls_md_finish(&md_ctx, mac); +cleanup: + mbedtls_md_free(&md_ctx); + + return ret; +} + +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return digest_vector(MBEDTLS_MD_SHA256, num_elem, addr, len, mac); +} + +int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return digest_vector(MBEDTLS_MD_SHA384, num_elem, addr, len, mac); +} + +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return digest_vector(MBEDTLS_MD_SHA1, num_elem, addr, len, mac); +} + +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return digest_vector(MBEDTLS_MD_MD5, num_elem, addr, len, mac); +} + +#ifdef MBEDTLS_MD4_C +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + return digest_vector(MBEDTLS_MD_MD4, num_elem, addr, len, mac); +} +#endif + +struct crypto_hash +{ + mbedtls_md_context_t ctx; +}; + +struct crypto_hash * +crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) +{ + struct crypto_hash *ctx; + mbedtls_md_type_t md_type; + const mbedtls_md_info_t *md_info; + int ret = 0; + + switch (alg) { + case CRYPTO_HASH_ALG_HMAC_MD5: + md_type = MBEDTLS_MD_MD5; + break; + case CRYPTO_HASH_ALG_HMAC_SHA1: + md_type = MBEDTLS_MD_SHA1; + break; + case CRYPTO_HASH_ALG_HMAC_SHA256: + md_type = MBEDTLS_MD_SHA256; + break; + default: + return NULL; + } + + ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + return NULL; + } + + mbedtls_md_init(&ctx->ctx); + md_info = mbedtls_md_info_from_type(md_type); + if (!md_info) { + os_free(ctx); + return NULL; + } + ret = mbedtls_md_setup(&ctx->ctx, md_info, 1); + if (ret != 0) { + os_free(ctx); + return NULL; + } + mbedtls_md_hmac_starts(&ctx->ctx, key, key_len); + + return ctx; +} + +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) +{ + if (ctx == NULL) { + return; + } + mbedtls_md_hmac_update(&ctx->ctx, data, len); +} + +int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) +{ + if (ctx == NULL) { + return -2; + } + + if (mac == NULL || len == NULL) { + mbedtls_md_free(&ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + return 0; + } + mbedtls_md_hmac_finish(&ctx->ctx, mac); + mbedtls_md_free(&ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + + return 0; +} + +static int hmac_vector( + mbedtls_md_type_t md_type, const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + size_t i; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret = 0; + + mbedtls_md_init(&md_ctx); + + md_info = mbedtls_md_info_from_type(md_type); + if (!md_info) { + return -1; + } + + ret = mbedtls_md_setup(&md_ctx, md_info, 1); + if (ret != 0) { + return (ret); + } + + mbedtls_md_hmac_starts(&md_ctx, key, key_len); + + for (i = 0; i < num_elem; i++) { + mbedtls_md_hmac_update(&md_ctx, addr[i], len[i]); + } + + mbedtls_md_hmac_finish(&md_ctx, mac); + + mbedtls_md_free(&md_ctx); + + return 0; +} + +int hmac_sha384_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + return hmac_vector( + MBEDTLS_MD_SHA384, key, key_len, num_elem, addr, len, mac); +} + +int hmac_sha384( + const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) +{ + return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac); +} + +int hmac_sha256_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + return hmac_vector( + MBEDTLS_MD_SHA256, key, key_len, num_elem, addr, len, mac); +} + +int hmac_sha256( + const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) +{ + return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + +int hmac_md5_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + return hmac_vector( + MBEDTLS_MD_MD5, key, key_len, num_elem, addr, len, mac); +} + +int hmac_md5( + const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) +{ + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); +} + +int hmac_sha1_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + return hmac_vector( + MBEDTLS_MD_SHA1, key, key_len, num_elem, addr, len, mac); +} + +int hmac_sha1( + const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) +{ + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + +static void *aes_crypt_init(int mode, const u8 *key, size_t len) +{ + int ret = -1; + mbedtls_aes_context *aes = os_malloc(sizeof(*aes)); + if (!aes) { + return NULL; + } + mbedtls_aes_init(aes); + + if (mode == MBEDTLS_AES_ENCRYPT) { + ret = mbedtls_aes_setkey_enc(aes, key, len * 8); + } else if (mode == MBEDTLS_AES_DECRYPT) { + ret = mbedtls_aes_setkey_dec(aes, key, len * 8); + } + if (ret < 0) { + mbedtls_aes_free(aes); + os_free(aes); + wpa_printf( + MSG_ERROR, + "%s: mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec failed", + __func__); + return NULL; + } + + return (void *)aes; +} + +static int aes_crypt(void *ctx, int mode, const u8 *in, u8 *out) +{ + return mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, mode, in, out); +} + +static void aes_crypt_deinit(void *ctx) +{ + mbedtls_aes_free((mbedtls_aes_context *)ctx); + os_free(ctx); +} + +void *aes_encrypt_init(const u8 *key, size_t len) +{ + return aes_crypt_init(MBEDTLS_AES_ENCRYPT, key, len); +} + +int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + return aes_crypt(ctx, MBEDTLS_AES_ENCRYPT, plain, crypt); +} + +void aes_encrypt_deinit(void *ctx) { return aes_crypt_deinit(ctx); } + +void *aes_decrypt_init(const u8 *key, size_t len) +{ + return aes_crypt_init(MBEDTLS_AES_DECRYPT, key, len); +} + +int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + return aes_crypt(ctx, MBEDTLS_AES_DECRYPT, crypt, plain); +} + +void aes_decrypt_deinit(void *ctx) { return aes_crypt_deinit(ctx); } + +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[MBEDTLS_AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, MBEDTLS_AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc( + &ctx, MBEDTLS_AES_ENCRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; +} + +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[MBEDTLS_AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_dec(&ctx, key, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, MBEDTLS_AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc( + &ctx, MBEDTLS_AES_DECRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; +} + +struct crypto_cipher +{ + mbedtls_cipher_context_t ctx_enc; + mbedtls_cipher_context_t ctx_dec; +}; + +static int crypto_init_cipher_ctx( + mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info, + const u8 *iv, const u8 *key, mbedtls_operation_t operation) +{ + mbedtls_cipher_init(ctx); + int ret = 0; + + ret = mbedtls_cipher_setup(ctx, cipher_info); + if (ret != 0) { + return -1; + } + + if (mbedtls_cipher_setkey( + ctx, key, cipher_info->MBEDTLS_PRIVATE(key_bitlen), + operation) != 0) { + wpa_printf(MSG_ERROR, "mbedtls_cipher_setkey returned error"); + return -1; + } + if (mbedtls_cipher_set_iv( + ctx, iv, cipher_info->MBEDTLS_PRIVATE(iv_size)) != 0) { + wpa_printf(MSG_ERROR, "mbedtls_cipher_set_iv returned error"); + return -1; + } + if (mbedtls_cipher_reset(ctx) != 0) { + wpa_printf(MSG_ERROR, "mbedtls_cipher_reset() returned error"); + return -1; + } + + return 0; +} + +static mbedtls_cipher_type_t +alg_to_mbedtls_cipher(enum crypto_cipher_alg alg, size_t key_len) +{ + switch (alg) { +#ifdef MBEDTLS_ARC4_C + case CRYPTO_CIPHER_ALG_RC4: + return MBEDTLS_CIPHER_ARC4_128; +#endif + case CRYPTO_CIPHER_ALG_AES: + if (key_len == 16) { + return MBEDTLS_CIPHER_AES_128_CBC; + } + if (key_len == 24) { + return MBEDTLS_CIPHER_AES_192_CBC; + } + if (key_len == 32) { + return MBEDTLS_CIPHER_AES_256_CBC; + } + break; +#ifdef MBEDTLS_DES_C + case CRYPTO_CIPHER_ALG_3DES: + return MBEDTLS_CIPHER_DES_EDE3_CBC; + case CRYPTO_CIPHER_ALG_DES: + return MBEDTLS_CIPHER_DES_CBC; +#endif + default: + break; + } + + return MBEDTLS_CIPHER_NONE; +} + +struct crypto_cipher *crypto_cipher_init( + enum crypto_cipher_alg alg, const u8 *iv, const u8 *key, size_t key_len) +{ + struct crypto_cipher *ctx; + mbedtls_cipher_type_t cipher_type; + const mbedtls_cipher_info_t *cipher_info; + + ctx = (struct crypto_cipher *)os_zalloc(sizeof(*ctx)); + if (!ctx) { + return NULL; + } + + cipher_type = alg_to_mbedtls_cipher(alg, key_len); + if (cipher_type == MBEDTLS_CIPHER_NONE) { + goto cleanup; + } + + cipher_info = mbedtls_cipher_info_from_type(cipher_type); + if (cipher_info == NULL) { + goto cleanup; + } + + /* Init both ctx encryption/decryption */ + if (crypto_init_cipher_ctx( + &ctx->ctx_enc, cipher_info, iv, key, MBEDTLS_ENCRYPT) < 0) { + goto cleanup; + } + + if (crypto_init_cipher_ctx( + &ctx->ctx_dec, cipher_info, iv, key, MBEDTLS_DECRYPT) < 0) { + goto cleanup; + } + + return ctx; + +cleanup: + os_free(ctx); + return NULL; +} + +int crypto_cipher_encrypt( + struct crypto_cipher *ctx, const u8 *plain, u8 *crypt, size_t len) +{ + int ret = 0; + size_t olen = 1200; + + ret = mbedtls_cipher_update(&ctx->ctx_enc, plain, len, crypt, &olen); + if (ret != 0) { + return -1; + } + + ret = mbedtls_cipher_finish(&ctx->ctx_enc, crypt + olen, &olen); + if (ret != 0) { + return -1; + } + + return 0; +} + +int crypto_cipher_decrypt( + struct crypto_cipher *ctx, const u8 *crypt, u8 *plain, size_t len) +{ + int ret = 0; + size_t olen = 1200; + + ret = mbedtls_cipher_update(&ctx->ctx_dec, crypt, len, plain, &olen); + if (ret != 0) { + return -1; + } + + ret = mbedtls_cipher_finish(&ctx->ctx_dec, plain + olen, &olen); + if (ret != 0) { + return -1; + } + + return 0; +} + +void crypto_cipher_deinit(struct crypto_cipher *ctx) +{ + mbedtls_cipher_free(&ctx->ctx_enc); + mbedtls_cipher_free(&ctx->ctx_dec); + os_free(ctx); +} + +int aes_ctr_encrypt( + const u8 *key, size_t key_len, const u8 *nonce, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + uint8_t stream_block[MBEDTLS_AES_BLOCK_SIZE]; + size_t offset = 0; + + mbedtls_aes_init(&ctx); + ret = mbedtls_aes_setkey_enc(&ctx, key, key_len * 8); + if (ret < 0) { + goto cleanup; + } + ret = mbedtls_aes_crypt_ctr( + &ctx, data_len, &offset, (u8 *)nonce, stream_block, data, data); +cleanup: + mbedtls_aes_free(&ctx); + return ret; +} + +int aes_128_ctr_encrypt( + const u8 *key, const u8 *nonce, u8 *data, size_t data_len) +{ + return aes_ctr_encrypt(key, 16, nonce, data, data_len); +} + +#ifdef MBEDTLS_NIST_KW_C +int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) +{ + mbedtls_nist_kw_context ctx; + size_t olen; + int ret = 0; + mbedtls_nist_kw_init(&ctx); + + ret = mbedtls_nist_kw_setkey( + &ctx, MBEDTLS_CIPHER_ID_AES, kek, kek_len * 8, 1); + if (ret != 0) { + return ret; + } + + ret = mbedtls_nist_kw_wrap( + &ctx, MBEDTLS_KW_MODE_KW, plain, n * 8, cipher, &olen, (n + 1) * 8); + + mbedtls_nist_kw_free(&ctx); + return ret; +} + +int aes_unwrap( + const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) +{ + mbedtls_nist_kw_context ctx; + size_t olen; + int ret = 0; + mbedtls_nist_kw_init(&ctx); + + ret = mbedtls_nist_kw_setkey( + &ctx, MBEDTLS_CIPHER_ID_AES, kek, kek_len * 8, 0); + if (ret != 0) { + return ret; + } + + ret = mbedtls_nist_kw_unwrap( + &ctx, MBEDTLS_KW_MODE_KW, cipher, (n + 1) * 8, plain, &olen, + (n * 8)); + + mbedtls_nist_kw_free(&ctx); + return ret; +} +#endif + +int crypto_mod_exp( + const uint8_t *base, size_t base_len, const uint8_t *power, + size_t power_len, const uint8_t *modulus, size_t modulus_len, + uint8_t *result, size_t *result_len) +{ + mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result, bn_rinv; + int ret = 0; + + mbedtls_mpi_init(&bn_base); + mbedtls_mpi_init(&bn_exp); + mbedtls_mpi_init(&bn_modulus); + mbedtls_mpi_init(&bn_result); + mbedtls_mpi_init(&bn_rinv); + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&bn_base, base, base_len)); + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&bn_exp, power, power_len)); + MBEDTLS_MPI_CHK( + mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len)); + + MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod( + &bn_result, &bn_base, &bn_exp, &bn_modulus, &bn_rinv)); + + ret = mbedtls_mpi_write_binary(&bn_result, result, *result_len); + +cleanup: + mbedtls_mpi_free(&bn_base); + mbedtls_mpi_free(&bn_exp); + mbedtls_mpi_free(&bn_modulus); + mbedtls_mpi_free(&bn_result); + mbedtls_mpi_free(&bn_rinv); + + return ret; +} + +int pbkdf2_sha1( + const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, + u8 *buf, size_t buflen) +{ + + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret = 0; + + mbedtls_md_init(&sha1_ctx); + + info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + if (info_sha1 == NULL) { + ret = -1; + goto cleanup; + } + + if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) { + ret = -1; + goto cleanup; + } + + ret = mbedtls_pkcs5_pbkdf2_hmac( + &sha1_ctx, (const u8 *)passphrase, os_strlen(passphrase), ssid, + ssid_len, iterations, 32, buf); + if (ret != 0) { + ret = -1; + goto cleanup; + } + +cleanup: + mbedtls_md_free(&sha1_ctx); + return ret; +} + +#ifdef MBEDTLS_DES_C +int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) +{ + int ret = 0; + mbedtls_des_context des; + u8 pkey[8], next, tmp; + int i; + + /* Add parity bits to the key */ + next = 0; + for (i = 0; i < 7; i++) { + tmp = key[i]; + pkey[i] = (tmp >> i) | next | 1; + next = tmp << (7 - i); + } + pkey[i] = next | 1; + + mbedtls_des_init(&des); + ret = mbedtls_des_setkey_enc(&des, pkey); + if (ret < 0) { + return ret; + } + ret = mbedtls_des_crypt_ecb(&des, clear, cypher); + mbedtls_des_free(&des); + + return ret; +} +#endif + +/* Only enable this if all other ciphers are using MbedTLS implementation */ +#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_CMAC_C) && \ + defined(MBEDTLS_NIST_KW_C) +int aes_ccm_ae( + const u8 *key, size_t key_len, const u8 *nonce, size_t M, const u8 *plain, + size_t plain_len, const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth) +{ + int ret = 0; + mbedtls_ccm_context ccm; + + mbedtls_ccm_init(&ccm); + + ret = mbedtls_ccm_setkey(&ccm, MBEDTLS_CIPHER_ID_AES, key, key_len * 8); + if (ret < 0) { + wpa_printf(MSG_ERROR, "mbedtls_ccm_setkey failed"); + goto cleanup; + } + + ret = mbedtls_ccm_encrypt_and_tag( + &ccm, plain_len, nonce, 13, aad, aad_len, plain, crypt, auth, M); + +cleanup: + mbedtls_ccm_free(&ccm); + + return ret; +} + +int aes_ccm_ad( + const u8 *key, size_t key_len, const u8 *nonce, size_t M, const u8 *crypt, + size_t crypt_len, const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain) +{ + int ret = 0; + mbedtls_ccm_context ccm; + + mbedtls_ccm_init(&ccm); + + ret = mbedtls_ccm_setkey(&ccm, MBEDTLS_CIPHER_ID_AES, key, key_len * 8); + if (ret < 0) { + goto cleanup; + ; + } + + ret = mbedtls_ccm_star_auth_decrypt( + &ccm, crypt_len, nonce, 13, aad, aad_len, crypt, plain, auth, M); + +cleanup: + mbedtls_ccm_free(&ccm); + + return ret; +} +#endif + +#ifdef MBEDTLS_ARC4_C +int rc4_skip( + const u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len) +{ + int ret = 0; + unsigned char skip_buf_in[16]; + unsigned char skip_buf_out[16]; + mbedtls_arc4_context ctx; + unsigned char *obuf = os_malloc(data_len); + + if (!obuf) { + wpa_printf(MSG_ERROR, "%s:memory allocation failed", __func__); + return -1; + } + mbedtls_arc4_init(&ctx); + mbedtls_arc4_setup(&ctx, key, keylen); + while (skip >= sizeof(skip_buf_in)) { + size_t len = skip; + if (len > sizeof(skip_buf_in)) { + len = sizeof(skip_buf_in); + } + if ((ret = mbedtls_arc4_crypt( + &ctx, len, skip_buf_in, skip_buf_out)) != 0) { + wpa_printf(MSG_ERROR, "rc4 encryption failed"); + return -1; + } + os_memcpy(skip_buf_in, skip_buf_out, 16); + skip -= len; + } + + mbedtls_arc4_crypt(&ctx, data_len, data, obuf); + + memcpy(data, obuf, data_len); + os_free(obuf); + + return 0; +} +#endif + +#ifdef MBEDTLS_CMAC_C +int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_vector(key, 32, 1, &data, &data_len, mac); +} + +int omac1_aes_vector( + const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac) +{ + const mbedtls_cipher_info_t *cipher_info; + int i, ret = 0; + mbedtls_cipher_type_t cipher_type; + mbedtls_cipher_context_t ctx; + + switch (key_len) { + case 16: + cipher_type = MBEDTLS_CIPHER_AES_128_ECB; + break; + case 24: + cipher_type = MBEDTLS_CIPHER_AES_192_ECB; + break; + case 32: + cipher_type = MBEDTLS_CIPHER_AES_256_ECB; + break; + default: + cipher_type = MBEDTLS_CIPHER_NONE; + break; + } + cipher_info = mbedtls_cipher_info_from_type(cipher_type); + if (cipher_info == NULL) { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto cleanup; + } + + if (key == NULL || mac == NULL) { + return -1; + } + + mbedtls_cipher_init(&ctx); + + ret = mbedtls_cipher_setup(&ctx, cipher_info); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_cipher_cmac_starts(&ctx, key, key_len * 8); + if (ret != 0) { + goto cleanup; + } + + for (i = 0; i < num_elem; i++) { + ret = mbedtls_cipher_cmac_update(&ctx, addr[i], len[i]); + if (ret != 0) { + goto cleanup; + } + } + + ret = mbedtls_cipher_cmac_finish(&ctx, mac); +cleanup: + mbedtls_cipher_free(&ctx); + return (ret); +} + +int omac1_aes_128_vector( + const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + return omac1_aes_vector(key, 16, num_elem, addr, len, mac); +} + +int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_128_vector(key, 1, &data, &data_len, mac); +} +#endif + +int crypto_bignum_is_odd(const struct crypto_bignum *a) +{ + return mbedtls_mpi_get_bit((mbedtls_mpi *)a, 0); +} + +int crypto_dh_derive_secret( + u8 generator, const u8 *prime, size_t prime_len, const u8 *order, + size_t order_len, const u8 *privkey, size_t privkey_len, const u8 *pubkey, + size_t pubkey_len, u8 *secret, size_t *len) +{ + return crypto_mod_exp( + prime, prime_len, privkey, privkey_len, pubkey, pubkey_len, secret, + len); +} + +int crypto_dh_init( + u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, u8 *pubkey) +{ + size_t pubkey_len, pad; + + if (os_get_random(privkey, prime_len) < 0) { + return -1; + } + if (os_memcmp(privkey, prime, prime_len) > 0) { + /* Make sure private value is smaller than prime */ + privkey[0] = 0; + } + + pubkey_len = prime_len; + if (crypto_mod_exp( + &generator, 1, privkey, prime_len, prime, prime_len, pubkey, + &pubkey_len) < 0) { + return -1; + } + if (pubkey_len < prime_len) { + pad = prime_len - pubkey_len; + os_memmove(pubkey + pad, pubkey, pubkey_len); + os_memset(pubkey, 0, pad); + } + + return 0; +} diff --git a/src/crypto/tls_mbedtls.c b/src/crypto/tls_mbedtls.c new file mode 100644 index 000000000..22e737686 --- /dev/null +++ b/src/crypto/tls_mbedtls.c @@ -0,0 +1,1182 @@ +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "utils/includes.h" +#include "utils/common.h" + +#include "tls.h" +#include "crypto/sha1.h" +#include "crypto/md5.h" +#include "crypto/sha256.h" +#include "crypto/sha384.h" +#include "random.h" +#include +#include +#include +#include +#include +#include +#include + +#define TLS_RANDOM_LEN 32 +#define TLS_MASTER_SECRET_LEN 48 +#define MAX_CIPHERSUITE 32 + +/* Throw a compilation error if basic requirements in mbedtls are not enabled */ +#if !defined(MBEDTLS_SSL_TLS_C) +#error "TLS not enabled in mbedtls config" +#endif + +#if !defined(MBEDTLS_SHA256_C) +#error "SHA256 is disabled in mbedtls config" +#endif + +#if !defined(MBEDTLS_AES_C) +#error "AES support is disabled in mbedtls config" +#endif + +uint32_t tls_instance_count; +struct tls_data +{ + /* Data for mbedlts */ + struct wpabuf *in_data; + /* Data from mbedtls */ + struct wpabuf *out_data; +}; + +mbedtls_ssl_export_keys_t tls_connection_export_keys_cb; + +typedef struct tls_context +{ + mbedtls_ssl_context ssl; /*!< TLS/SSL context */ + mbedtls_entropy_context + entropy; /*!< mbedTLS entropy context structure */ + mbedtls_ctr_drbg_context + ctr_drbg; /*!< mbedTLS ctr drbg context structure */ + mbedtls_ssl_config conf; /*!< TLS/SSL config to be shared structures */ + mbedtls_x509_crt cacert; /*!< Container for X.509 CA certificate */ + mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */ + mbedtls_x509_crt + clientcert; /*!< Container for X.509 client certificate */ + mbedtls_pk_context clientkey; /*!< Private key of client certificate */ + int ciphersuite[MAX_CIPHERSUITE]; +} tls_context_t; + +struct tls_connection +{ + tls_context_t *tls; + struct tls_data tls_io_data; + unsigned char master_secret[TLS_MASTER_SECRET_LEN]; + unsigned char randbytes[2 * TLS_RANDOM_LEN]; + mbedtls_tls_prf_types tls_prf_type; +}; + +static int f_rng(void *p_rng, unsigned char *buf, size_t len) +{ + return random_get_bytes(buf, len); +} + +static void tls_mbedtls_cleanup(tls_context_t *tls) +{ + if (!tls) { + return; + } + tls->cacert_ptr = NULL; + mbedtls_x509_crt_free(&tls->cacert); + mbedtls_x509_crt_free(&tls->clientcert); + mbedtls_pk_free(&tls->clientkey); + mbedtls_entropy_free(&tls->entropy); + mbedtls_ssl_config_free(&tls->conf); + mbedtls_ctr_drbg_free(&tls->ctr_drbg); + mbedtls_ssl_free(&tls->ssl); +} + +static void tls_mbedtls_conn_delete(tls_context_t *tls) +{ + if (tls != NULL) { + tls_mbedtls_cleanup(tls); + } +} + +static int tls_mbedtls_write(void *ctx, const unsigned char *buf, size_t len) +{ + struct tls_connection *conn = (struct tls_connection *)ctx; + struct tls_data *data = &conn->tls_io_data; + + if (wpabuf_resize(&data->out_data, len) < 0) + return 0; + + wpabuf_put_data(data->out_data, buf, len); + + return len; +} + +static int tls_mbedtls_read(void *ctx, unsigned char *buf, size_t len) +{ + struct tls_connection *conn = (struct tls_connection *)ctx; + struct tls_data *data = &conn->tls_io_data; + struct wpabuf *local_buf; + size_t data_len = len; + + if (data->in_data == NULL) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + if (len > wpabuf_len(data->in_data)) { + wpa_printf(MSG_ERROR, "don't have suffient data\n"); + data_len = wpabuf_len(data->in_data); + } + + os_memcpy(buf, wpabuf_head(data->in_data), data_len); + /* adjust buffer */ + if (len < wpabuf_len(data->in_data)) { + local_buf = wpabuf_alloc_copy( + (char *)wpabuf_head(data->in_data) + data_len, + wpabuf_len(data->in_data) - data_len); + wpabuf_free(data->in_data); + data->in_data = local_buf; + } else { + wpabuf_free(data->in_data); + data->in_data = NULL; + } + + return data_len; +} + +static int +set_pki_context(tls_context_t *tls, const struct tls_connection_params *cfg) +{ + int ret = 0; + + if (cfg->client_cert_blob == NULL || cfg->private_key_blob == NULL) { + wpa_printf(MSG_ERROR, "%s: config not correct", __func__); + return -1; + } + + mbedtls_x509_crt_init(&tls->clientcert); + mbedtls_pk_init(&tls->clientkey); + + ret = mbedtls_x509_crt_parse( + &tls->clientcert, cfg->client_cert_blob, cfg->client_cert_blob_len); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "mbedtls_x509_crt_parse returned -0x%x", -ret); + return ret; + } + + ret = mbedtls_pk_parse_key( + &tls->clientkey, cfg->private_key_blob, cfg->private_key_blob_len, + (const unsigned char *)cfg->private_key_passwd, + cfg->private_key_passwd ? os_strlen(cfg->private_key_passwd) : 0, + f_rng, NULL); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "mbedtls_pk_parse_keyfile returned -0x%x", -ret); + return ret; + } + + ret = mbedtls_ssl_conf_own_cert( + &tls->conf, &tls->clientcert, &tls->clientkey); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "mbedtls_ssl_conf_own_cert returned -0x%x", + -ret); + return ret; + } + + return 0; +} + +static int +set_ca_cert(tls_context_t *tls, const unsigned char *cacert, size_t cacert_len) +{ + tls->cacert_ptr = &tls->cacert; + mbedtls_x509_crt_init(tls->cacert_ptr); + int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "mbedtls_x509_crt_parse returned -0x%x", -ret); + return ret; + } + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + + return 0; +} + +#ifdef CONFIG_SUITEB192 +static int tls_sig_hashes_for_suiteb[] = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, MBEDTLS_MD_SHA384, +#endif + MBEDTLS_MD_NONE}; + +const mbedtls_x509_crt_profile suiteb_mbedtls_x509_crt_profile = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512) | +#endif + 0, + 0xFFFFFFF, /* Any PK alg */ + MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_SECP384R1), + 1024, +}; + +static void tls_set_suiteb_config(tls_context_t *tls) +{ + const mbedtls_x509_crt_profile *crt_profile = + &suiteb_mbedtls_x509_crt_profile; + mbedtls_ssl_conf_cert_profile(&tls->conf, crt_profile); + mbedtls_ssl_conf_sig_hashes(&tls->conf, tls_sig_hashes_for_suiteb); +} +#endif + +static int tls_sig_hashes_for_eap[] = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, MBEDTLS_MD_SHA384, +#endif +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, MBEDTLS_MD_SHA224, +#endif +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + MBEDTLS_MD_NONE}; + +const mbedtls_x509_crt_profile eap_mbedtls_x509_crt_profile = { +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | +#endif +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | +#endif +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512) | +#endif + 0, + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 1024, +}; + +static void tls_enable_sha1_config(tls_context_t *tls) +{ + const mbedtls_x509_crt_profile *crt_profile = + &eap_mbedtls_x509_crt_profile; + mbedtls_ssl_conf_cert_profile(&tls->conf, crt_profile); + mbedtls_ssl_conf_sig_hashes(&tls->conf, tls_sig_hashes_for_eap); +} + +static const int eap_ciphersuite_preference[] = { +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, +#endif +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, +#endif + +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, +#endif +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, + + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, +#endif +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_RSA_WITH_AES_256_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, +#endif + +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_RSA_WITH_AES_128_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, +#endif +/* The PSK suites */ +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_PSK_WITH_AES_256_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, +#endif + +#if defined(MBEDTLS_GCM_C) + MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_PSK_WITH_AES_128_CCM, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, +#endif +#if defined(MBEDTLS_CCM_C) + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, +#endif +#endif + +#if 0 + /* 3DES suites */ + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, +#endif +#if defined(MBEDTLS_ARC4_C) + /* RC4 suites */ + MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, +#endif + 0}; + +#ifdef CONFIG_SUITEB192 +static const int suiteb_rsa_ciphersuite_preference[] = { +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif +#endif + 0}; + +static const int suiteb_ecc_ciphersuite_preference[] = { +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +#endif +#endif + 0}; +static const int suiteb_ciphersuite_preference[] = { +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif +#endif + 0}; +#endif + +static void +tls_set_ciphersuite(const struct tls_connection_params *cfg, tls_context_t *tls) +{ + /* Only set ciphersuite if cert's key length is high or ciphersuites are + * set by user */ +#ifdef CONFIG_SUITEB192 + if (cfg->flags & TLS_CONN_SUITEB) { + /* cipher suites will be set based on certificate */ + mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type(&tls->clientkey); + if (pk_alg == MBEDTLS_PK_RSA || + pk_alg == MBEDTLS_PK_RSASSA_PSS) { + mbedtls_ssl_conf_ciphersuites( + &tls->conf, suiteb_rsa_ciphersuite_preference); + } else if ( + pk_alg == MBEDTLS_PK_ECDSA || pk_alg == MBEDTLS_PK_ECKEY || + pk_alg == MBEDTLS_PK_ECKEY_DH) { + mbedtls_ssl_conf_ciphersuites( + &tls->conf, suiteb_ecc_ciphersuite_preference); + } else { + mbedtls_ssl_conf_ciphersuites( + &tls->conf, suiteb_ciphersuite_preference); + } + } else +#endif + if (tls->ciphersuite[0]) { + mbedtls_ssl_conf_ciphersuites(&tls->conf, tls->ciphersuite); + } else if ( + mbedtls_pk_get_bitlen(&tls->clientkey) > 2048 || + (tls->cacert_ptr && + mbedtls_pk_get_bitlen(&tls->cacert_ptr->pk) > + 2048)) { + mbedtls_ssl_conf_ciphersuites( + &tls->conf, eap_ciphersuite_preference); + } +} + +static int +parse_certs(const struct tls_connection_params *cfg, tls_context_t *tls) +{ + int ret = 0; + +#ifdef CONFIG_MBEDTLS_FS_IO + if (cfg->ca_cert) { + tls->cacert_ptr = &tls->cacert; + mbedtls_x509_crt_init(tls->cacert_ptr); + + ret = mbedtls_x509_crt_parse_file(&tls->cacert, cfg->ca_cert); + if (ret < 0) { + wpa_printf( + MSG_ERROR, + "mbedtls_x509_crt_parse_der failed -0x%x", -ret); + return -1; + } + + mbedtls_ssl_conf_authmode( + &tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + wpa_printf(MSG_ERROR, "Loaded CA cert: %s\n", cfg->ca_cert); + + } else +#endif + if (cfg->ca_cert_blob != NULL) { + ret = + set_ca_cert(tls, cfg->ca_cert_blob, cfg->ca_cert_blob_len); + if (ret != 0) { + return ret; + } + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + } else { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); + } + +#ifdef CONFIG_MBEDTLS_FS_IO + if (cfg->client_cert && cfg->private_key) { + mbedtls_x509_crt_init(&tls->clientcert); + ret = mbedtls_x509_crt_parse_file( + &tls->clientcert, cfg->client_cert); + if (ret < 0) { + wpa_printf( + MSG_ERROR, + "mbedtls_x509_crt_parse_der failed -0x%x", -ret); + return -1; + } + wpa_printf( + MSG_ERROR, "Loaded Client cert: %s\n", cfg->client_cert); + + mbedtls_pk_init(&tls->clientkey); + ret = mbedtls_pk_parse_keyfile( + &tls->clientkey, cfg->private_key, cfg->private_key_passwd, + f_rng, NULL); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "mbedtls_pk_parse_key failed -0x%x", + -ret); + return -1; + } + wpa_printf( + MSG_ERROR, "Loaded private key: %s\n", cfg->private_key); + + ret = mbedtls_ssl_conf_own_cert( + &tls->conf, &tls->clientcert, &tls->clientkey); + if (ret < 0) { + wpa_printf( + MSG_ERROR, + "mbedtls_ssl_conf_own_cert returned -0x%x", -ret); + return ret; + } + wpa_printf(MSG_ERROR, "Loaded client and key\n"); + + } else +#endif + if (cfg->client_cert_blob != NULL && + cfg->private_key_blob != NULL) { + ret = set_pki_context(tls, cfg); + if (ret != 0) { + wpa_printf( + MSG_ERROR, "Failed to set client pki context"); + return ret; + } + } + + return 0; +} + +static int +set_client_config(const struct tls_connection_params *cfg, tls_context_t *tls) +{ + int ret = 0; + int preset = MBEDTLS_SSL_PRESET_DEFAULT; + assert(cfg != NULL); + assert(tls != NULL); + +#ifdef CONFIG_SUITEB192 + if (cfg->flags & TLS_CONN_SUITEB) + preset = MBEDTLS_SSL_PRESET_SUITEB; +#endif + ret = mbedtls_ssl_config_defaults( + &tls->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, + preset); + if (ret != 0) { + wpa_printf( + MSG_ERROR, "mbedtls_ssl_config_defaults returned -0x%x", + -ret); + return ret; + } + + if (preset != MBEDTLS_SSL_PRESET_SUITEB) { + /* Enable SHA1 support since it's not enabled by default in + * mbedtls */ + tls_enable_sha1_config(tls); +#ifdef CONFIG_SUITEB192 + } else { + tls_set_suiteb_config(tls); +#endif + } + wpa_printf( + MSG_ERROR, ": mbedtls_ssl_config_defaults: ciphersuite: %s\n", + mbedtls_ssl_get_ciphersuite(&tls->ssl)); + + wpa_printf(MSG_ERROR, ": CA cert: %s\n", cfg->ca_cert); + wpa_printf(MSG_ERROR, ": Client cert: %s\n", cfg->client_cert); + wpa_printf(MSG_ERROR, ": Client key: %s\n", cfg->private_key); + + if ((ret = parse_certs(cfg, tls))) { + wpa_printf(MSG_ERROR, "Failed to load certs: %d\n", ret); + return ret; + } + wpa_printf(MSG_INFO, "Loaded certs\n"); + + /* Usages of default ciphersuites can take a lot of time on low end + * device and can cause watchdog. Enabling the ciphers which are secured + * enough but doesn't take that much processing power */ + tls_set_ciphersuite(cfg, tls); + + return 0; +} + +static int tls_create_mbedtls_handle( + const struct tls_connection_params *params, tls_context_t *tls) +{ + int ret = 0; + + assert(params != NULL); + assert(tls != NULL); + + mbedtls_ssl_init(&tls->ssl); + mbedtls_ctr_drbg_init(&tls->ctr_drbg); + mbedtls_ssl_config_init(&tls->conf); + mbedtls_entropy_init(&tls->entropy); + + ret = set_client_config(params, tls); + if (ret != 0) { + wpa_printf(MSG_ERROR, "Failed to set client configurations"); + goto exit; + } + + ret = mbedtls_ctr_drbg_seed( + &tls->ctr_drbg, mbedtls_entropy_func, &tls->entropy, NULL, 0); + if (ret != 0) { + wpa_printf( + MSG_ERROR, "mbedtls_ctr_drbg_seed returned -0x%x", -ret); + goto exit; + } + + mbedtls_ssl_conf_rng( + &tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg); + + ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf); + if (ret != 0) { + wpa_printf(MSG_ERROR, "mbedtls_ssl_setup returned -0x%x", -ret); + goto exit; + } +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + /* Disable BEAST attack countermeasures for Windows 2008 + * interoperability */ + mbedtls_ssl_conf_cbc_record_splitting( + &tls->conf, MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED); +#endif + + return 0; + +exit: + tls_mbedtls_cleanup(tls); + return ret; +} + +void *tls_init(const struct tls_config *conf) +{ + tls_instance_count++; + return &tls_instance_count; +} + +void tls_deinit(void *tls_ctx) { tls_instance_count--; } + +struct tls_connection *tls_connection_init(void *tls_ctx) +{ + struct tls_connection *conn = os_zalloc(sizeof(*conn)); + if (!conn) { + wpa_printf( + MSG_ERROR, "TLS: Failed to allocate connection memory"); + return NULL; + } + + return conn; +} + +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) +{ + /* case: tls init failed */ + if (!conn) { + return; + } + /* Free ssl ctx and data */ + tls_mbedtls_conn_delete((tls_context_t *)conn->tls); + os_free(conn->tls); + conn->tls = NULL; + /* Data in in ssl ctx, free connection */ + os_free(conn); +} + +int tls_get_errors(void *tls_ctx) { return 0; } + +int tls_connection_established(void *tls_ctx, struct tls_connection *conn) +{ + mbedtls_ssl_context *ssl = &conn->tls->ssl; + + if (ssl->MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_HANDSHAKE_OVER) { + return 1; + } + + return 0; +} + +int tls_global_set_verify(void *tls_ctx, int check_crl, int strict) +{ + wpa_printf(MSG_INFO, "TLS: global settings are not supported"); + return -1; +} + +int tls_connection_set_verify( + void *tls_ctx, struct tls_connection *conn, int verify_peer, + unsigned int flags, const u8 *session_ctx, size_t session_ctx_len) +{ + wpa_printf(MSG_INFO, "TLS: tls_connection_set_verify not supported"); + return -1; +} + +struct wpabuf *tls_connection_handshake( + void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + tls_context_t *tls = conn->tls; + int ret = 0; + + /* data freed by sender */ + conn->tls_io_data.out_data = NULL; + if (wpabuf_len(in_data)) { + conn->tls_io_data.in_data = wpabuf_dup(in_data); + } + + /* Multiple reads */ + while (tls->ssl.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) { + ret = mbedtls_ssl_handshake_step(&tls->ssl); + + if (ret < 0) + break; + } + if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ) { + wpa_printf(MSG_INFO, "%s: ret is %d", __func__, ret); + goto end; + } + + if (!conn->tls_io_data.out_data) { + wpa_printf( + MSG_INFO, + "application data is null, adding one byte for ack"); + u8 *dummy = os_zalloc(1); + conn->tls_io_data.out_data = wpabuf_alloc_ext_data(dummy, 0); + } + +end: + return conn->tls_io_data.out_data; +} + +struct wpabuf *tls_connection_server_handshake( + void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + wpa_printf(MSG_ERROR, "%s: not supported %d", __func__, __LINE__); + return NULL; +} + +struct wpabuf *tls_connection_encrypt( + void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) +{ + /* Reset dangling pointer */ + conn->tls_io_data.out_data = NULL; + + ssize_t ret = mbedtls_ssl_write( + &conn->tls->ssl, (unsigned char *)wpabuf_head(in_data), + wpabuf_len(in_data)); + + if (ret < wpabuf_len(in_data)) { + wpa_printf( + MSG_ERROR, "%s:%d, not able to write whole data", __func__, + __LINE__); + } + + return conn->tls_io_data.out_data; +} + +struct wpabuf *tls_connection_decrypt( + void *tls_ctx, struct tls_connection *conn, const struct wpabuf *in_data) +{ + unsigned char buf[1200]; + int ret = 0; + conn->tls_io_data.in_data = wpabuf_dup(in_data); + ret = mbedtls_ssl_read(&conn->tls->ssl, buf, 1200); + if (ret < 0) { + wpa_printf( + MSG_ERROR, "%s:%d, not able to write whole data", __func__, + __LINE__); + return NULL; + } + + struct wpabuf *out = wpabuf_alloc_copy(buf, ret); + + return out; +} + +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) +{ + if (conn && conn->tls) { + mbedtls_ssl_session *session = NULL; + + // If we have a session, then its resumed + mbedtls_ssl_get_session(&conn->tls->ssl, session); + + if (session) { + return 1; + } + } + + return 0; +} + +/* cipher array should contain cipher number in mbedtls num as per IANA + * Please see cipherlist is u8, therefore only initial ones are supported */ +int tls_connection_set_cipher_list( + void *tls_ctx, struct tls_connection *conn, u8 *ciphers) +{ + int i = 0; + + while (*ciphers != 0 && i < MAX_CIPHERSUITE) { + conn->tls->ciphersuite[i] = ciphers[i]; + i++; + } + return 0; +} + +int tls_get_version( + void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen) +{ + const char *name; + + if (conn == NULL) { + return -1; + } + + name = mbedtls_ssl_get_version(&conn->tls->ssl); + if (name == NULL) { + return -1; + } + + os_strlcpy(buf, name, buflen); + + return 0; +} + +int tls_get_library_version(char *buf, size_t buf_len) +{ + + return os_snprintf(buf, buf_len, "MbedTLS build=test run=test"); +} + +// Lifted from https://stackoverflow.com/a/47117431 +char *strremove(char *str, const char *sub) +{ + char *p, *q, *r; + if (*sub && (q = r = os_strstr(str, sub)) != NULL) { + size_t len = os_strlen(sub); + while ((r = os_strstr(p = r + len, sub)) != NULL) { + os_memmove(q, p, r - p); + q += r - p; + } + os_memmove(q, p, strlen(p) + 1); + } + return str; +} + +// Lifted from: https://stackoverflow.com/a/779960 +// You must free the result if result is non-NULL. +char *str_replace(char *orig, char *rep, char *with) +{ + char *result; // the return string + char *ins; // the next insert point + char *tmp; // varies + int len_rep; // length of rep (the string to remove) + int len_with; // length of with (the string to replace rep with) + int len_front; // distance between rep and end of last rep + int count; // number of replacements + + // sanity checks and initialization + if (!orig || !rep) + return NULL; + len_rep = strlen(rep); + if (len_rep == 0) + return NULL; // empty rep causes infinite loop during count + if (!with) + with = ""; + len_with = strlen(with); + + // count the number of replacements needed + ins = orig; + for (count = 0; (tmp = strstr(ins, rep)); ++count) { + ins = tmp + len_rep; + } + + tmp = result = os_zalloc(strlen(orig) + (len_with - len_rep) * count + 1); + + if (!result) + return NULL; + + // first time through the loop, all the variable are set correctly + // from here on, + // tmp points to the end of the result string + // ins points to the next occurrence of rep in orig + // orig points to the remainder of orig after "end of rep" + while (count--) { + ins = strstr(orig, rep); + len_front = ins - orig; + tmp = strncpy(tmp, orig, len_front) + len_front; + tmp = strcpy(tmp, with) + len_with; + orig += len_front + len_rep; // move to next "end of rep" + } + strcpy(tmp, orig); + return result; +} + +int tls_get_cipher( + void *tls_ctx, struct tls_connection *conn, char *buf, size_t buflen) +{ + const char *name; + if (conn == NULL) { + return -1; + } + + name = mbedtls_ssl_get_ciphersuite(&conn->tls->ssl); + if (name == NULL) { + return -1; + } + + os_strlcpy(buf, name, buflen); + + // Translate to common format for hwsim tests to pass + strremove(buf, "TLS-"); + strremove(buf, "WITH-"); + char *tmp = str_replace(buf, "AES-", "AES"); + os_memcpy(buf, tmp, buflen); + os_free(tmp); + + return 0; +} + +int tls_connection_enable_workaround(void *tls_ctx, struct tls_connection *conn) +{ + return -1; +} + +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + +int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn) +{ + return 0; +} + +void tls_connection_set_success_data( + struct tls_connection *conn, struct wpabuf *data) +{} + +void tls_connection_set_success_data_resumed(struct tls_connection *conn) {} + +const struct wpabuf * +tls_connection_get_success_data(struct tls_connection *conn) +{ + return NULL; +} + +void tls_connection_remove_session(struct tls_connection *conn) {} + +char *tls_connection_peer_serial_num(void *tls_ctx, struct tls_connection *conn) +{ + return NULL; +} + +int tls_connection_set_params( + void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params) +{ + int ret = 0; + + wpa_printf( + MSG_ERROR, " client_cert 4is %s, %p", params->client_cert, params); + + tls_context_t *tls = (tls_context_t *)os_zalloc(sizeof(tls_context_t)); + + if (!tls) { + wpa_printf(MSG_ERROR, "failed to allocate tls context"); + return -1; + } + if (!params) { + wpa_printf(MSG_ERROR, "configuration is null"); + ret = -1; + goto err; + } + // assert(params->client_cert != NULL); + + ret = tls_create_mbedtls_handle(params, tls); + if (ret < 0) { + wpa_printf(MSG_ERROR, "failed to create ssl handle"); + goto err; + } + mbedtls_ssl_set_bio( + &tls->ssl, conn, tls_mbedtls_write, tls_mbedtls_read, NULL); + conn->tls = (tls_context_t *)tls; + + mbedtls_ssl_set_export_keys_cb( + &conn->tls->ssl, tls_connection_export_keys_cb, conn); + + return ret; +err: + os_free(tls); + return ret; +} + +int tls_global_set_params( + void *tls_ctx, const struct tls_connection_params *params) +{ + wpa_printf(MSG_INFO, "TLS: Global parameters not supported"); + return -1; +} + +int tls_connection_set_session_ticket_cb( + void *tls_ctx, struct tls_connection *conn, tls_session_ticket_cb cb, + void *ctx) +{ + wpa_printf(MSG_ERROR, "TLS: %s not supported", __func__); + return -1; +} + +void tls_connection_export_keys_cb( + void *p_expkey, mbedtls_ssl_key_export_type secret_type, + const unsigned char *secret, size_t secret_len, + const unsigned char client_random[32], + const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type) + +{ + struct tls_connection *conn = p_expkey; + + os_memcpy(conn->randbytes, client_random, TLS_RANDOM_LEN); + os_memcpy( + conn->randbytes + TLS_RANDOM_LEN, server_random, TLS_RANDOM_LEN); + os_memcpy(conn->master_secret, secret, secret_len); + conn->tls_prf_type = tls_prf_type; +} +static int tls_connection_prf( + void *tls_ctx, struct tls_connection *conn, const char *label, + int server_random_first, u8 *out, size_t out_len) +{ + int ret = 0; + u8 seed[2 * TLS_RANDOM_LEN]; + mbedtls_ssl_context *ssl = &conn->tls->ssl; + + if (!ssl || !conn) { + wpa_printf( + MSG_ERROR, "TLS: %s, connection info is null", __func__); + return -1; + } + if (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) { + wpa_printf( + MSG_ERROR, "TLS: %s, incorrect tls state=%d", __func__, + ssl->MBEDTLS_PRIVATE(state)); + return -1; + } + + if (server_random_first) { + os_memcpy( + seed, conn->randbytes + TLS_RANDOM_LEN, TLS_RANDOM_LEN); + os_memcpy( + seed + TLS_RANDOM_LEN, conn->randbytes, TLS_RANDOM_LEN); + } else { + os_memcpy(seed, conn->randbytes, 2 * TLS_RANDOM_LEN); + } + + wpa_hexdump_key(MSG_MSGDUMP, "random", seed, 2 * TLS_RANDOM_LEN); + wpa_hexdump_key( + MSG_MSGDUMP, "master", conn->master_secret, TLS_MASTER_SECRET_LEN); + + if (conn->tls_prf_type == MBEDTLS_SSL_TLS_PRF_SHA384) { + ret = tls_prf_sha384( + conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, + 2 * TLS_RANDOM_LEN, out, out_len); + } else if (conn->tls_prf_type == MBEDTLS_SSL_TLS_PRF_SHA256) { + ret = tls_prf_sha256( + conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, + 2 * TLS_RANDOM_LEN, out, out_len); + } else { + ret = tls_prf_sha1_md5( + conn->master_secret, TLS_MASTER_SECRET_LEN, label, seed, + 2 * TLS_RANDOM_LEN, out, out_len); + } + + if (ret < 0) { + wpa_printf(MSG_ERROR, "prf failed, ret=%d\n", ret); + } + wpa_hexdump_key(MSG_MSGDUMP, "key", out, out_len); + + return ret; +} + +int tls_connection_export_key( + void *tls_ctx, struct tls_connection *conn, const char *label, + const u8 *context, size_t context_len, u8 *out, size_t out_len) +{ + return tls_connection_prf(tls_ctx, conn, label, 0, out, out_len); +} + +int tls_connection_get_eap_fast_key( + void *tls_ctx, struct tls_connection *conn, u8 *out, size_t out_len) +{ + wpa_printf( + MSG_INFO, "TLS: tls_connection_get_eap_fast_key not supported, " + "please unset mbedtls crypto and try again"); + return -1; +} + +int tls_connection_client_hello_ext( + void *tls_ctx, struct tls_connection *conn, int ext_type, const u8 *data, + size_t data_len) +{ + wpa_printf( + MSG_INFO, "TLS: tls_connection_client_hello_ext not supported, " + "please unset mbedtls crypto and try again"); + return -1; +} + +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) +{ + if (conn->tls_io_data.in_data) { + wpabuf_free(conn->tls_io_data.in_data); + } + conn->tls_io_data.in_data = NULL; + + /* outdata may have dangling pointer */ + conn->tls_io_data.out_data = NULL; + + return mbedtls_ssl_session_reset(&conn->tls->ssl); +} + +int tls_connection_get_random( + void *tls_ctx, struct tls_connection *conn, struct tls_random *data) +{ + mbedtls_ssl_context *ssl = &conn->tls->ssl; + + os_memset(data, 0, sizeof(*data)); + if (ssl->MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_CLIENT_HELLO) { + return -1; + } + + data->client_random = conn->randbytes; + data->client_random_len = TLS_RANDOM_LEN; + + if (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_SERVER_HELLO) { + data->server_random = conn->randbytes + TLS_RANDOM_LEN; + data->server_random_len = TLS_RANDOM_LEN; + } + + return 0; +} diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 4b86d8fc6..21f8efa29 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2328,6 +2328,13 @@ struct wpa_signal_info { int center_frq2; }; + +struct wpa_conn_info { + unsigned short beacon_interval; + unsigned char dtim_period; +}; + + /** * struct wpa_channel_info - Information about the current channel * @frequency: Center frequency of the primary 20 MHz channel @@ -3786,6 +3793,13 @@ struct wpa_driver_ops { */ int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info); + /** + * beacon_poll - Get beacon info of current SSID + * @priv: Private driver interface data + * @beacon_info: Beacon info structure + */ + int (*get_conn_info)(void *priv, struct wpa_conn_info *conn_info); + /** * channel_info - Get parameters of the current operating channel * @priv: Private driver interface data @@ -6167,5 +6181,9 @@ extern const struct wpa_driver_ops wpa_driver_atheros_ops; #ifdef CONFIG_DRIVER_NONE extern const struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ #endif /* CONFIG_DRIVER_NONE */ +#ifdef CONFIG_ZEPHYR +extern const struct wpa_driver_ops wpa_driver_zep_ops; /* driver_zephyr.c */ +#endif /* CONFIG_ZEPHYR */ + #endif /* DRIVER_H */ diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 80d456472..597a926ea 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -105,10 +105,10 @@ struct wpa_driver_nl80211_data { u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; struct drv_nl80211_ext_capa { - enum nl80211_iftype iftype; + enum nrf_wifi_iftype iftype; u8 *ext_capa, *ext_capa_mask; unsigned int ext_capa_len; - } iface_ext_capa[NL80211_IFTYPE_MAX]; + } iface_ext_capa[NRF_WIFI_IFTYPE_MAX]; unsigned int num_iface_ext_capa; int has_capability; diff --git a/src/drivers/driver_zephyr.c b/src/drivers/driver_zephyr.c new file mode 100644 index 000000000..1aa34d224 --- /dev/null +++ b/src/drivers/driver_zephyr.c @@ -0,0 +1,1436 @@ +/* + * Driver interaction with Zephyr WLAN device drivers. + * Copyright (c) 2022, Nordic Semiconductor + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include + +#include "includes.h" +#include "utils/common.h" +#include "eloop.h" +#include "driver_zephyr.h" +#include "supp_main.h" +#include "common/ieee802_11_common.h" + +#define SCAN_TIMEOUT 30 +#define GET_WIPHY_TIMEOUT 10 + +void wpa_supplicant_event_wrapper(void *ctx, + enum wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_supplicant_event_msg msg = { 0 }; + + msg.ctx = ctx; + msg.event = event; + if (data) { + msg.data = os_zalloc(sizeof(*data)); + if (!msg.data) { + wpa_printf(MSG_ERROR, "Failed to allocated for event: %d", event); + return; + } + os_memcpy(msg.data, data, sizeof(*data)); + if (event == EVENT_AUTH) { + union wpa_event_data *data_tmp = msg.data; + + if (data->auth.ies) { + char *ies = os_zalloc(data->auth.ies_len); + + if (!ies) { + wpa_printf(MSG_ERROR, "%s: Failed to alloc ies\n", __func__); + return; + } + + os_memcpy(ies, data->auth.ies, data->auth.ies_len); + data_tmp->auth.ies = ies; + } + } + } + z_wpas_send_event(&msg); +} + +void wpa_drv_zep_event_mac_changed(struct zep_drv_if_ctx *if_ctx) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_INTERFACE_MAC_CHANGED, + NULL); +} + +static int wpa_drv_zep_abort_scan(void *priv, + u64 scan_cookie) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->scan_abort) { + wpa_printf(MSG_ERROR, + "%s: No op registered for scan_abort\n", + __func__); + goto out; + } + + ret = dev_ops->scan_abort(if_ctx->dev_priv); +out: + return ret; +} + + +/** + * wpa_drv_zep_scan_timeout - Scan timeout to report scan completion + * @eloop_ctx: Driver private data + * @timeout_ctx: ctx argument given to wpa_drv_zep_init() + * + * This function can be used as registered timeout when starting a scan to + * generate a scan completed event if the driver does not report this. + */ +void wpa_drv_zep_scan_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + + if_ctx = eloop_ctx; + + wpa_printf(MSG_ERROR, + "%s: Scan timeout - try to abort it\n", + __func__); + + if (wpa_drv_zep_abort_scan(if_ctx, 0) == 0) { + return; + } +} + + +void wpa_drv_zep_event_proc_scan_start(struct zep_drv_if_ctx *if_ctx) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_SCAN_STARTED, + NULL); +} + + +void wpa_drv_zep_event_proc_scan_done(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event) +{ + eloop_cancel_timeout(wpa_drv_zep_scan_timeout, + if_ctx, + if_ctx->supp_if_ctx); + + if_ctx->scan_res2_get_in_prog = false; + k_sem_give(&if_ctx->drv_resp_sem); + + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_SCAN_RESULTS, + event); +} + + +void wpa_drv_zep_event_proc_scan_res(struct zep_drv_if_ctx *if_ctx, + struct wpa_scan_res *r, + bool more_res) +{ + struct wpa_scan_res **tmp = NULL; + size_t scan_res_len = sizeof(struct wpa_scan_res) + r->ie_len + r->beacon_ie_len; + + if (!if_ctx->scan_res2) + return; + + tmp = os_realloc_array(if_ctx->scan_res2->res, + if_ctx->scan_res2->num + 1, + sizeof(struct wpa_scan_res *)); + + if (!tmp) { + wpa_printf(MSG_ERROR, "%s: Failed to realloc scan result array\n", __func__); + goto err; + } + + struct wpa_scan_res *sr = os_zalloc(scan_res_len); + if (!sr) { + wpa_printf(MSG_ERROR, "%s: Failed to alloc scan results(%d bytes)\n", __func__, scan_res_len); + goto err; + } + + os_memcpy(sr, r, scan_res_len); + + tmp[if_ctx->scan_res2->num++] = sr; + + if_ctx->scan_res2->res = tmp; + +err: + if (!more_res) { + if_ctx->scan_res2_get_in_prog = false; + k_sem_give(&if_ctx->drv_resp_sem); + } +} + + +void wpa_drv_zep_event_proc_auth_resp(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_AUTH, + event); +} + + +void wpa_drv_zep_event_proc_assoc_resp(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event, + unsigned int status) +{ + if (status != WLAN_STATUS_SUCCESS) { + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_ASSOC_REJECT, + event); + } else { + if_ctx->associated = true; + + os_memcpy(if_ctx->bssid, + event->assoc_info.addr, + ETH_ALEN); + + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_ASSOC, + event); + } +} + + +void wpa_drv_zep_event_proc_deauth(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event, const struct ieee80211_mgmt *mgmt) +{ + const u8 *bssid = NULL; + + bssid = mgmt->bssid; + + if ((if_ctx->capa.flags & WPA_DRIVER_FLAGS_SME) && + !if_ctx->associated && + os_memcmp(bssid, if_ctx->auth_bssid, ETH_ALEN) != 0 && + os_memcmp(bssid, if_ctx->auth_attempt_bssid, ETH_ALEN) != 0 && + os_memcmp(bssid, if_ctx->prev_bssid, ETH_ALEN) == 0) + { + /* + * Avoid issues with some roaming cases where + * disconnection event for the old AP may show up after + * we have started connection with the new AP. + * In case of locally generated event clear + * ignore_next_local_deauth as well, to avoid next local + * deauth event be wrongly ignored. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR, + MAC2STR(bssid), + MAC2STR(if_ctx->auth_attempt_bssid)); + return; + } + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_DEAUTH, + event); +} + + +void wpa_drv_zep_event_proc_disassoc(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_DISASSOC, + event); +} + +static void wpa_drv_zep_event_mgmt_tx_status(struct zep_drv_if_ctx *if_ctx, + const u8 *frame, size_t len, bool ack) +{ + union wpa_event_data event; + const struct ieee80211_hdr *hdr; + u16 fc; + + wpa_printf(MSG_DEBUG, "wpa_supp: Frame TX status event"); + + hdr = (const struct ieee80211_hdr *) frame; + fc = le_to_host16(hdr->frame_control); + + os_memset(&event, 0, sizeof(event)); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = frame; + event.tx_status.data_len = len; + event.tx_status.ack = ack; + + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_TX_STATUS, + &event); +} + +static void wpa_drv_zep_event_proc_unprot_deauth(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_UNPROT_DEAUTH, + event); +} + +static void wpa_drv_zep_event_proc_unprot_disassoc(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event) +{ + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, + EVENT_UNPROT_DISASSOC, + event); +} + +struct phy_info_arg { + u16 *num_modes; + struct hostapd_hw_modes *modes; + int last_mode, last_chan_idx; + int failed; + u8 dfs_domain; +}; + +static void phy_info_freq_cfg(struct hostapd_hw_modes *mode, + struct hostapd_channel_data *chan, + struct wpa_supp_event_channel *chnl_info) +{ + u8 channel = 0; + + chan->freq = chnl_info->center_frequency; + chan->flag = 0; + chan->allowed_bw = ~0; + chan->dfs_cac_ms = 0; + + if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES) { + chan->chan = channel; + } + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_DISABLED) + chan->flag |= HOSTAPD_CHAN_DISABLED; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_IR) + chan->flag |= HOSTAPD_CHAN_NO_IR; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_RADAR) + chan->flag |= HOSTAPD_CHAN_RADAR; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_INDOOR_ONLY) + chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_GO_CONCURRENT) + chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_10MHZ) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_10; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_20MHZ) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_20; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_HT40_PLUS) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40P; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_HT40_MINUS) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40M; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_80MHZ) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_80; + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_160MHZ) + chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_160; + + if (chnl_info->wpa_supp_flags & WPA_SUPP_CHAN_DFS_CAC_TIME_VALID) { + chan->dfs_cac_ms = (chnl_info->wpa_supp_time); + } + + /* Other elements are not present */ + chan->wmm_rules_valid = 0; + chan->wmm_rules_valid = 0; +} + + +static int phy_info_freqs_cfg(struct phy_info_arg *phy_info, + struct hostapd_hw_modes *mode, + struct wpa_supp_event_supported_band *band_info) +{ + int new_channels = 0; + struct hostapd_channel_data *channel = NULL; + int idx; + + if (!phy_info || !mode || !band_info) + return -1; + + new_channels = band_info->wpa_supp_n_channels; + + if (!new_channels) + return 0; + + channel = os_realloc_array(mode->channels, + mode->num_channels + new_channels, + sizeof(struct hostapd_channel_data)); + + if (!channel) + return -1; + + mode->channels = channel; + mode->num_channels += new_channels; + + idx = phy_info->last_chan_idx; + + for (int i = 0; i < new_channels; i++) { + phy_info_freq_cfg(mode, &mode->channels[idx], &band_info->channels[i]); + idx++; + } + + phy_info->last_chan_idx = idx; + + return 0; +} + +static int phy_info_rates_cfg(struct hostapd_hw_modes *mode, + struct wpa_supp_event_supported_band *band_info) +{ + int idx; + + if (!mode || !band_info) + return -1; + + mode->num_rates = band_info->wpa_supp_n_bitrates; + + if (!mode->num_rates) + return 0; + + mode->rates = os_calloc(mode->num_rates, sizeof(int)); + + if (!mode->rates) + return -1; + + idx = 0; + + for (int i = 0; i < mode->num_rates; i++) { + if (!band_info->bitrates[i].wpa_supp_bitrate) + continue; + mode->rates[idx] = band_info->bitrates[i].wpa_supp_bitrate; + idx++; + } + + return 0; +} + + + +static void phy_info_ht_capa_cfg(struct hostapd_hw_modes *mode, u16 capa, + u8 ampdu_factor, + u8 ampdu_density, + struct wpa_supp_event_mcs_info *mcs_set) +{ + if (capa) + mode->ht_capab = (capa); + + if (ampdu_factor) + mode->a_mpdu_params |= (ampdu_factor) & WPA_SUPP_AMPDU_FACTOR_MASK; + + if (ampdu_density) + mode->a_mpdu_params |= (ampdu_density) << WPA_SUPP_AMPDU_DENSITY_SHIFT; + + if (mcs_set) { + os_memcpy(mode->mcs_set, mcs_set, sizeof(*mcs_set)); + } + +} + +static void phy_info_vht_capa_cfg(struct hostapd_hw_modes *mode, + unsigned int capa, + struct wpa_supp_event_vht_mcs_info *vht_mcs_set) +{ + if (capa) + mode->vht_capab = (capa); + + if (vht_mcs_set) { + os_memcpy(mode->vht_mcs_set, vht_mcs_set, 8); + } +} + +static int phy_info_band_cfg(struct phy_info_arg *phy_info, + struct wpa_supp_event_supported_band *band_info) +{ + struct hostapd_hw_modes *mode; + int ret; + + if (phy_info->last_mode != band_info->band) { + mode = os_realloc_array(phy_info->modes, + *phy_info->num_modes + 1, + sizeof(*mode)); + + if (!mode) { + phy_info->failed = 1; + return -1; + } + + phy_info->modes = mode; + + mode = &phy_info->modes[*(phy_info->num_modes)]; + + os_memset(mode, 0, sizeof(*mode)); + + mode->mode = NUM_HOSTAPD_MODES; + mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN | + HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN; + + /* + * Unsupported VHT MCS stream is defined as value 3, so the VHT + * MCS RX/TX map must be initialized with 0xffff to mark all 8 + * possible streams as unsupported. This will be overridden if + * driver advertises VHT support. + */ + mode->vht_mcs_set[0] = 0xff; + mode->vht_mcs_set[1] = 0xff; + mode->vht_mcs_set[4] = 0xff; + mode->vht_mcs_set[5] = 0xff; + + *(phy_info->num_modes) += 1; + + phy_info->last_mode = band_info->band; + phy_info->last_chan_idx = 0; + } + else + mode = &phy_info->modes[*(phy_info->num_modes) - 1]; + + phy_info_ht_capa_cfg(mode, band_info->ht_cap.wpa_supp_cap, + band_info->ht_cap.wpa_supp_ampdu_factor, + band_info->ht_cap.wpa_supp_ampdu_density, + &band_info->ht_cap.mcs); + + phy_info_vht_capa_cfg(mode, band_info->vht_cap.wpa_supp_cap, + &band_info->vht_cap.vht_mcs); + + ret = phy_info_freqs_cfg(phy_info, mode, band_info); + + if (ret == 0) + ret = phy_info_rates_cfg(mode, band_info); + + if (ret != 0) { + phy_info->failed = 1; + return ret; + } + + return 0; +} + +static void wpa_drv_zep_event_get_wiphy(struct zep_drv_if_ctx *if_ctx, void *band_info) +{ + if (!band_info) { + /* Done with all bands */ + k_sem_give(&if_ctx->drv_resp_sem); + return; + } + + phy_info_band_cfg(if_ctx->phy_info_arg, band_info); +} + +static int wpa_drv_register_frame(struct zep_drv_if_ctx *if_ctx, + u16 type, const u8 *match, size_t match_len, + bool multicast) +{ + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->register_frame) + return -1; + + return dev_ops->register_frame(if_ctx->dev_priv, type, match, match_len, false); +} + +static int wpa_drv_register_action_frame(struct zep_drv_if_ctx *if_ctx, + const u8 *match, size_t match_len) +{ + u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); + + return wpa_drv_register_frame(if_ctx, type, match, match_len, false); +} + +static int wpa_drv_mgmt_subscribe_non_ap(struct zep_drv_if_ctx *if_ctx) +{ + int ret = 0; + + /* WNM - BSS Transition Management Request */ + if (wpa_drv_register_action_frame(if_ctx, (u8 *)"\x0a\x07", 2) < 0) + ret = -1; + + /* Radio Measurement - Neighbor Report Response */ + if (wpa_drv_register_action_frame(if_ctx, (u8 *)"\x05\x05", 2) < 0) + ret = -1; + + /* Radio Measurement - Radio Measurement Request */ + if (wpa_drv_register_action_frame(if_ctx, (u8 *)"\x05\x00", 2) < 0) + ret = -1; + + return ret; +} + +static void wpa_drv_zep_event_mgmt_rx(struct zep_drv_if_ctx *if_ctx, + char *frame, int frame_len, + int frequency, int rx_signal_dbm) +{ + const struct ieee80211_mgmt *mgmt; + + union wpa_event_data event; + u16 fc, stype; + int rx_freq = 0; + + wpa_printf(MSG_MSGDUMP, "wpa_supp: Frame event"); + mgmt = (const struct ieee80211_mgmt *)frame; + + if (frame_len < 24) { + wpa_printf(MSG_DEBUG, "wpa_supp: Too short management frame"); + return; + } + + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + + os_memset(&event, 0, sizeof(event)); + + if (frequency) { + event.rx_mgmt.freq = frequency; + rx_freq = event.rx_mgmt.freq; + } + + event.rx_mgmt.frame = frame; + event.rx_mgmt.frame_len = frame_len; + event.rx_mgmt.ssi_signal = rx_signal_dbm; + + wpa_supplicant_event_wrapper(if_ctx->supp_if_ctx, EVENT_RX_MGMT, &event); +} + +static struct hostapd_hw_modes * +wpa_driver_wpa_supp_postprocess_modes(struct hostapd_hw_modes *modes, + u16 *num_modes) +{ + u16 m; + struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; + int i, mode11g_idx = -1; + + /* heuristic to set up modes */ + for (m = 0; m < *num_modes; m++) { + if (!modes[m].num_channels) + continue; + if (modes[m].channels[0].freq < 4000) { + modes[m].mode = HOSTAPD_MODE_IEEE80211B; + for (i = 0; i < modes[m].num_rates; i++) { + if (modes[m].rates[i] > 200) { + modes[m].mode = HOSTAPD_MODE_IEEE80211G; + break; + } + } + } else if (modes[m].channels[0].freq > 50000) + modes[m].mode = HOSTAPD_MODE_IEEE80211AD; + else + modes[m].mode = HOSTAPD_MODE_IEEE80211A; + } + + /* If only 802.11g mode is included, use it to construct matching + * 802.11b mode data. */ + + for (m = 0; m < *num_modes; m++) { + if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) + return modes; /* 802.11b already included */ + if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) + mode11g_idx = m; + } + + if (mode11g_idx < 0) + return modes; /* 2.4 GHz band not supported at all */ + + nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes)); + if (nmodes == NULL) + return modes; /* Could not add 802.11b mode */ + + mode = &nmodes[*num_modes]; + os_memset(mode, 0, sizeof(*mode)); + (*num_modes)++; + modes = nmodes; + + mode->mode = HOSTAPD_MODE_IEEE80211B; + mode11g = &modes[mode11g_idx]; + mode->num_channels = mode11g->num_channels; + mode->channels = os_memdup(mode11g->channels, + mode11g->num_channels * + sizeof(struct hostapd_channel_data)); + if (mode->channels == NULL) { + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + + mode->num_rates = 0; + mode->rates = os_malloc(4 * sizeof(int)); + if (mode->rates == NULL) { + os_free(mode->channels); + (*num_modes)--; + return modes; /* Could not add 802.11b mode */ + } + + for (i = 0; i < mode11g->num_rates; i++) { + if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && + mode11g->rates[i] != 55 && mode11g->rates[i] != 110) + continue; + mode->rates[mode->num_rates] = mode11g->rates[i]; + mode->num_rates++; + if (mode->num_rates == 4) + break; + } + + if (mode->num_rates == 0) { + os_free(mode->channels); + os_free(mode->rates); + (*num_modes)--; + return modes; /* No 802.11b rates */ + } + + wpa_printf(MSG_DEBUG, "wpa_supp: Added 802.11b mode based on 802.11g " + "information"); + + return modes; +} + +struct hostapd_hw_modes *wpa_drv_get_hw_feature_data(void *priv, + u16 *num_modes, + u16 *flags, u8 *dfs_domain) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + struct phy_info_arg result = { + .num_modes = num_modes, + .modes = NULL, + .last_mode = -1, + .failed = 0, + .dfs_domain = 0, + }; + + *num_modes = 0; + *flags = 0; + *dfs_domain = 0; + + if_ctx->phy_info_arg = &result; + + ret = dev_ops->get_wiphy(if_ctx->dev_priv); + if (ret < 0) { + return NULL; + } + + k_sem_reset(&if_ctx->drv_resp_sem); + k_sem_take(&if_ctx->drv_resp_sem, K_SECONDS(GET_WIPHY_TIMEOUT)); + + if (!result.modes) { + return NULL; + } + + struct hostapd_hw_modes *modes; + + *dfs_domain = result.dfs_domain; + + modes = wpa_driver_wpa_supp_postprocess_modes(result.modes, + num_modes); + + return modes; +} + +static void *wpa_drv_zep_global_init(void *ctx) +{ + struct zep_drv_ctx *drv_ctx = NULL; + + drv_ctx = os_zalloc(sizeof(*drv_ctx)); + + if (!drv_ctx) { + return NULL; + } + + drv_ctx->supp_ctx = ctx; + + return drv_ctx; +} + + +static void wpa_drv_zep_global_deinit(void *priv) +{ + struct zep_drv_ctx *drv_ctx = priv; + + if (!drv_ctx) { + return; + } + + os_free(drv_ctx); +} + + +/** + * wpa_driver_zep_init - Initialize Zephyr driver interface + * @ctx: Context to be used when calling wpa_supplicant functions, + * e.g., wpa_supplicant_event_wrapper() + * @ifname: Interface name, e.g., wlan0 + * @global_priv: private driver global data from global_init() + * + * Returns: Pointer to private data, %NULL on failure + */ +static void *wpa_drv_zep_init(void *ctx, + const char *ifname, + void *global_priv) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + const struct device *device = NULL; + struct zep_wpa_supp_dev_callbk_fns callbk_fns; + + device = device_get_binding(ifname); + + if (!device) { + wpa_printf(MSG_ERROR, "%s: Interface %s not found\n", __func__, ifname); + goto out; + } + + if_ctx = os_zalloc(sizeof(*if_ctx)); + + if (if_ctx == NULL) { + goto out; + } + + if_ctx->supp_if_ctx = ctx; + + if_ctx->dev_ctx = device; + if_ctx->drv_ctx = global_priv; + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->init) { + wpa_printf(MSG_ERROR, + "%s: No op registered for init\n", + __func__); + os_free(if_ctx); + if_ctx = NULL; + goto out; + } + + os_memset(&callbk_fns, + 0, + sizeof(callbk_fns)); + + callbk_fns.scan_start = wpa_drv_zep_event_proc_scan_start; + callbk_fns.scan_done = wpa_drv_zep_event_proc_scan_done; + callbk_fns.scan_res = wpa_drv_zep_event_proc_scan_res; + callbk_fns.auth_resp = wpa_drv_zep_event_proc_auth_resp; + callbk_fns.assoc_resp = wpa_drv_zep_event_proc_assoc_resp; + callbk_fns.deauth = wpa_drv_zep_event_proc_deauth; + callbk_fns.disassoc = wpa_drv_zep_event_proc_disassoc; + callbk_fns.mgmt_tx_status = wpa_drv_zep_event_mgmt_tx_status; + callbk_fns.unprot_deauth = wpa_drv_zep_event_proc_unprot_deauth; + callbk_fns.unprot_disassoc = wpa_drv_zep_event_proc_unprot_disassoc; + callbk_fns.get_wiphy_res = wpa_drv_zep_event_get_wiphy; + callbk_fns.mgmt_rx = wpa_drv_zep_event_mgmt_rx; + callbk_fns.mac_changed = wpa_drv_zep_event_mac_changed; + + if_ctx->dev_priv = dev_ops->init(if_ctx, + ifname, + &callbk_fns); + + if (!if_ctx->dev_priv) { + wpa_printf(MSG_ERROR, + "%s: Failed to initialize the interface\n", + __func__); + os_free(if_ctx); + if_ctx = NULL; + goto out; + } + + k_sem_init(&if_ctx->drv_resp_sem, 0, 1); + + wpa_drv_mgmt_subscribe_non_ap(if_ctx); + +out: + return if_ctx; +} + + +static void wpa_drv_zep_deinit(void *priv) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->deinit) { + wpa_printf(MSG_ERROR, "%s: No op registered for deinit\n", __func__); + return; + } + + dev_ops->deinit(if_ctx->dev_priv); + + os_free(if_ctx); +} + + +static int wpa_drv_zep_scan2(void *priv, struct wpa_driver_scan_params *params) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int timeout = 0; + int ret = -1; + + if (!priv || !params) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + + if (if_ctx->scan_res2_get_in_prog) { + wpa_printf(MSG_ERROR, "%s: Scan is already in progress\n", __func__); + goto out; + } + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->scan2) { + wpa_printf(MSG_ERROR, "%s: No op registered for scan2\n", __func__); + goto out; + } + + ret = dev_ops->scan2(if_ctx->dev_priv, params); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: scan2 op failed\n", __func__); + goto out; + } + + /* The driver delivers events to notify when scan is + * complete, so use longer timeout to avoid race conditions + * with scanning and following association request. + */ + timeout = SCAN_TIMEOUT; + + wpa_printf(MSG_DEBUG, + "%s: Scan requested - scan timeout %d seconds\n", + __func__, + timeout); + + eloop_cancel_timeout(wpa_drv_zep_scan_timeout, + if_ctx, + if_ctx->supp_if_ctx); + + eloop_register_timeout(timeout, + 0, + wpa_drv_zep_scan_timeout, + if_ctx, + if_ctx->supp_if_ctx); + + ret = 0; + +out: + return ret; +} + + +/** + * wpa_drv_zep_get_scan_results2 - Fetch the latest scan results + * @priv: Pointer to private data from wpa_drv_zep_init() + * Returns: Scan results on success, -1 on failure + */ +struct wpa_scan_results *wpa_drv_zep_get_scan_results2(void *priv) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if (!priv) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->get_scan_results2) { + wpa_printf(MSG_ERROR, + "%s: No op registered for scan2\n", + __func__); + goto out; + } + + if_ctx->scan_res2 = os_zalloc(sizeof(*if_ctx->scan_res2)); + + if (!if_ctx->scan_res2) { + wpa_printf(MSG_ERROR, "%s: Failed to alloc memory for scan results\n", __func__); + goto out; + } + + ret = dev_ops->get_scan_results2(if_ctx->dev_priv); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: get_scan_results2 op failed\n", __func__); + goto out; + } + + if_ctx->scan_res2_get_in_prog = true; + + k_sem_reset(&if_ctx->drv_resp_sem); + k_sem_take(&if_ctx->drv_resp_sem, K_SECONDS(SCAN_TIMEOUT)); + + if (if_ctx->scan_res2_get_in_prog) { + wpa_printf(MSG_ERROR, "%s: Timed out waiting for scan results\n", __func__); + ret = -1; + goto out; + } + + ret = 0; +out: + if (ret == -1) { + if (if_ctx->scan_res2) { + wpa_scan_results_free(if_ctx->scan_res2); + if_ctx->scan_res2 = NULL; + } + } + + return if_ctx->scan_res2; +} + + +static int wpa_drv_zep_deauthenticate(void *priv, const u8 *addr, + u16 reason_code) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if ((!priv) || (!addr)) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + ret = dev_ops->deauthenticate(if_ctx->dev_priv, addr, reason_code); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: deauthenticate op failed\n", __func__); + goto out; + } + + ret = 0; +out: + return ret; +} + + +static int wpa_drv_zep_authenticate(void *priv, + struct wpa_driver_auth_params *params) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + struct wpa_bss *curr_bss; + int ret = -1; + + if ((!priv) || (!params)) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + os_memcpy(if_ctx->ssid, + params->ssid, + params->ssid_len); + + if_ctx->ssid_len = params->ssid_len; + + curr_bss = wpa_bss_get(if_ctx->supp_if_ctx, params->bssid, params->ssid, params->ssid_len); + + if (!curr_bss) { + wpa_printf(MSG_ERROR, "%s: Failed to get BSS", __func__); + ret = -1; + goto out; + } + + if (params->bssid) + os_memcpy(if_ctx->auth_attempt_bssid, params->bssid, ETH_ALEN); + + if (if_ctx->associated) + os_memcpy(if_ctx->prev_bssid, if_ctx->bssid, ETH_ALEN); + + os_memset(if_ctx->auth_bssid, 0, ETH_ALEN); + + if_ctx->associated = false; + + ret = dev_ops->authenticate(if_ctx->dev_priv, + params, + curr_bss); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: authenticate op failed\n", __func__); + goto out; + } + + ret = 0; +out: + return ret; +} + + +static int wpa_drv_zep_associate(void *priv, + struct wpa_driver_associate_params *params) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if ((!priv) || (!params)) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + ret = dev_ops->associate(if_ctx->dev_priv, + params); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: associate op failed\n", __func__); + goto out; + } + + ret = 0; +out: + return ret; +} + + +static int _wpa_drv_zep_set_key(void *priv, + const char *ifname, + enum wpa_alg alg, + const u8 *addr, + int key_idx, + int set_tx, + const u8 *seq, + size_t seq_len, + const u8 *key, + size_t key_len) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if (!priv) { + wpa_printf(MSG_ERROR, "%s: Invalid handle\n", __func__); + goto out; + } + if (alg != WPA_ALG_NONE && !key) { + wpa_printf(MSG_ERROR, "%s: Missing key\n", __func__); + goto out; + } + + if_ctx = priv; + dev_ops = if_ctx->dev_ctx->config; + + wpa_printf(MSG_DEBUG, "%s: priv:%p alg %d addr %p key_idx %d set_tx %d seq %p " + "seq_len %d key %p key_len %d\n", + __func__, + if_ctx->dev_priv, + alg, addr, + key_idx, + set_tx, + seq, + seq_len, + key, + key_len); + + ret = dev_ops->set_key(if_ctx->dev_priv, + ifname, + alg, + addr, + key_idx, + set_tx, + seq, + seq_len, + key, + key_len); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: set_key op failed\n", __func__); + goto out; + } +out: + return ret; +} + + +static int wpa_drv_zep_set_key(void* priv, + struct wpa_driver_set_key_params *params) +{ + return _wpa_drv_zep_set_key(priv, + params->ifname, + params->alg, + params->addr, + params->key_idx, + params->set_tx, + params->seq, + params->seq_len, + params->key, + params->key_len); +} + + +static int wpa_drv_zep_get_capa(void *priv, + struct wpa_driver_capa *capa) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if ((!priv) || (!capa)) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops->get_capa) { + wpa_printf(MSG_ERROR, "%s: get_capa op not supported\n", __func__); + goto out; + } + + ret = dev_ops->get_capa(if_ctx->dev_priv, + capa); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: get_capa op failed\n", __func__); + goto out; + } + + ret = 0; + + if_ctx->capa = *capa; + +out: + return ret; +} + + +static int wpa_drv_zep_get_bssid(void *priv, + u8 *bssid) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + + if_ctx = priv; + + os_memcpy(bssid, + if_ctx->bssid, + ETH_ALEN); + + return 0; +} + + +static int wpa_drv_zep_get_ssid(void *priv, + u8 *ssid) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + + if_ctx = priv; + + wpa_printf(MSG_DEBUG, + "%s: SSID size: %d\n", + __func__, + if_ctx->ssid_len); + + os_memcpy(ssid, + if_ctx->ssid, + if_ctx->ssid_len); + + return if_ctx->ssid_len; +} + + +static int wpa_drv_zep_set_supp_port(void *priv, + int authorized) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + struct net_if *iface = NULL; + + int ret; + + if_ctx = priv; + + dev_ops = if_ctx->dev_ctx->config; + + iface = net_if_lookup_by_dev(if_ctx->dev_ctx); + + ret = dev_ops->set_supp_port(if_ctx->dev_priv, + authorized, + if_ctx->bssid); + +#ifdef CONFIG_NET_DHCPV4 + if (authorized) { + net_dhcpv4_restart(iface); + } +#endif + + return ret; +} + + +static int wpa_drv_zep_signal_poll(void *priv, struct wpa_signal_info *si) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if (!priv) { + wpa_printf(MSG_ERROR, "%s: Invalid handle\n", __func__); + goto out; + } + + if (!si) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + dev_ops = if_ctx->dev_ctx->config; + + os_memset(si, 0, sizeof(*si)); + + if (dev_ops && dev_ops->signal_poll) { + ret = dev_ops->signal_poll(if_ctx->dev_priv, si, if_ctx->bssid); + if (ret) { + wpa_printf(MSG_ERROR, "%s: Signal polling failed: %d\n", __func__, ret); + goto out; + } + } else { + wpa_printf(MSG_ERROR, "%s: Signal polling not supported\n", __func__); + goto out; + } + +out: + return ret; +} + +static int wpa_drv_zep_send_action(void *priv, unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, + const u8 *bssid, + const u8 *data, size_t data_len, + int no_cck) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + u8 *buf; + struct ieee80211_hdr *hdr; + + if_ctx = priv; + dev_ops = if_ctx->dev_ctx->config; + + wpa_printf(MSG_DEBUG, "wpa_supp: Send Action frame (" + "freq=%u MHz wait=%d ms no_cck=%d)", + freq, wait_time, no_cck); + + buf = os_zalloc(24 + data_len); + if (buf == NULL) + return ret; + os_memcpy(buf + 24, data, data_len); + hdr = (struct ieee80211_hdr *)buf; + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); + os_memcpy(hdr->addr1, dst, ETH_ALEN); + os_memcpy(hdr->addr2, src, ETH_ALEN); + os_memcpy(hdr->addr3, bssid, ETH_ALEN); + + + return dev_ops->send_mlme(if_ctx->dev_priv, buf, 24 + data_len, + 0, freq, no_cck, 1, + wait_time, 0); +} + +static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type, + const u8 **ext_capa, const u8 **ext_capa_mask, + unsigned int *ext_capa_len) +{ + struct wpa_driver_capa capa; + + wpa_drv_zep_get_capa(priv, &capa); + + /* By default, use the per-radio values */ + *ext_capa = capa.extended_capa; + *ext_capa_mask = capa.extended_capa_mask; + *ext_capa_len = capa.extended_capa_len; + + return 0; +} + +static int wpa_drv_zep_get_conn_info(void *priv, struct wpa_conn_info *ci) +{ + struct zep_drv_if_ctx *if_ctx = NULL; + const struct zep_wpa_supp_dev_ops *dev_ops = NULL; + int ret = -1; + + if (!priv) { + wpa_printf(MSG_ERROR, "%s: Invalid handle\n", __func__); + goto out; + } + + if (!ci) { + wpa_printf(MSG_ERROR, "%s: Invalid params\n", __func__); + goto out; + } + + if_ctx = priv; + dev_ops = if_ctx->dev_ctx->config; + + if (!dev_ops) { + wpa_printf(MSG_ERROR, "%s:Failed to get config handle\n", __func__); + goto out; + } + + if (dev_ops->get_conn_info) { + ret = dev_ops->get_conn_info(if_ctx->dev_priv, ci); + if (ret) { + wpa_printf(MSG_ERROR, "%s: Failed to get connection info: %d\n", __func__, ret); + goto out; + } + } else { + wpa_printf(MSG_ERROR, "%s: Getting connection info is not supported\n", __func__); + goto out; + } + +out: + return ret; +} + +const struct wpa_driver_ops wpa_driver_zep_ops = { + .name = "zephyr", + .desc = "Zephyr wpa_supplicant driver", + .global_init = wpa_drv_zep_global_init, + .global_deinit = wpa_drv_zep_global_deinit, + .init2 = wpa_drv_zep_init, + .deinit = wpa_drv_zep_deinit, + .scan2 = wpa_drv_zep_scan2, + .abort_scan = wpa_drv_zep_abort_scan, + .get_scan_results2 = wpa_drv_zep_get_scan_results2, + .authenticate = wpa_drv_zep_authenticate, + .associate = wpa_drv_zep_associate, + .get_capa = wpa_drv_zep_get_capa, + .get_bssid = wpa_drv_zep_get_bssid, + .get_ssid = wpa_drv_zep_get_ssid, + .set_supp_port = wpa_drv_zep_set_supp_port, + .deauthenticate = wpa_drv_zep_deauthenticate, + .set_key = wpa_drv_zep_set_key, + .signal_poll = wpa_drv_zep_signal_poll, + .send_action = wpa_drv_zep_send_action, + .get_hw_feature_data = wpa_drv_get_hw_feature_data, + .get_ext_capab = nl80211_get_ext_capab, + .get_conn_info = wpa_drv_zep_get_conn_info, +}; diff --git a/src/drivers/driver_zephyr.h b/src/drivers/driver_zephyr.h new file mode 100644 index 000000000..e2d24839e --- /dev/null +++ b/src/drivers/driver_zephyr.h @@ -0,0 +1,226 @@ +/* + * Driver interaction with Zephyr WLAN device drivers. + * Copyright (c) 2022, Nordic Semiconductor + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DRIVER_ZEPHYR_H +#define DRIVER_ZEPHYR_H + +#include +#include + +#include "driver.h" +#include "wpa_supplicant_i.h" +#include "bss.h" + +#define __WPA_SUPP_PKD __attribute__((__packed__)) + +struct wpa_supp_event_channel { +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_IR (1 << 0) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_IBSS (1 << 1) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_RADAR (1 << 2) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_HT40_MINUS (1 << 3) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_HT40_PLUS (1 << 4) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_80MHZ (1 << 5) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_160MHZ (1 << 6) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_INDOOR_ONLY (1 << 7) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_GO_CONCURRENT (1 << 8) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_20MHZ (1 << 9) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_ATTR_NO_10MHZ (1 << 10) +#define WPA_SUPP_CHAN_FLAG_FREQUENCY_DISABLED (1 << 11) + +#define WPA_SUPP_CHAN_DFS_VALID (1 << 12) +#define WPA_SUPP_CHAN_DFS_CAC_TIME_VALID (1 << 13) + unsigned short wpa_supp_flags; + signed int wpa_supp_max_power; + unsigned int wpa_supp_time; + unsigned int dfs_cac_msec; + signed char ch_valid; + unsigned short center_frequency; + signed char dfs_state; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_rate { +#define WPA_SUPP_EVENT_GET_WIPHY_FLAG_RATE_SHORT_PREAMBLE (1 << 0) + unsigned short wpa_supp_flags; + unsigned short wpa_supp_bitrate; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_mcs_info { +#define WPA_SUPP_HT_MCS_MASK_LEN 10 +#define WPA_SUPP_HT_MCS_RES_LEN 3 + unsigned short wpa_supp_rx_highest; + unsigned char wpa_supp_rx_mask[WPA_SUPP_HT_MCS_MASK_LEN]; + unsigned char wpa_supp_tx_params; + unsigned char wpa_supp_reserved[WPA_SUPP_HT_MCS_RES_LEN]; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_sta_ht_cap { + signed int wpa_supp_ht_supported; + unsigned short wpa_supp_cap; + struct wpa_supp_event_mcs_info mcs; +#define WPA_SUPP_AMPDU_FACTOR_MASK 0x03 +#define WPA_SUPP_AMPDU_DENSITY_SHIFT 2 + unsigned char wpa_supp_ampdu_factor; + unsigned char wpa_supp_ampdu_density; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_vht_mcs_info { + unsigned short rx_mcs_map; + unsigned short rx_highest; + unsigned short tx_mcs_map; + unsigned short tx_highest; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_sta_vht_cap { + signed char wpa_supp_vht_supported; + unsigned int wpa_supp_cap; + struct wpa_supp_event_vht_mcs_info vht_mcs; +} __WPA_SUPP_PKD; + +struct wpa_supp_event_supported_band { + unsigned short wpa_supp_n_channels; + unsigned short wpa_supp_n_bitrates; +#define WPA_SUPP_SBAND_MAX_CHANNELS 29 +#define WPA_SUPP_SBAND_MAX_RATES 13 + struct wpa_supp_event_channel channels[WPA_SUPP_SBAND_MAX_CHANNELS]; + struct wpa_supp_event_rate bitrates[WPA_SUPP_SBAND_MAX_RATES]; + struct wpa_supp_event_sta_ht_cap ht_cap; + struct wpa_supp_event_sta_vht_cap vht_cap; + signed char band; +} __WPA_SUPP_PKD; + +struct wpa_bss; + +struct zep_wpa_supp_mbox_msg_data { + void *ctx; + enum wpa_event_type event; + void *data; +}; + + +struct zep_drv_ctx { + void *supp_ctx; +}; + + +struct zep_drv_if_ctx { + struct zep_drv_ctx *drv_ctx; + void *supp_if_ctx; + const struct device *dev_ctx; + void *dev_priv; + struct k_sem drv_resp_sem; + + struct wpa_scan_results *scan_res2; + bool scan_res2_get_in_prog; + + unsigned int assoc_freq; + unsigned char ssid[SSID_MAX_LEN]; + size_t ssid_len; + unsigned char bssid[6]; + bool associated; + + void *phy_info_arg; + struct wpa_driver_capa capa; + + unsigned char prev_bssid[6]; + unsigned char auth_bssid[6]; + unsigned char auth_attempt_bssid[6]; +}; + + +struct zep_wpa_supp_dev_callbk_fns { + void (*scan_start)(struct zep_drv_if_ctx *if_ctx); + + void (*scan_done)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event); + + void (*scan_res)(struct zep_drv_if_ctx *if_ctx, struct wpa_scan_res *r, + bool more_res); + + void (*auth_resp)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event); + + void (*assoc_resp)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event, unsigned int status); + + void (*deauth)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event, const struct ieee80211_mgmt *mgmt); + + void (*disassoc)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event); + + void (*mgmt_tx_status)(struct zep_drv_if_ctx *if_ctx, + const u8 *frame, size_t len, bool ack); + + void (*unprot_deauth)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event); + + void (*unprot_disassoc)(struct zep_drv_if_ctx *if_ctx, + union wpa_event_data *event); + + void (*get_wiphy_res)(struct zep_drv_if_ctx *if_ctx, + void *band); + + void (*mgmt_rx)(struct zep_drv_if_ctx *if_ctx, + char *frame, int frame_len, int frequency, int rx_signal_dbm); + + void (*mac_changed)(struct zep_drv_if_ctx *if_ctx); +}; + + +struct zep_wpa_supp_dev_ops { + void *(*init)(void *supp_drv_if_ctx, + const char *iface_name, + struct zep_wpa_supp_dev_callbk_fns *callbk_fns); + void (*deinit)(void *if_priv); + int (*scan2)(void *if_priv, + struct wpa_driver_scan_params *params); + int (*scan_abort)(void *if_priv); + int (*get_scan_results2)(void *if_priv); + int (*deauthenticate)(void *if_priv, + const char *addr, + unsigned short reason_code); + int (*authenticate)(void *if_priv, + struct wpa_driver_auth_params *params, + struct wpa_bss *curr_bss); + int (*associate)(void *if_priv, + struct wpa_driver_associate_params *params); + int (*set_key)(void *if_priv, + const unsigned char *ifname, + enum wpa_alg alg, + const unsigned char *addr, + int key_idx, + int set_tx, + const unsigned char *seq, + size_t seq_len, + const unsigned char *key, + size_t key_len); + int (*set_supp_port)(void *if_priv, + int authorized, + char *bssid); + int (*signal_poll)(void *if_priv, struct wpa_signal_info *si, + unsigned char *bssid); + int (*send_mlme)(void *if_priv, const u8 *data, + size_t data_len, int noack, + unsigned int freq, int no_cck, + int offchanok, + unsigned int wait_time, + int cookie); + int (*get_wiphy)(void *if_priv); + + int (*register_frame)(void *if_priv, + u16 type, const u8 *match, size_t match_len, + bool multicast); + + int (*get_capa)(void *if_priv, + struct wpa_driver_capa *capa); + + int (*get_conn_info)(void *if_priv, + struct wpa_conn_info *info); +}; + +#endif /* DRIVER_ZEPHYR_H */ diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index e95df6ddb..fffc94a35 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -48,6 +48,9 @@ const struct wpa_driver_ops *const wpa_drivers[] = #endif /* CONFIG_DRIVER_ATHEROS */ #ifdef CONFIG_DRIVER_NONE &wpa_driver_none_ops, +#endif /* CONFIG_DRIVER_NONE */ +#ifdef CONFIG_ZEPHYR + &wpa_driver_zep_ops, #endif /* CONFIG_DRIVER_NONE */ NULL }; diff --git a/src/l2_packet/l2_packet_zephyr.c b/src/l2_packet/l2_packet_zephyr.c new file mode 100644 index 000000000..a22c7d050 --- /dev/null +++ b/src/l2_packet/l2_packet_zephyr.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "l2_packet.h" +#include "common/eapol_common.h" +struct l2_packet_data { + char ifname[17]; + u8 own_addr[ETH_ALEN]; + int ifindex; + struct net_if *iface; + void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len); + void *rx_callback_ctx; + int l2_hdr; /* whether to include layer 2 (Ethernet) header data + * buffers */ + int fd; + unsigned short protocol; +}; + +int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) +{ + os_memcpy(addr, l2->own_addr, ETH_ALEN); + return 0; +} + +int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, + const u8 *buf, size_t len) +{ + int ret; + + if (l2 == NULL) { + return -1; + } + + if (l2->l2_hdr) { + ret = send(l2->fd, buf, len, 0); + if (ret < 0) { + wpa_printf(MSG_ERROR, "l2_packet_send - send: %s", + strerror(errno)); + } + } else { + struct sockaddr_ll ll; + + os_memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + ll.sll_ifindex = l2->ifindex; + ll.sll_protocol = htons(proto); + ll.sll_halen = ETH_ALEN; + os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN); + // TODO: This takes up too much stack, call wifi driver TX directly? + ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll, + sizeof(ll)); + if (ret < 0) { + wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s", + strerror(errno)); + } + } + return ret; +} + +static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct l2_packet_data *l2 = eloop_ctx; + u8 buf[2300]; + int res; + struct sockaddr_ll ll; + socklen_t fromlen; + const struct ieee802_1x_hdr *hdr; + + os_memset(&ll, 0, sizeof(ll)); + fromlen = sizeof(ll); + res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&ll, + &fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "RAW : failed to recv error %d", errno); + return; + } + + // FIXME: sll_addr is not being filled as L2 header is not removed + wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " proto=0x%x len=%d", + __func__, MAC2STR(ll.sll_addr), ll.sll_protocol, (int) res); + + hdr = (const struct ieee802_1x_hdr *) buf; + + // FIXME: L2 header is now removed but sll_protocol is not set. + // So, as a workaround add this check to drop packets. + if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) + return; + + // FIXME: We should only get registered protcols from networking stack + // but for some reason ETH_P_ALL is being set (bind_default) + l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); +} + +struct l2_packet_data * +l2_packet_init(const char *ifname, const u8 *own_addr, unsigned short protocol, + void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len), + void *rx_callback_ctx, int l2_hdr) +{ + struct l2_packet_data *l2; + struct sockaddr_ll ll; + int ret = 0; + struct net_linkaddr *link_addr = NULL; + struct net_if *iface = NULL; + const struct device *device = device_get_binding(ifname); + + if (!device) { + wpa_printf(MSG_ERROR, "Cannot get device for: %s\n", ifname); + return NULL; + } + + iface = net_if_lookup_by_dev(device); + + if (!iface) { + wpa_printf(MSG_ERROR, "Cannot get device for: %s\n", ifname); + return NULL; + } + + l2 = os_zalloc(sizeof(struct l2_packet_data)); + if (l2 == NULL) { + return NULL; + } + os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); + l2->rx_callback = rx_callback; + l2->rx_callback_ctx = rx_callback_ctx; + l2->l2_hdr = l2_hdr; + l2->protocol = protocol; + l2->iface = iface; + + l2->ifindex = net_if_get_by_iface(l2->iface); + + if (!l2->ifindex) { + wpa_printf(MSG_ERROR, "Cannot get interface index for: %s\n", + l2->ifname); + os_free(l2); + return NULL; + } + + link_addr = &iface->if_dev->link_addr; + os_memcpy(l2->own_addr, link_addr->addr, link_addr->len); + + l2->fd = socket(AF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, + htons(protocol)); + if (l2->fd < 0) { + wpa_printf(MSG_ERROR, + "Failed to open socket: %s, proto: %d, af: %d", + strerror(errno), htons(protocol), AF_PACKET); + goto fail; + } + + os_memset(&ll, 0, sizeof(ll)); + ll.sll_family = AF_PACKET; + + ll.sll_ifindex = l2->ifindex; + ll.sll_protocol = htons(protocol); + + // FIXME: This should skip bind_default to ETH_P_ALL, but its not. + memcpy(ll.sll_addr, l2->own_addr, ETH_ALEN); + + ret = bind(l2->fd, (const struct sockaddr *) &ll, sizeof(ll)); + if (ret < 0) { + goto fail; + } + + if (rx_callback) { + eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); + } + + wpa_printf(MSG_DEBUG, "l2_packet_init: iface %s ifindex %d", l2->ifname, + l2->ifindex); + + return l2; +fail: + if (l2->fd >= 0) + close(l2->fd); + os_free(l2); + wpa_printf(MSG_ERROR, "Failed to create l2_packet: %d\n", ret); + return NULL; +} + +struct l2_packet_data * +l2_packet_init_bridge(const char *br_ifname, const char *ifname, + const u8 *own_addr, unsigned short protocol, + void (*rx_callback)(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len), + void *rx_callback_ctx, int l2_hdr) +{ + return l2_packet_init(br_ifname, own_addr, protocol, rx_callback, + rx_callback_ctx, l2_hdr); +} + +void l2_packet_deinit(struct l2_packet_data *l2) +{ + if (l2 == NULL) { + return; + } + + if (l2->fd >= 0) { + eloop_unregister_read_sock(l2->fd); + close(l2->fd); + } + + os_free(l2); +} + +int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) +{ +#ifdef CONFIG_NET_IPV4 + char addr_buf[NET_IPV4_ADDR_LEN]; + os_strlcpy(buf, net_addr_ntop(AF_INET, + &l2->iface->config.ip.ipv4->unicast[0].address.in_addr.s_addr, + addr_buf, sizeof(addr_buf)), len); + return 0; +#else + return -1; +#endif +} + +void l2_packet_notify_auth_start(struct l2_packet_data *l2) +{ + /* This function can be left empty */ +} + +int l2_packet_set_packet_filter(struct l2_packet_data *l2, + enum l2_packet_filter_type type) +{ + /* TODO: Set filter */ + return 0; +} diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 0a2f87787..9c04692e8 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2365,7 +2365,7 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm, wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, " EAPOL-Key type=%d", key->type); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)", + " key_info 0x%x (ver=%d keyidx=%ld rsvd=%ld %s%s%s%s%s%s%s%s)", key_info, key_info & WPA_KEY_INFO_TYPE_MASK, (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> WPA_KEY_INFO_KEY_INDEX_SHIFT, diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 41daaae2c..a1f02511f 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -304,6 +304,19 @@ static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, return -1; } +static inline int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe, + size_t *rsnxe_len) +{ + return -1; + +} + +static inline int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *rsnxe, + size_t rsnxe_len) +{ + return -1; +} + static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) { return 0; diff --git a/src/utils/common.c b/src/utils/common.c index 2c1275193..9db7ce32e 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -1302,3 +1302,13 @@ void forced_memzero(void *ptr, size_t len) if (len) forced_memzero_val = ((u8 *) ptr)[0]; } + +#ifdef CONFIG_ZEPHYR +#include +extern char *inet_ntoa(struct in_addr in) +{ + char addr[NET_IPV4_ADDR_LEN]; + + return net_addr_ntop(AF_INET, (const void *)&in, addr, NET_IPV4_ADDR_LEN); +} +#endif diff --git a/src/utils/common.h b/src/utils/common.h index 45f72bb30..4a06a7126 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -129,7 +129,7 @@ typedef int8_t s8; /* Define platform specific byte swapping macros */ -#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) || defined (CONFIG_ZEPHYR) static inline unsigned short wpa_swap_16(unsigned short v) { @@ -532,7 +532,7 @@ static inline int is_multicast_ether_addr(const u8 *a) #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" -#include "wpa_debug.h" +#include struct wpa_freq_range_list { @@ -553,7 +553,11 @@ void int_array_concat(int **res, const int *a); void int_array_sort_unique(int *a); void int_array_add_unique(int **res, int a); +#ifdef CONFIG_ZEPHYR +char *inet_ntoa(struct in_addr in); +#else #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif void str_clear_free(char *str); void bin_clear_free(void *bin, size_t len); diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c index 2ffd1a2a2..5f0cc8108 100644 --- a/src/utils/edit_simple.c +++ b/src/utils/edit_simple.c @@ -13,6 +13,9 @@ #include "edit.h" +#ifdef CONFIG_ZEPHYR +#define STDIN_FILENO 1 +#endif #define CMD_BUF_LEN 4096 static char cmdbuf[CMD_BUF_LEN]; static int cmdbuf_pos = 0; diff --git a/src/utils/eloop.c b/src/utils/eloop.c index 00b0beff0..a578c320e 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -963,7 +963,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, } -#ifndef CONFIG_NATIVE_WINDOWS +#if !(defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ZEPHYR)) static void eloop_handle_alarm(int sig) { wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " @@ -980,7 +980,7 @@ static void eloop_handle_signal(int sig) { size_t i; -#ifndef CONFIG_NATIVE_WINDOWS +#if !(defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ZEPHYR)) if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { /* Use SIGALRM to break out from potential busy loops that * would not allow the program to be killed. */ @@ -1009,7 +1009,7 @@ static void eloop_process_pending_signals(void) eloop.signaled = 0; if (eloop.pending_terminate) { -#ifndef CONFIG_NATIVE_WINDOWS +#if !(defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ZEPHYR)) alarm(0); #endif /* CONFIG_NATIVE_WINDOWS */ eloop.pending_terminate = 0; diff --git a/src/utils/includes.h b/src/utils/includes.h index 741fc9c14..fad478dea 100644 --- a/src/utils/includes.h +++ b/src/utils/includes.h @@ -29,11 +29,11 @@ #endif /* _WIN32_WCE */ #include -#ifndef _MSC_VER +#if !(defined(MSC_VER) || defined(CONFIG_ZEPHYR)) #include #endif /* _MSC_VER */ -#ifndef CONFIG_NATIVE_WINDOWS +#if !(defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ZEPHYR)) #include #include #include @@ -43,4 +43,17 @@ #endif /* __vxworks */ #endif /* CONFIG_NATIVE_WINDOWS */ +#if defined(CONFIG_ZEPHYR) +#if defined(CONFIG_POSIX_API) +#include +#include +#include +#include +#else /* defined(CONFIG_POSIX_API) */ +#include +#include +#endif /* defined(CONFIG_POSIX_API) */ +#include +#endif /* defined(CONFIG_ZEPHYR) */ + #endif /* INCLUDES_H */ diff --git a/src/utils/os.h b/src/utils/os.h index 21ba5c3ff..de1ac943c 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -9,7 +9,7 @@ #ifndef OS_H #define OS_H -typedef long os_time_t; +typedef uint64_t os_time_t; /** * os_sleep - Sleep (sec, usec) @@ -298,6 +298,42 @@ static inline void * os_calloc(size_t nmemb, size_t size) * these functions need to be implemented in os_*.c file for the target system. */ +#ifdef CONFIG_ZEPHYR +/** + * os_strdup - Duplicate a string + * @s: Source string + * Returns: Allocated buffer with the string copied into it or %NULL on failure + * + * Caller is responsible for freeing the returned buffer with os_free(). + */ +char *os_strdup(const char *s); + +/** + * os_strcasecmp - Compare two strings ignoring case + * @s1: First string + * @s2: Second string + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greatred than s2 + */ +int os_strcasecmp(const char *s1, const char *s2); + +/** + * os_strncasecmp - Compare two strings ignoring case + * @s1: First string + * @s2: Second string + * @n: Maximum numbers of characters to compare + * Returns: An integer less than, equal to, or greater than zero if s1 is + * found to be less than, to match, or be greater than s2. Only first n + * characters will be compared. + */ +int os_strncasecmp(const char *s1, const char *s2, size_t n); + +#ifndef os_memcmp_const +#define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n)) +#endif +#endif + + #ifdef OS_NO_C_LIB_DEFINES /** @@ -493,7 +529,7 @@ char * os_strdup(const char *s); #ifndef os_strdup #ifdef _MSC_VER #define os_strdup(s) _strdup(s) -#else +#elif !defined(CONFIG_ZEPHYR) #define os_strdup(s) strdup(s) #endif #endif @@ -518,14 +554,14 @@ char * os_strdup(const char *s); #ifndef os_strcasecmp #ifdef _MSC_VER #define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) -#else +#elif !defined(CONFIG_ZEPHYR) #define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) #endif #endif #ifndef os_strncasecmp #ifdef _MSC_VER #define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) -#else +#elif !defined(CONFIG_ZEPHYR) #define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) #endif #endif @@ -597,6 +633,7 @@ static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size, */ size_t os_strlcpy(char *dest, const char *src, size_t siz); +#ifndef CONFIG_ZEPHYR /** * os_memcmp_const - Constant time memory comparison * @a: First buffer to compare @@ -614,7 +651,7 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz); */ int os_memcmp_const(const void *a, const void *b, size_t len); - +#endif /** * os_memdup - Allocate duplicate of passed memory chunk * @src: Source buffer to duplicate diff --git a/src/utils/os_zephyr.c b/src/utils/os_zephyr.c new file mode 100644 index 000000000..cbc68ae6f --- /dev/null +++ b/src/utils/os_zephyr.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +#include +#include + +#include "includes.h" +#include "os.h" + +void os_sleep(os_time_t sec, os_time_t usec) +{ + if (sec) { + k_sleep(K_SECONDS(sec)); + } + if (usec) { + k_usleep(usec); + } +} + +int os_get_time(struct os_time *t) +{ + int res; + struct timeval tv; + + res = gettimeofday(&tv, NULL); + t->sec = tv.tv_sec; + t->usec = tv.tv_usec; + return res; +} + +int os_get_reltime(struct os_reltime *t) +{ +#if defined(CLOCK_BOOTTIME) + static clockid_t clock_id = CLOCK_BOOTTIME; +#elif defined(CLOCK_MONOTONIC) + static clockid_t clock_id = CLOCK_MONOTONIC; +#else + static clockid_t clock_id = CLOCK_REALTIME; +#endif + struct timespec ts; + int res; + + if (TEST_FAIL()) { + return -1; + } + + while (1) { + res = clock_gettime(clock_id, &ts); + if (res == 0) { + t->sec = ts.tv_sec; + t->usec = ts.tv_nsec / 1000; + return 0; + } + switch (clock_id) { +#ifdef CLOCK_BOOTTIME + case CLOCK_BOOTTIME: + clock_id = CLOCK_MONOTONIC; + break; +#endif +#ifdef CLOCK_MONOTONIC + case CLOCK_MONOTONIC: + clock_id = CLOCK_REALTIME; + break; +#endif + case CLOCK_REALTIME: + return -1; + } + } +} + +int os_mktime(int year, int month, int day, int hour, int min, int sec, + os_time_t *t) +{ + struct tm tm, *tm1; + time_t t_local, t1, t2; + os_time_t tz_offset; + + if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || + hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || + sec > 60) { + return -1; + } + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + + t_local = mktime(&tm); + + /* figure out offset to UTC */ + tm1 = localtime(&t_local); + if (tm1) { + t1 = mktime(tm1); + tm1 = gmtime(&t_local); + if (tm1) { + t2 = mktime(tm1); + tz_offset = t2 - t1; + } else { + tz_offset = 0; + } + } else { + tz_offset = 0; + } + + *t = (os_time_t)t_local - tz_offset; + return 0; +} + +int os_gmtime(os_time_t t, struct os_tm *tm) +{ + struct tm *tm2; + time_t t2 = t; + + tm2 = gmtime(&t2); + if (tm2 == NULL) { + return -1; + } + tm->sec = tm2->tm_sec; + tm->min = tm2->tm_min; + tm->hour = tm2->tm_hour; + tm->day = tm2->tm_mday; + tm->month = tm2->tm_mon + 1; + tm->year = tm2->tm_year + 1900; + return 0; +} + +int os_daemonize(const char *pid_file) +{ + return -1; +} + +void os_daemonize_terminate(const char *pid_file) +{ +} + +int os_get_random(unsigned char *buf, size_t len) +{ + sys_rand_get(buf, len); + + return 0; +} + +unsigned long os_random(void) +{ + return sys_rand32_get(); +} + +char *os_rel2abs_path(const char *rel_path) +{ + return NULL; /* strdup(rel_path) can be used here */ +} + +int os_program_init(void) +{ + return 0; +} + +void os_program_deinit(void) +{ +} + +int os_setenv(const char *name, const char *value, int overwrite) +{ + return -1; +} + +int os_unsetenv(const char *name) +{ + return -1; +} + +char *os_readfile(const char *name, size_t *len) +{ + return NULL; +} + +int os_fdatasync(FILE *stream) +{ + return 0; +} + +char *os_strdup(const char *s) +{ + size_t len; + char *d; + + len = os_strlen(s); + d = os_malloc(len + 1); + if (d == NULL) { + return NULL; + } + os_memcpy(d, s, len); + d[len] = '\0'; + return d; +} + +void *os_memdup(const void *src, size_t len) +{ + void *r = os_malloc(len); + + if (r && src) { + os_memcpy(r, src, len); + } + return r; +} + +void *os_zalloc(size_t size) +{ + return calloc(1, size); +} + +size_t os_strlcpy(char *dest, const char *src, size_t siz) +{ + const char *s = src; + size_t left = siz; + + if (left) { + /* Copy string up to the maximum size of the dest buffer */ + while (--left != 0) { + if ((*dest++ = *s++) == '\0') { + break; + } + } + } + + if (left == 0) { + /* Not enough room for the string; force NUL-termination */ + if (siz != 0) { + *dest = '\0'; + } + while (*s++) { + ; /* determine total src string length */ + } + } + + return s - src - 1; +} + +int os_exec(const char *program, const char *arg, int wait_completion) +{ + return -1; +} + +/* Duplicate S, returning an identical malloc'd string. */ +char *__strdup(const char *s) +{ + size_t len = strlen(s) + 1; + void *new = malloc(len); + + if (new == NULL) { + return NULL; + } + return (char *)memcpy(new, s, len); +} + +int os_strcasecmp(const char *s1, const char *s2) +{ + /* + * Ignoring case is not required for main functionality, so just use + * the case sensitive version of the function. + */ + return os_strcmp(s1, s2); +} + +int os_strncasecmp(const char *s1, const char *s2, size_t n) +{ + /* + * Ignoring case is not required for main functionality, so just use + * the case sensitive version of the function. + */ + return os_strncmp(s1, s2, n); +} diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index e13783ce1..117c33152 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -182,9 +182,26 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) os_free(anqp); } +static bool wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + struct wpa_radio_work *work; + struct wpa_connect_work *cwork; + + work = radio_work_pending(wpa_s, "sme-connect"); + if (!work) + work = radio_work_pending(wpa_s, "connect"); + if (!work) + return false; + + cwork = work->ctx; + if (cwork->bss != bss) + return false; + + return true; +} static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, - struct wpa_bss *old_bss, struct wpa_bss *new_bss) { struct wpa_radio_work *work; @@ -197,8 +214,6 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, return; cwork = work->ctx; - if (cwork->bss != old_bss) - return; wpa_printf(MSG_DEBUG, "Update BSS pointer for the pending connect radio work"); @@ -224,7 +239,8 @@ void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } } } - wpa_bss_update_pending_connect(wpa_s, bss, NULL); + if (wpa_bss_check_pending_connect(wpa_s, bss)) + wpa_bss_update_pending_connect(wpa_s, NULL); dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; @@ -685,20 +701,24 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } else { struct wpa_bss *nbss; struct dl_list *prev = bss->list_id.prev; + bool update_pending_connect = wpa_bss_check_pending_connect( + wpa_s, bss); + unsigned int i; + bool update_current_bss = wpa_s->current_bss == bss; + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpa_s->last_scan_res[i] == bss) + break; + } dl_list_del(&bss->list_id); nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (nbss) { - unsigned int i; - for (i = 0; i < wpa_s->last_scan_res_used; i++) { - if (wpa_s->last_scan_res[i] == bss) { - wpa_s->last_scan_res[i] = nbss; - break; - } - } - if (wpa_s->current_bss == bss) + if (i != wpa_s->last_scan_res_used) + wpa_s->last_scan_res[i] = nbss; + if (update_current_bss) wpa_s->current_bss = nbss; - wpa_bss_update_pending_connect(wpa_s, bss, nbss); + if (update_pending_connect) + wpa_bss_update_pending_connect(wpa_s, nbss); bss = nbss; os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); @@ -936,6 +956,10 @@ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) return; os_get_reltime(&t); + + if (t.sec < age) + return; /* avoid underflow */ + t.sec -= age; dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index f7ca929fe..cd82b2bdb 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -62,7 +62,7 @@ #ifdef __NetBSD__ #include #elif !defined(__CYGWIN__) && !defined(CONFIG_NATIVE_WINDOWS) -#include +#include #endif static int wpa_supplicant_global_iface_list(struct wpa_global *global, @@ -8612,7 +8612,7 @@ static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s, int ret; os_reltime_sub(&now, &work->time, &diff); - ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n", + ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%lld.%06lld\n", work->type, work->wpa_s->ifname, work->freq, work->started, diff.sec, diff.usec); if (os_snprintf_error(end - pos, ret)) @@ -11449,7 +11449,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { char *reply; - const int reply_size = 4096; + const int reply_size = 1024; int reply_len; if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || @@ -11478,6 +11478,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply = os_malloc(reply_size); if (reply == NULL) { + wpa_printf(MSG_ERROR, "ctrl_iface: reply malloc of %d failed", + reply_size); *resp_len = 1; return NULL; } diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h index dfbd25a03..e0440e853 100644 --- a/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant/ctrl_iface.h @@ -12,7 +12,12 @@ #ifdef CONFIG_CTRL_IFACE #ifndef CTRL_IFACE_MAX_LEN -#define CTRL_IFACE_MAX_LEN 8192 +#ifdef CONFIG_ZEPHYR +#define CTRL_IFACE_MAX_LEN 1024 +#else +#define CTRL_IFACE_MAX_LEN 4096 +#endif /* CONFIG_ZEPHYR */ + #endif /* CTRL_IFACE_MAX_LEN */ /* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */ diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 1cbf7fa28..db2c155da 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -18,7 +18,6 @@ #define COOKIE_LEN 8 - /* Per-interface ctrl_iface */ /** diff --git a/wpa_supplicant/ctrl_iface_zephyr.c b/wpa_supplicant/ctrl_iface_zephyr.c new file mode 100644 index 000000000..d3b9f07c3 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_zephyr.c @@ -0,0 +1,230 @@ +/* + * WPA Supplicant / Zephyr socket pair -based control interface + * Copyright (c) 2022, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "ctrl_iface_zephyr.h" + +static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + char *buf, *pos; + int res; + char *reply = NULL; + size_t reply_len = 0; + + buf = os_zalloc(CTRL_IFACE_MAX_LEN + 1); + if (!buf) + return; + res = recv(sock, buf, CTRL_IFACE_MAX_LEN, 0); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", + strerror(errno)); + os_free(buf); + return; + } + + if ((size_t) res > CTRL_IFACE_MAX_LEN) { + wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated"); + os_free(buf); + return; + } + buf[res] = '\0'; + + pos = buf; + while (*pos == ' ') + pos++; + + reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, + &reply_len); + + if (reply) { + send(sock, reply, reply_len, 0); + os_free(reply); + } else if (reply_len == 1) { + send(sock, "FAIL\n", 5, 0); + } else if (reply_len == 2) { + send(sock, "OK\n", 3, 0); + } + + os_free(buf); +} + + +struct ctrl_iface_priv * +wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + int ret; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->wpa_s = wpa_s; + memset(priv->sock_pair, -1, sizeof(priv->sock_pair)); + + if (wpa_s->conf->ctrl_interface == NULL) + return priv; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, priv->sock_pair); + if (ret != 0) { + wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); + goto fail; + } + + os_free(wpa_s->conf->ctrl_interface); + wpa_s->conf->ctrl_interface = os_strdup("zephyr:"); + if (!wpa_s->conf->ctrl_interface) { + wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface"); + goto fail; + } + + eloop_register_read_sock(priv->sock_pair[1], wpa_supplicant_ctrl_iface_receive, + wpa_s, priv); + + return priv; + +fail: + if (priv->sock_pair[0] >= 0) + close(priv->sock_pair[0]); + if (priv->sock_pair[1] >= 0) + close(priv->sock_pair[1]); + os_free(priv); + return NULL; +} + + +void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s, + struct ctrl_iface_priv *priv) +{ + if (!priv) + return; + + if (priv->sock_pair[1] > -1) { + eloop_unregister_read_sock(priv->sock_pair[1]); + close(priv->sock_pair[1]); + priv->sock_pair[1] = -1; + } + + if (priv->sock_pair[0] >= 0) + close(priv->sock_pair[0]); + + os_free(priv); +} + +void +wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) +{ +} + +/* Global control interface */ + +static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_global *global = eloop_ctx; + char *buf, *pos; + int res; + char *reply = NULL; + size_t reply_len = 0; + + wpa_printf(MSG_DEBUG, "Global ctrl_iface received"); + + buf = os_zalloc(CTRL_IFACE_MAX_LEN + 1); + if (!buf) { + wpa_printf(MSG_ERROR, "Global ctrl_iface: no memory"); + return; + } + res = recv(sock, buf, CTRL_IFACE_MAX_LEN, 0); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", + strerror(errno)); + os_free(buf); + return; + } + + if ((size_t) res > CTRL_IFACE_MAX_LEN) { + wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated"); + os_free(buf); + return; + } + buf[res] = '\0'; + + pos = buf; + while (*pos == ' ') + pos++; + + reply = wpa_supplicant_global_ctrl_iface_process(global, pos, + &reply_len); + + if (reply) { + send(sock, reply, reply_len, 0); + os_free(reply); + } else if (reply_len == 1) { + send(sock, "FAIL\n", 5, 0); + } else if (reply_len == 2) { + send(sock, "OK\n", 3, 0); + } + + os_free(buf); +} +struct ctrl_iface_global_priv * +wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *priv; + int ret; + + priv = os_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->global = global; + memset(priv->sock_pair, -1, sizeof(priv->sock_pair)); + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, priv->sock_pair); + if (ret != 0) { + wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); + goto fail; + } + + os_free(global->params.ctrl_interface); + global->params.ctrl_interface = os_strdup("g_zephyr:"); + if (!global->params.ctrl_interface) { + wpa_printf(MSG_ERROR, "Failed to malloc global ctrl_interface\n"); + goto fail; + } + + eloop_register_read_sock(priv->sock_pair[1], wpa_supplicant_global_ctrl_iface_receive, + global, priv); + + return priv; + +fail: + if (priv->sock_pair[0] >= 0) + close(priv->sock_pair[0]); + if (priv->sock_pair[1] >= 0) + close(priv->sock_pair[1]); + os_free(priv); + return NULL; +} + +void +wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) +{ + if (!priv) + return; + + if (priv->sock_pair[1] > -1) { + eloop_unregister_read_sock(priv->sock_pair[1]); + close(priv->sock_pair[1]); + priv->sock_pair[1] = -1; + } + + if (priv->sock_pair[0] >= 0) + close(priv->sock_pair[0]); + + os_free(priv); +} diff --git a/wpa_supplicant/ctrl_iface_zephyr.h b/wpa_supplicant/ctrl_iface_zephyr.h new file mode 100644 index 000000000..bad010264 --- /dev/null +++ b/wpa_supplicant/ctrl_iface_zephyr.h @@ -0,0 +1,30 @@ +/* + * WPA Supplicant / Zephyr socket pair -based control interface + * Copyright (c) 2022, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +/* Per-interface ctrl_iface */ +#include "includes.h" + +#include "common.h" +#include "eloop.h" +#include "config.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "common/wpa_ctrl.h" + +struct ctrl_iface_priv { + struct wpa_supplicant *wpa_s; + /* 0 - wpa_cli, 1 - ctrl_iface */ + int sock_pair[2]; +}; + +struct ctrl_iface_global_priv { + struct wpa_global *global; + /* 0 - wpa_cli, 1 - ctrl_iface */ + int sock_pair[2]; +}; + diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 237f4e085..af74a27b3 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -523,6 +523,9 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s, int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_signal_info *si); +int wpa_drv_get_conn_info(struct wpa_supplicant *wpa_s, + struct wpa_conn_info *conn_info); + static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s, struct wpa_channel_info *ci) { diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 603ac33d1..04092dfc0 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -6,6 +6,10 @@ * See README for more details. */ +#ifdef CONFIG_ZEPHYR +#include +#endif /* CONFIG_ZEPHYR */ + #include "includes.h" #include "common.h" @@ -2931,6 +2935,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wpa_s->connection_set = 0; if (data->assoc_info.req_ies && data->assoc_info.resp_ies) { struct ieee802_11_elems req_elems, resp_elems; + memset(&resp_elems, 0, sizeof(struct ieee802_11_elems)); if (ieee802_11_parse_elems(data->assoc_info.req_ies, data->assoc_info.req_ies_len, @@ -2951,6 +2956,22 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, BAND_2_4_GHZ); wpa_s->connection_he = req_elems.he_capabilities && resp_elems.he_capabilities; + if (!wpa_s->connection_ht && !wpa_s->connection_vht && + !wpa_s->connection_he) { + wpa_s->connection_a = 0; + wpa_s->connection_b = 0; + wpa_s->connection_g = 0; + if (wpas_freq_to_band(data->assoc_info.freq) == BAND_5_GHZ) { + wpa_s->connection_a = 1; + } else if (wpas_freq_to_band(data->assoc_info.freq) == + BAND_2_4_GHZ) { + if (supp_rates_11b_only(&resp_elems)) { + wpa_s->connection_b = 1; + } else { + wpa_s->connection_g = 1; + } + } + } } } @@ -3567,6 +3588,9 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, " reason=%d%s", MAC2STR(bssid), reason_code, locally_generated ? " locally_generated=1" : ""); +#ifdef CONFIG_ZEPHYR + send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_DISCONNECT_RESULT, 0); +#endif /* CONFIG_ZEPHYR */ } } @@ -5002,7 +5026,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, os_get_reltime(&wpa_s->scan_start_time); os_reltime_sub(&wpa_s->scan_start_time, &wpa_s->scan_trigger_time, &diff); - wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", + wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %lld.%06lld seconds", diff.sec, diff.usec); wpa_s->own_scan_requested = 0; wpa_s->own_scan_running = 1; @@ -5037,7 +5061,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); wpa_s->scan_start_time.sec = 0; wpa_s->scan_start_time.usec = 0; - wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", + wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %lld.%06lld seconds", diff.sec, diff.usec); } if (wpa_supplicant_event_scan_results(wpa_s, data)) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index a996b436b..90d0f81fd 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5210,7 +5210,7 @@ static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s, updated = os_reltime_before(&wpa_s->p2p_auto_started, &bss->last_update); wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at " - "%ld.%06ld (%supdated in last scan)", + "%lld.%06lld (%supdated in last scan)", bss->last_update.sec, bss->last_update.usec, updated ? "": "not "); @@ -5986,7 +5986,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (auto_join) { os_get_reltime(&wpa_s->p2p_auto_started); wpa_printf(MSG_DEBUG, "P2P: Auto join started at " - "%ld.%06ld", + "%lld.%06lld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); } @@ -7271,7 +7271,7 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpas_p2p_stop_find(wpa_s); wpa_s->p2p_join_scan_count = 0; os_get_reltime(&wpa_s->p2p_auto_started); - wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld", + wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %lld.%06lld", wpa_s->p2p_auto_started.sec, wpa_s->p2p_auto_started.usec); wpas_p2p_join_scan(wpa_s, NULL); diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index b0094ca6c..d3bffa098 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -2051,7 +2051,9 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, * better. */ static int wpa_scan_result_compar(const void *a, const void *b) { +#ifndef CONFIG_ZEPHYR #define MIN(a,b) a < b ? a : b +#endif struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c index d0fdd55d3..16ef6fe1f 100644 --- a/wpa_supplicant/wmm_ac.c +++ b/wpa_supplicant/wmm_ac.c @@ -159,12 +159,14 @@ static void wmm_ac_del_req(struct wpa_supplicant *wpa_s, int failed) static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; +#ifndef CONFIG_ZEPHYR struct wmm_ac_addts_request *addts_req = timeout_ctx; wpa_printf(MSG_DEBUG, "Timeout getting ADDTS response (tsid=%d up=%d)", wmm_ac_get_tsid(&addts_req->tspec), wmm_ac_get_user_priority(&addts_req->tspec)); +#endif /* CONFIG_ZEPHYR */ wmm_ac_del_req(wpa_s, 1); } diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 96160dccb..11e09f304 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -762,7 +762,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, os_reltime_expired(&now, &target->last_update, age_secs)) { wpa_printf(MSG_DEBUG, - "Candidate BSS is more than %ld seconds old", + "Candidate BSS is more than %lld seconds old", age_secs); continue; } diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 033589f76..298d9b868 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -31,13 +31,9 @@ static const char *const wpa_cli_version = "wpa_cli v" VERSION_STR "\n" "Copyright (c) 2004-2022, Jouni Malinen and contributors"; -#define VENDOR_ELEM_FRAME_ID \ - " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ - "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \ - "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \ - "11: Assoc Req (P2P), 12: Assoc Resp (P2P)" +struct wpa_ctrl *ctrl_conn; +char *ifname_prefix = NULL; -static struct wpa_ctrl *ctrl_conn; static struct wpa_ctrl *mon_conn; static int wpa_cli_quit = 0; static int wpa_cli_attached = 0; @@ -55,18 +51,6 @@ static const char *action_file = NULL; static int reconnect = 0; static int ping_interval = 5; static int interactive = 0; -static char *ifname_prefix = NULL; - -static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ -static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ -static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ -static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ -static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */ -static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */ -#ifdef CONFIG_AP -static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ -#endif /* CONFIG_AP */ - static void print_help(const char *cmd); static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); @@ -261,7 +245,7 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print) } -static int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) +int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) { return _wpa_ctrl_command(ctrl, cmd, 1); } @@ -283,3699 +267,6 @@ static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args, } -static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "IFNAME"); -} - - -static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc > 0 && os_strcmp(argv[0], "verbose") == 0) - return wpa_ctrl_command(ctrl, "STATUS-VERBOSE"); - if (argc > 0 && os_strcmp(argv[0], "wps") == 0) - return wpa_ctrl_command(ctrl, "STATUS-WPS"); - if (argc > 0 && os_strcmp(argv[0], "driver") == 0) - return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); -#ifdef ANDROID - if (argc > 0 && os_strcmp(argv[0], "no_events") == 0) - return wpa_ctrl_command(ctrl, "STATUS-NO_EVENTS"); -#endif /* ANDROID */ - return wpa_ctrl_command(ctrl, "STATUS"); -} - - -static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "PING"); -} - - -static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "RELOG"); -} - - -static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv); -} - - -static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "MIB"); -} - - -static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "PMKSA"); -} - - -static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); -} - - -#ifdef CONFIG_PMKSA_CACHE_EXTERNAL - -static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv); -} - - -static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv); -} - - -#ifdef CONFIG_MESH - -static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv); -} - - -static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv); -} - -#endif /* CONFIG_MESH */ -#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ - - -static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - print_help(argc > 0 ? argv[0] : NULL); - return 0; -} - - -static char ** wpa_cli_complete_help(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = wpa_list_cmd_list(); - break; - } - - return res; -} - - -static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - printf("%s\n\n%s\n", wpa_cli_version, cli_full_license); - return 0; -} - - -static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - wpa_cli_quit = 1; - if (interactive) - eloop_terminate(); - return 0; -} - - -static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - int res; - - if (argc == 1) { - res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]); - if (os_snprintf_error(sizeof(cmd), res)) { - printf("Too long SET command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); - } - - return wpa_cli_cmd(ctrl, "SET", 2, argc, argv); -} - - -static char ** wpa_cli_complete_set(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - const char *fields[] = { - /* runtime values */ - "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod", - "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime", - "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout", - "wps_fragment_size", "wps_version_number", "ampdu", - "tdls_testing", "tdls_disabled", "pno", "radio_disabled", - "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps", - "no_keep_alive", - /* global configuration parameters */ -#ifdef CONFIG_CTRL_IFACE - "ctrl_interface", "no_ctrl_interface", "ctrl_interface_group", -#endif /* CONFIG_CTRL_IFACE */ - "eapol_version", "ap_scan", "bgscan", -#ifdef CONFIG_MESH - "user_mpm", "max_peer_links", "mesh_max_inactivity", - "dot11RSNASAERetransPeriod", -#endif /* CONFIG_MESH */ - "disable_scan_offload", "fast_reauth", "opensc_engine_path", - "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers", - "pcsc_reader", "pcsc_pin", "external_sim", "driver_param", - "dot11RSNAConfigPMKLifetime", - "dot11RSNAConfigPMKReauthThreshold", - "dot11RSNAConfigSATimeout", -#ifndef CONFIG_NO_CONFIG_WRITE - "update_config", -#endif /* CONFIG_NO_CONFIG_WRITE */ - "load_dynamic_eap", -#ifdef CONFIG_WPS - "uuid", "device_name", "manufacturer", "model_name", - "model_number", "serial_number", "device_type", "os_version", - "config_methods", "wps_cred_processing", "wps_vendor_ext_m1", -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - "sec_device_type", - "p2p_listen_reg_class", "p2p_listen_channel", - "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", - "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", - "p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan", - "p2p_no_go_freq", "p2p_add_cli_chan", - "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht", - "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface", - "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask", - "ip_addr_start", "ip_addr_end", "p2p_go_edmg", -#endif /* CONFIG_P2P */ - "country", "bss_max_count", "bss_expiration_age", - "bss_expiration_scan_count", "filter_ssids", "filter_rssi", - "max_num_sta", "disassoc_low_ack", "ap_isolate", -#ifdef CONFIG_HS20 - "hs20", -#endif /* CONFIG_HS20 */ - "interworking", "hessid", "access_network_type", "pbc_in_m1", - "go_interworking", "go_access_network_type", "go_internet", - "go_venue_group", "go_venue_type", - "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", - "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend", - "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", - "sae_groups", "dtim_period", "beacon_int", - "ap_vendor_elements", "ignore_old_scan_res", "freq_list", - "scan_cur_freq", "scan_res_valid_for_connect", - "sched_scan_interval", - "tdls_external_control", "osu_dir", "wowlan_triggers", - "p2p_search_delay", "mac_addr", "rand_addr_lifetime", - "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim", "wps_priority", - "ap_assocresp_elements", -#ifdef CONFIG_TESTING_OPTIONS - "ignore_auth_resp", -#endif /* CONFIG_TESTING_OPTIONS */ - "relative_rssi", "relative_band_adjust", - "extended_key_id", - }; - int i, num_fields = ARRAY_SIZE(fields); - - if (arg == 1) { - char **res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(fields[i]); - if (res[i] == NULL) - return res; - } - return res; - } - - if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0) - return cli_txt_list_array(&bsses); - - return NULL; -} - -static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DUMP"); -} - - -static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); -} - - -static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); -} - - -static char ** wpa_cli_complete_get(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - const char *fields[] = { -#ifdef CONFIG_CTRL_IFACE - "ctrl_interface", "ctrl_interface_group", -#endif /* CONFIG_CTRL_IFACE */ - "eapol_version", "ap_scan", -#ifdef CONFIG_MESH - "user_mpm", "max_peer_links", "mesh_max_inactivity", -#endif /* CONFIG_MESH */ - "disable_scan_offload", "fast_reauth", "opensc_engine_path", - "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers", - "pcsc_reader", "pcsc_pin", "external_sim", "driver_param", - "dot11RSNAConfigPMKLifetime", - "dot11RSNAConfigPMKReauthThreshold", - "dot11RSNAConfigSATimeout", -#ifndef CONFIG_NO_CONFIG_WRITE - "update_config", -#endif /* CONFIG_NO_CONFIG_WRITE */ -#ifdef CONFIG_WPS - "device_name", "manufacturer", "model_name", "model_number", - "serial_number", "config_methods", "wps_cred_processing", -#endif /* CONFIG_WPS */ -#ifdef CONFIG_P2P - "p2p_listen_reg_class", "p2p_listen_channel", - "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", - "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", - "p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan", - "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht", - "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface", - "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask", - "ip_addr_start", "ip_addr_end", -#endif /* CONFIG_P2P */ - "bss_max_count", "bss_expiration_age", - "bss_expiration_scan_count", "filter_ssids", "filter_rssi", - "max_num_sta", "disassoc_low_ack", "ap_isolate", -#ifdef CONFIG_HS20 - "hs20", -#endif /* CONFIG_HS20 */ - "interworking", "access_network_type", "pbc_in_m1", "autoscan", - "go_interworking", "go_access_network_type", "go_internet", - "go_venue_group", "go_venue_type", - "wps_nfc_dev_pw_id", "ext_password_backend", - "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", - "dtim_period", "beacon_int", "ignore_old_scan_res", - "scan_cur_freq", "scan_res_valid_for_connect", - "sched_scan_interval", - "sched_scan_start_delay", - "tdls_external_control", "osu_dir", "wowlan_triggers", - "p2p_search_delay", "mac_addr", "rand_addr_lifetime", - "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim", "extended_key_id" - }; - int i, num_fields = ARRAY_SIZE(fields); - - if (arg == 1) { - char **res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(fields[i]); - if (res[i] == NULL) - return res; - } - return res; - } - - return NULL; -} - - -static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "LOGOFF"); -} - - -static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "LOGON"); -} - - -static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "REASSOCIATE"); -} - - -static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "REATTACH"); -} - - -static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv); -} - - -static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv); -} - - -static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv); -} - - -static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv); -} - - -static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv); -} - - -static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - int res; - - if (argc < 1) - res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0"); - else - res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]); - if (os_snprintf_error(sizeof(cmd), res)) { - printf("Too long BSS_FLUSH command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv); -} - - -static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc == 0) { - printf("Invalid WPS_PIN command: need one or two arguments:\n" - "- BSSID: use 'any' to select any\n" - "- PIN: optional, used only with devices that have no " - "display\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WPS_CANCEL"); -} - - -#ifdef CONFIG_WPS_NFC - -static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv); -} - - -static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - int ret; - char *buf; - size_t buflen; - - if (argc != 1) { - printf("Invalid 'wps_nfc_tag_read' command - one argument " - "is required.\n"); - return -1; - } - - buflen = 18 + os_strlen(argv[0]); - buf = os_malloc(buflen); - if (buf == NULL) - return -1; - os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); - - ret = wpa_ctrl_command(ctrl, buf); - os_free(buf); - - return ret; -} - - -static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv); -} - - -static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv); -} - - -static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv); -} - -#endif /* CONFIG_WPS_NFC */ - - -static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256]; - int res; - - if (argc == 2) - res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", - argv[0], argv[1]); - else if (argc == 5 || argc == 6) { - char ssid_hex[2 * SSID_MAX_LEN + 1]; - char key_hex[2 * 64 + 1]; - int i; - - ssid_hex[0] = '\0'; - for (i = 0; i < SSID_MAX_LEN; i++) { - if (argv[2][i] == '\0') - break; - os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); - } - - key_hex[0] = '\0'; - if (argc == 6) { - for (i = 0; i < 64; i++) { - if (argv[5][i] == '\0') - break; - os_snprintf(&key_hex[i * 2], 3, "%02x", - argv[5][i]); - } - } - - res = os_snprintf(cmd, sizeof(cmd), - "WPS_REG %s %s %s %s %s %s", - argv[0], argv[1], ssid_hex, argv[3], argv[4], - key_hex); - } else { - printf("Invalid WPS_REG command: need two arguments:\n" - "- BSSID of the target AP\n" - "- AP PIN\n"); - printf("Alternatively, six arguments can be used to " - "reconfigure the AP:\n" - "- BSSID of the target AP\n" - "- AP PIN\n" - "- new SSID\n" - "- new auth (OPEN, WPAPSK, WPA2PSK)\n" - "- new encr (NONE, WEP, TKIP, CCMP)\n" - "- new key\n"); - return -1; - } - - if (os_snprintf_error(sizeof(cmd), res)) { - printf("Too long WPS_REG command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WPS_ER_STOP"); - -} - - -static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc < 2) { - printf("Invalid WPS_ER_PIN command: need at least two " - "arguments:\n" - "- UUID: use 'any' to select any\n" - "- PIN: Enrollee PIN\n" - "optional: - Enrollee MAC address\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 2) { - printf("Invalid WPS_ER_LEARN command: need two arguments:\n" - "- UUID: specify which AP to use\n" - "- PIN: AP PIN\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 2) { - printf("Invalid WPS_ER_SET_CONFIG command: need two " - "arguments:\n" - "- UUID: specify which AP to use\n" - "- Network configuration id\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv); -} - - -static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256]; - int res; - - if (argc == 5 || argc == 6) { - char ssid_hex[2 * SSID_MAX_LEN + 1]; - char key_hex[2 * 64 + 1]; - int i; - - ssid_hex[0] = '\0'; - for (i = 0; i < SSID_MAX_LEN; i++) { - if (argv[2][i] == '\0') - break; - os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); - } - - key_hex[0] = '\0'; - if (argc == 6) { - for (i = 0; i < 64; i++) { - if (argv[5][i] == '\0') - break; - os_snprintf(&key_hex[i * 2], 3, "%02x", - argv[5][i]); - } - } - - res = os_snprintf(cmd, sizeof(cmd), - "WPS_ER_CONFIG %s %s %s %s %s %s", - argv[0], argv[1], ssid_hex, argv[3], argv[4], - key_hex); - } else { - printf("Invalid WPS_ER_CONFIG command: need six arguments:\n" - "- AP UUID\n" - "- AP PIN\n" - "- new SSID\n" - "- new auth (OPEN, WPAPSK, WPA2PSK)\n" - "- new encr (NONE, WEP, TKIP, CCMP)\n" - "- new key\n"); - return -1; - } - - if (os_snprintf_error(sizeof(cmd), res)) { - printf("Too long WPS_ER_CONFIG command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -#ifdef CONFIG_WPS_NFC -static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 2) { - printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two " - "arguments:\n" - "- WPS/NDEF: token format\n" - "- UUID: specify which AP to use\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv); -} -#endif /* CONFIG_WPS_NFC */ - - -static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv); -} - - -static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv); -} - - -static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid IDENTITY command: needs two arguments " - "(network id and identity)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long IDENTITY command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long IDENTITY command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid PASSWORD command: needs two arguments " - "(network id and password)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PASSWORD command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PASSWORD command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid NEW_PASSWORD command: needs two arguments " - "(network id and password)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long NEW_PASSWORD command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long NEW_PASSWORD command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid PIN command: needs two arguments " - "(network id and pin)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PIN command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PIN command.\n"); - return -1; - } - pos += ret; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid OTP command: needs two arguments (network " - "id and password)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long OTP command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long OTP command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid SIM command: needs two arguments " - "(network id and SIM operation response)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long SIM command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long SIM command.\n"); - return -1; - } - pos += ret; - } - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PSK_PASSPHRASE command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PSK_PASSPHRASE command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256], *pos, *end; - int i, ret; - - if (argc < 2) { - printf("Invalid PASSPHRASE command: needs two arguments " - "(network id and passphrase)\n"); - return -1; - } - - end = cmd + sizeof(cmd); - pos = cmd; - ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", - argv[0], argv[1]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PASSPHRASE command.\n"); - return -1; - } - pos += ret; - for (i = 2; i < argc; i++) { - ret = os_snprintf(pos, end - pos, " %s", argv[i]); - if (os_snprintf_error(end - pos, ret)) { - printf("Too long PASSPHRASE command.\n"); - return -1; - } - pos += ret; - } - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc < 2) { - printf("Invalid BSSID command: needs two arguments (network " - "id and BSSID)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv); -} - - -static int wpa_cli_cmd_bssid_ignore(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "BSSID_IGNORE", 0, argc, argv); -} - - -static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv); -} - - -static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv); -} - - -static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv); -} - - -static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv); -} - - -static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv); -} - - -static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - int res = wpa_ctrl_command(ctrl, "ADD_NETWORK"); - if (interactive) - update_networks(ctrl); - return res; -} - - -static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - int res = wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); - if (interactive) - update_networks(ctrl); - return res; -} - - -static void wpa_cli_show_network_variables(void) -{ - printf("set_network variables:\n" - " ssid (network name, SSID)\n" - " psk (WPA passphrase or pre-shared key)\n" - " key_mgmt (key management protocol)\n" - " identity (EAP identity)\n" - " password (EAP password)\n" - " ...\n" - "\n" - "Note: Values are entered in the same format as the " - "configuration file is using,\n" - "i.e., strings values need to be inside double quotation " - "marks.\n" - "For example: set_network 1 ssid \"network name\"\n" - "\n" - "Please see wpa_supplicant.conf documentation for full list " - "of\navailable variables.\n"); -} - - -static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc == 0) { - wpa_cli_show_network_variables(); - return 0; - } - - if (argc < 3) { - printf("Invalid SET_NETWORK command: needs three arguments\n" - "(network id, variable name, and value)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); -} - - -static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc == 0) { - wpa_cli_show_network_variables(); - return 0; - } - - if (argc != 2) { - printf("Invalid GET_NETWORK command: needs two arguments\n" - "(network id and variable name)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv); -} - - -static const char *network_fields[] = { - "ssid", "scan_ssid", "bssid", "bssid_ignore", - "bssid_accept", "psk", "proto", "key_mgmt", - "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq", - "freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1", - "vht_center_freq2", "ht", "edmg", -#ifdef IEEE8021X_EAPOL - "eap", "identity", "anonymous_identity", "password", "ca_cert", - "ca_path", "client_cert", "private_key", "private_key_passwd", - "dh_file", "subject_match", "altsubject_match", - "check_cert_subject", - "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", - "client_cert2", "private_key2", "private_key2_passwd", - "dh_file2", "subject_match2", "altsubject_match2", - "check_cert_subject2", - "domain_suffix_match2", "domain_match2", "phase1", "phase2", - "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", - "pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id", - "engine", "engine2", "eapol_flags", "sim_num", - "openssl_ciphers", "erp", -#endif /* IEEE8021X_EAPOL */ - "wep_key0", "wep_key1", "wep_key2", "wep_key3", - "wep_tx_keyidx", "priority", -#ifdef IEEE8021X_EAPOL - "eap_workaround", "pac_file", "fragment_size", "ocsp", -#endif /* IEEE8021X_EAPOL */ - "mode", - "proactive_key_caching", "disabled", "id_str", - "ieee80211w", - "mixed_cell", "frequency", "fixed_freq", -#ifdef CONFIG_MESH - "no_auto_peer", "mesh_rssi_threshold", - "mesh_basic_rates", "dot11MeshMaxRetries", - "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout", - "dot11MeshHoldingTimeout", -#endif /* CONFIG_MESH */ - "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid", - "wpa_deny_ptk0_rekey", - "enable_edmg", "edmg_channel", -#ifdef CONFIG_P2P - "go_p2p_dev_addr", "p2p_client_list", "psk_list", -#endif /* CONFIG_P2P */ -#ifdef CONFIG_HT_OVERRIDES - "disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc", - "ht40_intolerant", "disable_max_amsdu", "ampdu_factor", - "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc", -#endif /* CONFIG_HT_OVERRIDES */ -#ifdef CONFIG_VHT_OVERRIDES - "disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1", - "vht_rx_mcs_nss_2", "vht_rx_mcs_nss_3", "vht_rx_mcs_nss_4", - "vht_rx_mcs_nss_5", "vht_rx_mcs_nss_6", "vht_rx_mcs_nss_7", - "vht_rx_mcs_nss_8", "vht_tx_mcs_nss_1", "vht_tx_mcs_nss_2", - "vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5", - "vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8", -#endif /* CONFIG_VHT_OVERRIDES */ -#ifdef CONFIG_HE_OVERRIDES - "disable_he", -#endif /* CONFIG_HE_OVERRIDES */ - "ap_max_inactivity", "dtim_period", "beacon_int", -#ifdef CONFIG_MACSEC - "macsec_policy", - "macsec_integ_only", - "macsec_replay_protect", - "macsec_replay_window", - "macsec_port", - "mka_priority", -#endif /* CONFIG_MACSEC */ -#ifdef CONFIG_HS20 - "update_identifier", -#endif /* CONFIG_HS20 */ - "mac_addr", "pbss", "wps_disabled" -}; - - -static char ** wpa_cli_complete_network(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - int i, num_fields = ARRAY_SIZE(network_fields); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&networks); - break; - case 2: - res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(network_fields[i]); - if (res[i] == NULL) - break; - } - } - return res; -} - - -static char ** wpa_cli_complete_network_id(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - if (arg == 1) - return cli_txt_list_array(&networks); - return NULL; -} - - -static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc == 0) { - wpa_cli_show_network_variables(); - return 0; - } - - if (argc < 3) { - printf("Invalid DUP_NETWORK command: needs three arguments\n" - "(src netid, dest netid, and variable name)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "DUP_NETWORK", 3, argc, argv); -} - - -static char ** wpa_cli_complete_dup_network(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - int i, num_fields = ARRAY_SIZE(network_fields); - char **res = NULL; - - switch (arg) { - case 1: - case 2: - res = cli_txt_list_array(&networks); - break; - case 3: - res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(network_fields[i]); - if (res[i] == NULL) - break; - } - } - return res; -} - - -static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "LIST_CREDS"); -} - - -static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - int res = wpa_ctrl_command(ctrl, "ADD_CRED"); - if (interactive) - update_creds(ctrl); - return res; -} - - -static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - int res = wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); - if (interactive) - update_creds(ctrl); - return res; -} - - -static const char * const cred_fields[] = { - "temporary", "priority", "sp_priority", "pcsc", "eap", - "update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home", - "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load", - "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password", - "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi", - "ca_cert_id", "cert_id", "key_id", "engine_id", "engine", - "milenage", "domain_suffix_match", "domain", "phase1", "phase2", - "roaming_consortium", "required_roaming_consortium", "excluded_ssid", - "roaming_partner", "provisioning_sp" -}; - - -static char ** wpa_cli_complete_cred(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - int i, num_fields = ARRAY_SIZE(cred_fields); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&creds); - break; - case 2: - res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(cred_fields[i]); - if (res[i] == NULL) - break; - } - } - return res; -} - - -static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc != 3) { - printf("Invalid SET_CRED command: needs three arguments\n" - "(cred id, variable name, and value)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv); -} - - -static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc != 2) { - printf("Invalid GET_CRED command: needs two arguments\n" - "(cred id, variable name)\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv); -} - - -static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DISCONNECT"); -} - - -static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "RECONNECT"); -} - - -static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); -} - - -static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv); -} - - -static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); -} - - -static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "ABORT_SCAN"); -} - - -static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); -} - - -static char ** wpa_cli_complete_bss(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&bsses); - break; - } - - return res; -} - - -static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc < 1 || argc > 3) { - printf("Invalid GET_CAPABILITY command: need at least one argument and max three arguments\n"); - return -1; - } - - if (argc > 1 && os_strcmp(argv[0], "key_mgmt") != 0 && - os_strncmp(argv[1], "iftype=", 7) == 0) { - printf("Invalid GET_CAPABILITY command: 'iftype=' param is allowed only for 'key_mgmt'\n"); - return -1; - } - - if (argc == 2 && os_strcmp(argv[1], "strict") != 0 && - os_strncmp(argv[1], "iftype=", 7) != 0) { - printf("Invalid GET_CAPABILITY command: the second argument, if any, must be 'strict' OR 'iftype='\n"); - return -1; - } - - if (argc == 3 && os_strcmp(argv[2], "strict") != 0) { - printf("Invalid GET_CAPABILITY command: the third argument, if any, must be 'strict'\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv); -} - - -static char ** wpa_cli_complete_get_capability(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - const char *fields[] = { - "eap", "pairwise", "group", "group_mgmt", "key_mgmt", - "proto", "auth_alg", "modes", "channels", "freq", -#ifdef CONFIG_TDLS - "tdls", -#endif /* CONFIG_TDLS */ -#ifdef CONFIG_ERP - "erp", -#endif /* CONFIG_ERP */ -#ifdef CONFIG_FIPS - "fips", -#endif /* CONFIG_FIPS */ -#ifdef CONFIG_ACS - "acs", -#endif /* CONFIG_ACS */ - }; - const char *iftypes[] = { - "iftype=STATION", "iftype=AP", "iftype=P2P_CLIENT", - "iftype=P2P_GO", "iftype=AP_VLAN", "iftype=IBSS", "iftype=NAN", - "iftype=P2P_DEVICE", "iftype=MESH", - }; - int i, num_fields = ARRAY_SIZE(fields); - int num_iftypes = ARRAY_SIZE(iftypes); - char **res = NULL; - - if (arg == 1) { - res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(fields[i]); - if (res[i] == NULL) - return res; - } - } - if (arg == 2) { - /* the second argument can be "iftype=" OR - * "strict" */ - res = os_calloc(num_iftypes + 2, sizeof(char *)); - if (!res) - return NULL; - res[0] = os_strdup("strict"); - if (!res[0]) - return res; - for (i = 0; i < num_iftypes; i++) { - res[i + 1] = os_strdup(iftypes[i]); - if (!res[i + 1]) - return res; - } - } - if (arg == 3) { - res = os_calloc(1 + 1, sizeof(char *)); - if (res == NULL) - return NULL; - res[0] = os_strdup("strict"); - } - return res; -} - - -static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl) -{ - printf("Available interfaces:\n"); - return wpa_ctrl_command(ctrl, "INTERFACES"); -} - - -static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc < 1) { - wpa_cli_list_interfaces(ctrl); - return 0; - } - - wpa_cli_close_connection(); - os_free(ctrl_ifname); - ctrl_ifname = os_strdup(argv[0]); - if (!ctrl_ifname) { - printf("Failed to allocate memory\n"); - return 0; - } - - if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) { - printf("Connected to interface '%s'.\n", ctrl_ifname); - } else { - printf("Could not connect to interface '%s' - re-trying\n", - ctrl_ifname); - } - return 0; -} - - -static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "RECONFIGURE"); -} - - -static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "TERMINATE"); -} - - -static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[256]; - int res; - - if (argc < 1) { - printf("Invalid INTERFACE_ADD command: needs at least one " - "argument (interface name)\n" - "All arguments: ifname confname driver ctrl_interface " - "driver_param bridge_name [create]\n"); - return -1; - } - - /* - * INTERFACE_ADD TABTABTABTAB - * TAB[TAB[TAB]] - */ - res = os_snprintf(cmd, sizeof(cmd), - "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", - argv[0], - argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", - argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", - argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "", - argc > 7 ? argv[7] : ""); - if (os_snprintf_error(sizeof(cmd), res)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv); -} - - -static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); -} - - -#ifdef CONFIG_AP -static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "STA", 1, argc, argv); -} - - -static char ** wpa_cli_complete_sta(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&stations); - break; - } - - return res; -} - - -static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd, - char *addr, size_t addr_len, int print) -{ - char buf[4096], *pos; - size_t len; - int ret; - - if (ctrl_conn == NULL) { - printf("Not connected to hostapd - command dropped.\n"); - return -1; - } - if (ifname_prefix) { - os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", - ifname_prefix, cmd); - buf[sizeof(buf) - 1] = '\0'; - cmd = buf; - } - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, - wpa_cli_msg_cb); - if (ret == -2) { - printf("'%s' command timed out.\n", cmd); - return -2; - } else if (ret < 0) { - printf("'%s' command failed.\n", cmd); - return -1; - } - - buf[len] = '\0'; - if (os_memcmp(buf, "FAIL", 4) == 0 || - os_memcmp(buf, "UNKNOWN COMMAND", 15) == 0) - return -1; - if (print) - printf("%s", buf); - - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - *pos = '\0'; - os_strlcpy(addr, buf, addr_len); - return 0; -} - - -static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char addr[32], cmd[64]; - - if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1)) - return 0; - do { - os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); - } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0); - - return -1; -} - - -static int wpa_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char addr[32], cmd[64]; - - if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) - return 0; - do { - if (os_strcmp(addr, "") != 0) - printf("%s\n", addr); - os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); - } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); - - return 0; -} - - -static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv); -} - - -static char ** wpa_cli_complete_deauthenticate(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&stations); - break; - } - - return res; -} - - -static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); -} - - -static char ** wpa_cli_complete_disassociate(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&stations); - break; - } - - return res; -} - - -static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv); -} - - -static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); -} - -#endif /* CONFIG_AP */ - - -static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "SUSPEND"); -} - - -static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "RESUME"); -} - - -#ifdef CONFIG_TESTING_OPTIONS -static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DROP_SA"); -} -#endif /* CONFIG_TESTING_OPTIONS */ - - -static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv); -} - - -#ifdef CONFIG_MESH - -static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv); -} - - -static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv); -} - - -static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv); -} - - -static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv); -} - - -static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv); -} - - -static int wpa_cli_cmd_mesh_link_probe(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MESH_LINK_PROBE", 1, argc, argv); -} - -#endif /* CONFIG_MESH */ - - -#ifdef CONFIG_P2P - -static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv); -} - - -static char ** wpa_cli_complete_p2p_find(const char *str, int pos) -{ - char **res = NULL; - int arg = get_cmd_arg_num(str, pos); - - res = os_calloc(6, sizeof(char *)); - if (res == NULL) - return NULL; - res[0] = os_strdup("type=social"); - if (res[0] == NULL) { - os_free(res); - return NULL; - } - res[1] = os_strdup("type=progressive"); - if (res[1] == NULL) - return res; - res[2] = os_strdup("delay="); - if (res[2] == NULL) - return res; - res[3] = os_strdup("dev_id="); - if (res[3] == NULL) - return res; - if (arg == 1) - res[4] = os_strdup("[timeout]"); - - return res; -} - - -static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_STOP_FIND"); -} - - -static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv); -} - - -static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv); -} - - -static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv); -} - - -static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&p2p_peers); - break; - } - - return res; -} - - -static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv); -} - - -static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv); -} - - -static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&p2p_groups); - break; - } - - return res; -} - - -static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv); -} - - -static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 2 && argc != 3) { - printf("Invalid P2P_PROV_DISC command: needs at least " - "two arguments, address and config method\n" - "(display, keypad, or pbc) and an optional join\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv); -} - - -static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE"); -} - - -static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[4096]; - - if (argc < 2) { - printf("Invalid P2P_SERV_DISC_REQ command: needs two " - "or more arguments (address and TLVs)\n"); - return -1; - } - - if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0) - return -1; - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[4096]; - int res; - - if (argc != 4) { - printf("Invalid P2P_SERV_DISC_RESP command: needs four " - "arguments (freq, address, dialog token, and TLVs)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s", - argv[0], argv[1], argv[2], argv[3]); - if (os_snprintf_error(sizeof(cmd), res)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE"); -} - - -static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH"); -} - - -static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc < 3) { - printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv); -} - - -static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc < 5 || argc > 6) { - printf("Invalid P2P_SERVICE_REP command: needs 5-6 " - "arguments\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv); -} - - -static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[4096]; - int res; - - if (argc != 2 && argc != 3) { - printf("Invalid P2P_SERVICE_DEL command: needs two or three " - "arguments\n"); - return -1; - } - - if (argc == 3) - res = os_snprintf(cmd, sizeof(cmd), - "P2P_SERVICE_DEL %s %s %s", - argv[0], argv[1], argv[2]); - else - res = os_snprintf(cmd, sizeof(cmd), - "P2P_SERVICE_DEL %s %s", - argv[0], argv[1]); - if (os_snprintf_error(sizeof(cmd), res)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl, - int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv); -} - - -static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - char **res = NULL; - - switch (arg) { - case 1: - res = cli_txt_list_array(&p2p_peers); - break; - } - - return res; -} - - -static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, const char *cmd, - char *addr, size_t addr_len, - int discovered) -{ - char buf[4096], *pos; - size_t len; - int ret; - - if (ctrl_conn == NULL) - return -1; - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, - wpa_cli_msg_cb); - if (ret == -2) { - printf("'%s' command timed out.\n", cmd); - return -2; - } else if (ret < 0) { - printf("'%s' command failed.\n", cmd); - return -1; - } - - buf[len] = '\0'; - if (os_memcmp(buf, "FAIL", 4) == 0) - return -1; - - pos = buf; - while (*pos != '\0' && *pos != '\n') - pos++; - *pos++ = '\0'; - os_strlcpy(addr, buf, addr_len); - if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL) - printf("%s\n", addr); - return 0; -} - - -static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char addr[32], cmd[64]; - int discovered; - - discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0; - - if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST", - addr, sizeof(addr), discovered)) - return -1; - do { - os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); - } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr), - discovered) == 0); - - return 0; -} - - -static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv); -} - - -static char ** wpa_cli_complete_p2p_set(const char *str, int pos) -{ - int arg = get_cmd_arg_num(str, pos); - const char *fields[] = { - "discoverability", - "managed", - "listen_channel", - "ssid_postfix", - "noa", - "ps", - "oppps", - "ctwindow", - "disabled", - "conc_pref", - "force_long_sd", - "peer_filter", - "cross_connect", - "go_apsd", - "client_apsd", - "disallow_freq", - "disc_int", - "per_sta_psk", - }; - int i, num_fields = ARRAY_SIZE(fields); - - if (arg == 1) { - char **res = os_calloc(num_fields + 1, sizeof(char *)); - if (res == NULL) - return NULL; - for (i = 0; i < num_fields; i++) { - res[i] = os_strdup(fields[i]); - if (res[i] == NULL) - return res; - } - return res; - } - - if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0) - return cli_txt_list_array(&p2p_peers); - - return NULL; -} - - -static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_FLUSH"); -} - - -static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "P2P_CANCEL"); -} - - -static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 0 && argc != 2 && argc != 4) { - printf("Invalid P2P_PRESENCE_REQ command: needs two arguments " - "(preferred duration, interval; in microsecods).\n" - "Optional second pair can be used to provide " - "acceptable values.\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv); -} - - -static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - if (argc != 0 && argc != 2) { - printf("Invalid P2P_EXT_LISTEN command: needs two arguments " - "(availability period, availability interval; in " - "millisecods).\n" - "Extended Listen Timing can be cancelled with this " - "command when used without parameters.\n"); - return -1; - } - - return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv); -} - - -static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv); -} - -#endif /* CONFIG_P2P */ - - -static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv); -} - - -static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv); -} - - -static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv); -} - - -#ifdef CONFIG_WIFI_DISPLAY - -static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[100]; - int res; - - if (argc != 1 && argc != 2) { - printf("Invalid WFD_SUBELEM_SET command: needs one or two " - "arguments (subelem, hexdump)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s", - argv[0], argc > 1 ? argv[1] : ""); - if (os_snprintf_error(sizeof(cmd), res)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[100]; - int res; - - if (argc != 1) { - printf("Invalid WFD_SUBELEM_GET command: needs one " - "argument (subelem)\n"); - return -1; - } - - res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s", - argv[0]); - if (os_snprintf_error(sizeof(cmd), res)) - return -1; - cmd[sizeof(cmd) - 1] = '\0'; - return wpa_ctrl_command(ctrl, cmd); -} -#endif /* CONFIG_WIFI_DISPLAY */ - - -#ifdef CONFIG_INTERWORKING -static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "FETCH_ANQP"); -} - - -static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP"); -} - - -static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv); -} - - -static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv); -} - - -static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv); -} - - -static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); -} - - -static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv); -} - - -static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv); -} -#endif /* CONFIG_INTERWORKING */ - - -#ifdef CONFIG_HS20 - -static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv); -} - - -static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[512]; - - if (argc == 0) { - printf("Command needs one or two arguments (dst mac addr and " - "optional home realm)\n"); - return -1; - } - - if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST", - argc, argv) < 0) - return -1; - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - char cmd[512]; - - if (argc < 2) { - printf("Command needs two arguments (dst mac addr and " - "icon name)\n"); - return -1; - } - - if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0) - return -1; - - return wpa_ctrl_command(ctrl, cmd); -} - - -static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "FETCH_OSU"); -} - - -static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU"); -} - -#endif /* CONFIG_HS20 */ - - -static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv); -} - - -static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv); -} - - -static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv); -} - - -static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv); -} - - -static int wpa_cli_cmd_tdls_link_status(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_LINK_STATUS", 1, argc, argv); -} - - -static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv); -} - - -static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv); -} - - -static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "WMM_AC_STATUS"); -} - - -static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv); -} - - -static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv); -} - - -static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "SIGNAL_POLL"); -} - - -static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv); -} - - -static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "PKTCNT_POLL"); -} - - -static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "REAUTHENTICATE"); -} - - -#ifdef CONFIG_AUTOSCAN - -static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc == 0) - return wpa_ctrl_command(ctrl, "AUTOSCAN "); - - return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv); -} - -#endif /* CONFIG_AUTOSCAN */ - - -#ifdef CONFIG_WNM - -static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv); -} - - -static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv); -} - -#endif /* CONFIG_WNM */ - - -static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - if (argc == 0) - return -1; - return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); -} - - -#ifdef ANDROID -static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DRIVER", 1, argc, argv); -} -#endif /* ANDROID */ - - -static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv); -} - - -static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "FLUSH"); -} - - -static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); -} - - -static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv); -} - - -static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv); -} - - -static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "TWT_TEARDOWN", 0, argc, argv); -} - - -static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_ctrl_command(ctrl, "ERP_FLUSH"); -} - - -static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv); -} - - -static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "GET_PREF_FREQ_LIST", 1, argc, argv); -} - - -static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv); -} - - -static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv); -} - - -#ifdef CONFIG_DPP - -static int wpa_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN"); -} - - -static int wpa_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); -} - - -static int wpa_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); -} - - -#ifdef CONFIG_DPP2 - -static int wpa_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP"); -} - - -static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv); -} - - -static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP"); -} - -#endif /* CONFIG_DPP2 */ -#endif /* CONFIG_DPP */ - - -static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd) -{ - char buf[512], *pos, *bssid = NULL, *freq = NULL, *level = NULL, - *flags = NULL, *ssid = NULL; - size_t len; - int ret, id = -1; - - if (!ctrl_conn) - return -1; - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, - wpa_cli_msg_cb); - if (ret == -2) { - printf("'%s' command timed out.\n", cmd); - return -2; - } else if (ret < 0) { - printf("'%s' command failed.\n", cmd); - return -1; - } - - buf[len] = '\0'; - if (os_memcmp(buf, "FAIL", 4) == 0) - return -1; - - pos = buf; - while (*pos != '\0') { - if (str_starts(pos, "id=")) - id = atoi(pos + 3); - if (str_starts(pos, "bssid=")) - bssid = pos + 6; - if (str_starts(pos, "freq=")) - freq = pos + 5; - if (str_starts(pos, "level=")) - level = pos + 6; - if (str_starts(pos, "flags=")) - flags = pos + 6; - if (str_starts(pos, "ssid=")) - ssid = pos + 5; - - while (*pos != '\0' && *pos != '\n') - pos++; - *pos++ = '\0'; - } - if (id != -1) - printf("%s\t%s\t%s\t%s\t%s\n", bssid ? bssid : "N/A", - freq ? freq : "N/A", level ? level : "N/A", - flags ? flags : "N/A", ssid ? ssid : "N/A"); - return id; -} - - -static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - char cmd[64]; - int id = -1; - unsigned int mask; - - printf("bssid / frequency / signal level / flags / ssid\n"); - - mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ | - WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID; - do { - if (id < 0) - os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x", - mask); - else - os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x", - id, mask); - id = wpa_ctrl_command_bss(ctrl, cmd); - } while (id >= 0); - - return 0; -} - - -#ifdef CONFIG_PASN - -static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv); -} - - -static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv); -} - -static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PTKSA_CACHE_LIST", 0, argc, argv); -} - - -static int wpa_cli_cmd_pasn_deauth(struct wpa_ctrl *ctrl, int argc, - char *argv[]) -{ - return wpa_cli_cmd(ctrl, "PASN_DEAUTH", 1, argc, argv); -} - -#endif /* CONFIG_PASN */ - - -static int wpa_cli_cmd_mscs(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "MSCS", 1, argc, argv); -} - - -static int wpa_cli_cmd_scs(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "SCS", 2, argc, argv); -} - - -static int wpa_cli_cmd_dscp_resp(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DSCP_RESP", 1, argc, argv); -} - - -static int wpa_cli_cmd_dscp_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) -{ - return wpa_cli_cmd(ctrl, "DSCP_QUERY", 1, argc, argv); -} - - -enum wpa_cli_cmd_flags { - cli_cmd_flag_none = 0x00, - cli_cmd_flag_sensitive = 0x01 -}; - -struct wpa_cli_cmd { - const char *cmd; - int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); - char ** (*completion)(const char *str, int pos); - enum wpa_cli_cmd_flags flags; - const char *usage; -}; - -static const struct wpa_cli_cmd wpa_cli_commands[] = { - { "status", wpa_cli_cmd_status, NULL, - cli_cmd_flag_none, - "[verbose] = get current WPA/EAPOL/EAP status" }, - { "ifname", wpa_cli_cmd_ifname, NULL, - cli_cmd_flag_none, - "= get current interface name" }, - { "ping", wpa_cli_cmd_ping, NULL, - cli_cmd_flag_none, - "= pings wpa_supplicant" }, - { "relog", wpa_cli_cmd_relog, NULL, - cli_cmd_flag_none, - "= re-open log-file (allow rolling logs)" }, - { "note", wpa_cli_cmd_note, NULL, - cli_cmd_flag_none, - " = add a note to wpa_supplicant debug log" }, - { "mib", wpa_cli_cmd_mib, NULL, - cli_cmd_flag_none, - "= get MIB variables (dot1x, dot11)" }, - { "help", wpa_cli_cmd_help, wpa_cli_complete_help, - cli_cmd_flag_none, - "[command] = show usage help" }, - { "interface", wpa_cli_cmd_interface, NULL, - cli_cmd_flag_none, - "[ifname] = show interfaces/select interface" }, - { "level", wpa_cli_cmd_level, NULL, - cli_cmd_flag_none, - " = change debug level" }, - { "license", wpa_cli_cmd_license, NULL, - cli_cmd_flag_none, - "= show full wpa_cli license" }, - { "quit", wpa_cli_cmd_quit, NULL, - cli_cmd_flag_none, - "= exit wpa_cli" }, - { "set", wpa_cli_cmd_set, wpa_cli_complete_set, - cli_cmd_flag_none, - "= set variables (shows list of variables when run without " - "arguments)" }, - { "dump", wpa_cli_cmd_dump, NULL, - cli_cmd_flag_none, - "= dump config variables" }, - { "get", wpa_cli_cmd_get, wpa_cli_complete_get, - cli_cmd_flag_none, - " = get information" }, - { "driver_flags", wpa_cli_cmd_driver_flags, NULL, - cli_cmd_flag_none, - "= list driver flags" }, - { "logon", wpa_cli_cmd_logon, NULL, - cli_cmd_flag_none, - "= IEEE 802.1X EAPOL state machine logon" }, - { "logoff", wpa_cli_cmd_logoff, NULL, - cli_cmd_flag_none, - "= IEEE 802.1X EAPOL state machine logoff" }, - { "pmksa", wpa_cli_cmd_pmksa, NULL, - cli_cmd_flag_none, - "= show PMKSA cache" }, - { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL, - cli_cmd_flag_none, - "= flush PMKSA cache entries" }, -#ifdef CONFIG_PMKSA_CACHE_EXTERNAL - { "pmksa_get", wpa_cli_cmd_pmksa_get, NULL, - cli_cmd_flag_none, - " = fetch all stored PMKSA cache entries" }, - { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL, - cli_cmd_flag_sensitive, - " = store PMKSA cache entry from external storage" }, -#ifdef CONFIG_MESH - { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL, - cli_cmd_flag_none, - " = fetch all stored mesh PMKSA cache entries" }, - { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL, - cli_cmd_flag_sensitive, - " = store mesh PMKSA cache entry from external storage" }, -#endif /* CONFIG_MESH */ -#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ - { "reassociate", wpa_cli_cmd_reassociate, NULL, - cli_cmd_flag_none, - "= force reassociation" }, - { "reattach", wpa_cli_cmd_reattach, NULL, - cli_cmd_flag_none, - "= force reassociation back to the same BSS" }, - { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, - cli_cmd_flag_none, - " = force preauthentication" }, - { "identity", wpa_cli_cmd_identity, wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = configure identity for an SSID" }, - { "password", wpa_cli_cmd_password, wpa_cli_complete_network_id, - cli_cmd_flag_sensitive, - " = configure password for an SSID" }, - { "new_password", wpa_cli_cmd_new_password, - wpa_cli_complete_network_id, cli_cmd_flag_sensitive, - " = change password for an SSID" }, - { "pin", wpa_cli_cmd_pin, wpa_cli_complete_network_id, - cli_cmd_flag_sensitive, - " = configure pin for an SSID" }, - { "otp", wpa_cli_cmd_otp, wpa_cli_complete_network_id, - cli_cmd_flag_sensitive, - " = configure one-time-password for an SSID" - }, - { "psk_passphrase", wpa_cli_cmd_psk_passphrase, - wpa_cli_complete_network_id, cli_cmd_flag_sensitive, - " = configure PSK/passphrase for an SSID" }, - { "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id, - cli_cmd_flag_sensitive, - " = configure private key passphrase\n" - " for an SSID" }, - { "sim", wpa_cli_cmd_sim, wpa_cli_complete_network_id, - cli_cmd_flag_sensitive, - " = report SIM operation result" }, - { "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = set preferred BSSID for an SSID" }, - { "bssid_ignore", wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss, - cli_cmd_flag_none, - " = add a BSSID to the list of temporarily ignored BSSs\n" - "bssid_ignore clear = clear the list of temporarily ignored BSSIDs\n" - "bssid_ignore = display the list of temporarily ignored BSSIDs" }, - { "blacklist", /* deprecated alias for bssid_ignore */ - wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss, - cli_cmd_flag_none, - "= deprecated alias for bssid_ignore" }, - { "log_level", wpa_cli_cmd_log_level, NULL, - cli_cmd_flag_none, - " [] = update the log level/timestamp\n" - "log_level = display the current log level and log options" }, - { "list_networks", wpa_cli_cmd_list_networks, NULL, - cli_cmd_flag_none, - "= list configured networks" }, - { "select_network", wpa_cli_cmd_select_network, - wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = select a network (disable others)" }, - { "enable_network", wpa_cli_cmd_enable_network, - wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = enable a network" }, - { "disable_network", wpa_cli_cmd_disable_network, - wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = disable a network" }, - { "add_network", wpa_cli_cmd_add_network, NULL, - cli_cmd_flag_none, - "= add a network" }, - { "remove_network", wpa_cli_cmd_remove_network, - wpa_cli_complete_network_id, - cli_cmd_flag_none, - " = remove a network" }, - { "set_network", wpa_cli_cmd_set_network, wpa_cli_complete_network, - cli_cmd_flag_sensitive, - " = set network variables (shows\n" - " list of variables when run without arguments)" }, - { "get_network", wpa_cli_cmd_get_network, wpa_cli_complete_network, - cli_cmd_flag_none, - " = get network variables" }, - { "dup_network", wpa_cli_cmd_dup_network, wpa_cli_complete_dup_network, - cli_cmd_flag_none, - " = duplicate network variables" - }, - { "list_creds", wpa_cli_cmd_list_creds, NULL, - cli_cmd_flag_none, - "= list configured credentials" }, - { "add_cred", wpa_cli_cmd_add_cred, NULL, - cli_cmd_flag_none, - "= add a credential" }, - { "remove_cred", wpa_cli_cmd_remove_cred, NULL, - cli_cmd_flag_none, - " = remove a credential" }, - { "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred, - cli_cmd_flag_sensitive, - " = set credential variables" }, - { "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred, - cli_cmd_flag_none, - " = get credential variables" }, - { "save_config", wpa_cli_cmd_save_config, NULL, - cli_cmd_flag_none, - "= save the current configuration" }, - { "disconnect", wpa_cli_cmd_disconnect, NULL, - cli_cmd_flag_none, - "= disconnect and wait for reassociate/reconnect command before\n" - " connecting" }, - { "reconnect", wpa_cli_cmd_reconnect, NULL, - cli_cmd_flag_none, - "= like reassociate, but only takes effect if already disconnected" - }, - { "scan", wpa_cli_cmd_scan, NULL, - cli_cmd_flag_none, - "= request new BSS scan" }, - { "scan_results", wpa_cli_cmd_scan_results, NULL, - cli_cmd_flag_none, - "= get latest scan results" }, - { "abort_scan", wpa_cli_cmd_abort_scan, NULL, - cli_cmd_flag_none, - "= request ongoing scan to be aborted" }, - { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss, - cli_cmd_flag_none, - "< | > = get detailed scan result info" }, - { "get_capability", wpa_cli_cmd_get_capability, - wpa_cli_complete_get_capability, cli_cmd_flag_none, - " " - "= get capabilities" }, - { "reconfigure", wpa_cli_cmd_reconfigure, NULL, - cli_cmd_flag_none, - "= force wpa_supplicant to re-read its configuration file" }, - { "terminate", wpa_cli_cmd_terminate, NULL, - cli_cmd_flag_none, - "= terminate wpa_supplicant" }, - { "interface_add", wpa_cli_cmd_interface_add, NULL, - cli_cmd_flag_none, - " \n" - " = adds new interface, all " - "parameters but\n" - " are optional. Supported types are station ('sta') and " - "AP ('ap')" }, - { "interface_remove", wpa_cli_cmd_interface_remove, NULL, - cli_cmd_flag_none, - " = removes the interface" }, - { "interface_list", wpa_cli_cmd_interface_list, NULL, - cli_cmd_flag_none, - "= list available interfaces" }, - { "ap_scan", wpa_cli_cmd_ap_scan, NULL, - cli_cmd_flag_none, - " = set ap_scan parameter" }, - { "scan_interval", wpa_cli_cmd_scan_interval, NULL, - cli_cmd_flag_none, - " = set scan_interval parameter (in seconds)" }, - { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL, - cli_cmd_flag_none, - " = set BSS expiration age parameter" }, - { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL, - cli_cmd_flag_none, - " = set BSS expiration scan count parameter" }, - { "bss_flush", wpa_cli_cmd_bss_flush, NULL, - cli_cmd_flag_none, - " = set BSS flush age (0 by default)" }, - { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, - cli_cmd_flag_none, - " = request over-the-DS FT with " }, - { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss, - cli_cmd_flag_none, - "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, - { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss, - cli_cmd_flag_sensitive, - " [PIN] = start WPS PIN method (returns PIN, if not " - "hardcoded)" }, - { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL, - cli_cmd_flag_sensitive, - " = verify PIN checksum" }, - { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none, - "Cancels the pending WPS operation" }, -#ifdef CONFIG_WPS_NFC - { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss, - cli_cmd_flag_none, - "[BSSID] = start Wi-Fi Protected Setup: NFC" }, - { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL, - cli_cmd_flag_none, - " = build configuration token" }, - { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL, - cli_cmd_flag_none, - " = create password token" }, - { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL, - cli_cmd_flag_sensitive, - " = report read NFC tag with WPS data" }, - { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL, - cli_cmd_flag_none, - " = create NFC handover request" }, - { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL, - cli_cmd_flag_none, - " = create NFC handover select" }, - { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL, - cli_cmd_flag_none, - " = report completed " - "NFC handover" }, -#endif /* CONFIG_WPS_NFC */ - { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss, - cli_cmd_flag_sensitive, - " = start WPS Registrar to configure an AP" }, - { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL, - cli_cmd_flag_sensitive, - "[params..] = enable/disable AP PIN" }, - { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL, - cli_cmd_flag_none, - "[IP address] = start Wi-Fi Protected Setup External Registrar" }, - { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL, - cli_cmd_flag_none, - "= stop Wi-Fi Protected Setup External Registrar" }, - { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL, - cli_cmd_flag_sensitive, - " = add an Enrollee PIN to External Registrar" }, - { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL, - cli_cmd_flag_none, - " = accept an Enrollee PBC using External Registrar" }, - { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL, - cli_cmd_flag_sensitive, - " = learn AP configuration" }, - { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL, - cli_cmd_flag_none, - " = set AP configuration for enrolling" }, - { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL, - cli_cmd_flag_sensitive, - " = configure AP" }, -#ifdef CONFIG_WPS_NFC - { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL, - cli_cmd_flag_none, - " = build NFC configuration token" }, -#endif /* CONFIG_WPS_NFC */ - { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL, - cli_cmd_flag_none, - " = request RSN authentication with in IBSS" }, -#ifdef CONFIG_AP - { "sta", wpa_cli_cmd_sta, wpa_cli_complete_sta, - cli_cmd_flag_none, - " = get information about an associated station (AP)" }, - { "all_sta", wpa_cli_cmd_all_sta, NULL, - cli_cmd_flag_none, - "= get information about all associated stations (AP)" }, - { "list_sta", wpa_cli_cmd_list_sta, NULL, - cli_cmd_flag_none, - "= list all stations (AP)" }, - { "deauthenticate", wpa_cli_cmd_deauthenticate, - wpa_cli_complete_deauthenticate, cli_cmd_flag_none, - " = deauthenticate a station" }, - { "disassociate", wpa_cli_cmd_disassociate, - wpa_cli_complete_disassociate, cli_cmd_flag_none, - " = disassociate a station" }, - { "chan_switch", wpa_cli_cmd_chanswitch, NULL, - cli_cmd_flag_none, - " [sec_channel_offset=] [center_freq1=]" - " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]" - " = CSA parameters" }, - { "update_beacon", wpa_cli_cmd_update_beacon, NULL, - cli_cmd_flag_none, - "= update Beacon frame contents"}, -#endif /* CONFIG_AP */ - { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, - "= notification of suspend/hibernate" }, - { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none, - "= notification of resume/thaw" }, -#ifdef CONFIG_TESTING_OPTIONS - { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, - "= drop SA without deauth/disassoc (test command)" }, -#endif /* CONFIG_TESTING_OPTIONS */ - { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, - cli_cmd_flag_none, - " = roam to the specified BSS" }, -#ifdef CONFIG_MESH - { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL, - cli_cmd_flag_none, - "[ifname] = Create a new mesh interface" }, - { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL, - cli_cmd_flag_none, - " = join a mesh network (disable others)" }, - { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL, - cli_cmd_flag_none, - " = Remove mesh group interface" }, - { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL, - cli_cmd_flag_none, - " = Remove a mesh peer" }, - { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL, - cli_cmd_flag_none, - " [duration=] = Add a mesh peer" }, - { "mesh_link_probe", wpa_cli_cmd_mesh_link_probe, NULL, - cli_cmd_flag_none, - " [payload=] = Probe a mesh link for a given peer by injecting a frame." }, -#endif /* CONFIG_MESH */ -#ifdef CONFIG_P2P - { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, - cli_cmd_flag_none, - "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, - { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, - "= stop P2P Devices search" }, - { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL, - cli_cmd_flag_none, - " adv_id= conncap= [info=] = provision with a P2P ASP Device" }, - { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL, - cli_cmd_flag_none, - " adv_id= [role] [info=] = provision with a P2P ASP Device" }, - { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, - cli_cmd_flag_none, - " <\"pbc\"|PIN> [ht40] = connect to a P2P Device" }, - { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none, - "[timeout] = listen for P2P Devices for up-to timeout seconds" }, - { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, - wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none, - " = remove P2P group interface (terminate group if GO)" }, - { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none, - "[ht40] = add a new P2P group (local end as GO)" }, - { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL, - cli_cmd_flag_none, - " = Get peer interface address on local GO using peer Device Address" }, - { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, - wpa_cli_complete_p2p_peer, cli_cmd_flag_none, - " = request provisioning discovery" }, - { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL, - cli_cmd_flag_none, - "= get the passphrase for a group (GO only)" }, - { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req, - wpa_cli_complete_p2p_peer, cli_cmd_flag_none, - " = schedule service discovery request" }, - { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req, - NULL, cli_cmd_flag_none, - " = cancel pending service discovery request" }, - { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL, - cli_cmd_flag_none, - " = service discovery response" }, - { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL, - cli_cmd_flag_none, - "= indicate change in local services" }, - { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL, - cli_cmd_flag_none, - " = set external processing of service discovery" }, - { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL, - cli_cmd_flag_none, - "= remove all stored service entries" }, - { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL, - cli_cmd_flag_none, - " = add a local " - "service" }, - { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL, - cli_cmd_flag_none, - "asp [] = replace " - "local ASP service" }, - { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL, - cli_cmd_flag_none, - " [|service] = remove a local " - "service" }, - { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer, - cli_cmd_flag_none, - " = reject connection attempts from a specific peer" }, - { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL, - cli_cmd_flag_none, - " [peer=addr] = invite peer" }, - { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none, - "[discovered] = list known (optionally, only fully discovered) P2P " - "peers" }, - { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer, - cli_cmd_flag_none, - "
= show information about known P2P peer" }, - { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set, - cli_cmd_flag_none, - " = set a P2P parameter" }, - { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none, - "= flush P2P state" }, - { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none, - "= cancel P2P group formation" }, - { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, - wpa_cli_complete_p2p_peer, cli_cmd_flag_none, - "
= unauthorize a peer" }, - { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL, - cli_cmd_flag_none, - "[ ] [ ] = request GO " - "presence" }, - { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL, - cli_cmd_flag_none, - "[ ] = set extended listen timing" }, - { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client, - wpa_cli_complete_p2p_peer, cli_cmd_flag_none, - " = remove a peer from all groups" }, -#endif /* CONFIG_P2P */ - { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL, - cli_cmd_flag_none, - " = add vendor specific IEs to frame(s)\n" - VENDOR_ELEM_FRAME_ID }, - { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL, - cli_cmd_flag_none, - " = get vendor specific IE(s) to frame(s)\n" - VENDOR_ELEM_FRAME_ID }, - { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL, - cli_cmd_flag_none, - " = remove vendor specific IE(s) in frame(s)\n" - VENDOR_ELEM_FRAME_ID }, -#ifdef CONFIG_WIFI_DISPLAY - { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, - cli_cmd_flag_none, - " [contents] = set Wi-Fi Display subelement" }, - { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL, - cli_cmd_flag_none, - " = get Wi-Fi Display subelement" }, -#endif /* CONFIG_WIFI_DISPLAY */ -#ifdef CONFIG_INTERWORKING - { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none, - "= fetch ANQP information for all APs" }, - { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL, - cli_cmd_flag_none, - "= stop fetch_anqp operation" }, - { "interworking_select", wpa_cli_cmd_interworking_select, NULL, - cli_cmd_flag_none, - "[auto] = perform Interworking network selection" }, - { "interworking_connect", wpa_cli_cmd_interworking_connect, - wpa_cli_complete_bss, cli_cmd_flag_none, - " = connect using Interworking credentials" }, - { "interworking_add_network", wpa_cli_cmd_interworking_add_network, - wpa_cli_complete_bss, cli_cmd_flag_none, - " = connect using Interworking credentials" }, - { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, - cli_cmd_flag_none, - " [,]... = request ANQP information" }, - { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss, - cli_cmd_flag_none, - " [QueryReq] = GAS request" }, - { "gas_response_get", wpa_cli_cmd_gas_response_get, - wpa_cli_complete_bss, cli_cmd_flag_none, - " [start,len] = Fetch last GAS response" }, -#endif /* CONFIG_INTERWORKING */ -#ifdef CONFIG_HS20 - { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss, - cli_cmd_flag_none, - " [,]... = request HS 2.0 ANQP information" - }, - { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list, - wpa_cli_complete_bss, cli_cmd_flag_none, - " = get HS20 nai home realm list" }, - { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request, - wpa_cli_complete_bss, cli_cmd_flag_none, - " = get Hotspot 2.0 OSU icon" }, - { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none, - "= fetch OSU provider information from all APs" }, - { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL, - cli_cmd_flag_none, - "= cancel fetch_osu command" }, -#endif /* CONFIG_HS20 */ - { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL, - cli_cmd_flag_none, - "<0/1> = disable/enable automatic reconnection" }, - { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL, - cli_cmd_flag_none, - " = request TDLS discovery with " }, - { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL, - cli_cmd_flag_none, - " = request TDLS setup with " }, - { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL, - cli_cmd_flag_none, - " = tear down TDLS with " }, - { "tdls_link_status", wpa_cli_cmd_tdls_link_status, NULL, - cli_cmd_flag_none, - " = TDLS link status with " }, - { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL, - cli_cmd_flag_none, - " [nominal_msdu_size=#] " - "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] " - "= add WMM-AC traffic stream" }, - { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL, - cli_cmd_flag_none, - " = delete WMM-AC traffic stream" }, - { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL, - cli_cmd_flag_none, - "= show status for Wireless Multi-Media Admission-Control" }, - { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL, - cli_cmd_flag_none, - " [sec_channel_offset=] [center_freq1=] " - "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching " - "with TDLS peer" }, - { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL, - cli_cmd_flag_none, - " = disable channel switching with TDLS peer " }, - { "signal_poll", wpa_cli_cmd_signal_poll, NULL, - cli_cmd_flag_none, - "= get signal parameters" }, - { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL, - cli_cmd_flag_none, - "= set signal monitor parameters" }, - { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, - cli_cmd_flag_none, - "= get TX/RX packet counters" }, - { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL, - cli_cmd_flag_none, - "= trigger IEEE 802.1X/EAPOL reauthentication" }, -#ifdef CONFIG_AUTOSCAN - { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none, - "[params] = Set or unset (if none) autoscan parameters" }, -#endif /* CONFIG_AUTOSCAN */ -#ifdef CONFIG_WNM - { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, - " [interval=#] = enter/exit WNM-Sleep mode" }, - { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, - " [list]" - " [neighbor=,,,,[,]" - " = Send BSS Transition Management Query" }, -#endif /* CONFIG_WNM */ - { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, - " = Sent unprocessed command" }, - { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, - "= flush wpa_supplicant state" }, -#ifdef ANDROID - { "driver", wpa_cli_cmd_driver, NULL, cli_cmd_flag_none, - " = driver private commands" }, -#endif /* ANDROID */ - { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, - "= radio_work " }, - { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none, - " [] = Send vendor command" - }, - { "neighbor_rep_request", - wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none, - "[ssid=] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)" - }, - { "twt_setup", - wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none, - "[dialog=] [exponent=] [mantissa=] [min_twt=] [setup_cmd=] [twt=] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=] [control=] = Send TWT Setup frame" - }, - { "twt_teardown", - wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none, - "[flags=] = Send TWT Teardown frame" - }, - { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, - "= flush ERP keys" }, - { "mac_rand_scan", - wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none, - " enable=<0/1> [addr=mac-address " - "mask=mac-address-mask] = scan MAC randomization" - }, - { "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL, - cli_cmd_flag_none, - " = retrieve preferred freq list for the specified interface type" }, - { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL, - cli_cmd_flag_none, - " = start P2P listen offload" }, - { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL, - cli_cmd_flag_none, - "= stop P2P listen offload" }, -#ifdef CONFIG_DPP - { "dpp_qr_code", wpa_cli_cmd_dpp_qr_code, NULL, cli_cmd_flag_none, - "report a scanned DPP URI from a QR Code" }, - { "dpp_bootstrap_gen", wpa_cli_cmd_dpp_bootstrap_gen, NULL, - cli_cmd_flag_sensitive, - "type= [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, - { "dpp_bootstrap_remove", wpa_cli_cmd_dpp_bootstrap_remove, NULL, - cli_cmd_flag_none, - "*| = remove DPP bootstrap information" }, - { "dpp_bootstrap_get_uri", wpa_cli_cmd_dpp_bootstrap_get_uri, NULL, - cli_cmd_flag_none, - " = get DPP bootstrap URI" }, - { "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL, - cli_cmd_flag_none, - " = show DPP bootstrap information" }, - { "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL, - cli_cmd_flag_none, - " [conf=..] [ssid=] [ssid_charset=#] [psk=] [pass=] [configurator=] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" }, - { "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none, - "peer= [own=] = initiate DPP bootstrapping" }, - { "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none, - " = start DPP listen" }, - { "dpp_stop_listen", wpa_cli_cmd_dpp_stop_listen, NULL, - cli_cmd_flag_none, - "= stop DPP listen" }, - { "dpp_configurator_add", wpa_cli_cmd_dpp_configurator_add, NULL, - cli_cmd_flag_sensitive, - "[curve=..] [key=..] = add DPP configurator" }, - { "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL, - cli_cmd_flag_none, - "*| = remove DPP configurator" }, - { "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key, - NULL, cli_cmd_flag_none, - " = Get DPP configurator's private key" }, - { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL, - cli_cmd_flag_none, - "conf= configurator= = generate self DPP configuration" }, - { "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL, - cli_cmd_flag_sensitive, - "add PKEX code" }, - { "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL, - cli_cmd_flag_none, - "*| = remove DPP pkex information" }, -#ifdef CONFIG_DPP2 - { "dpp_controller_start", wpa_cli_cmd_dpp_controller_start, NULL, - cli_cmd_flag_none, - "[tcp_port=] [role=..] = start DPP controller" }, - { "dpp_controller_stop", wpa_cli_cmd_dpp_controller_stop, NULL, - cli_cmd_flag_none, - "= stop DPP controller" }, - { "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL, - cli_cmd_flag_none, - "own= iter= = start DPP chirp" }, - { "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL, - cli_cmd_flag_none, - "= stop DPP chirp" }, -#endif /* CONFIG_DPP2 */ -#endif /* CONFIG_DPP */ - { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none, - "= list all BSS entries (scan results)" }, -#ifdef CONFIG_PASN - { "pasn_auth_start", wpa_cli_cmd_pasn_auth_start, NULL, - cli_cmd_flag_none, - "bssid= akmp= cipher= group= nid= = Start PASN authentication" }, - { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL, - cli_cmd_flag_none, - "= Stop PASN authentication" }, - { "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL, - cli_cmd_flag_none, - "= Get the PTKSA Cache" }, - { "pasn_deauth", wpa_cli_cmd_pasn_deauth, NULL, - cli_cmd_flag_none, - "bssid= = Remove PASN PTKSA state" }, -#endif /* CONFIG_PASN */ - { "mscs", wpa_cli_cmd_mscs, NULL, - cli_cmd_flag_none, - " [up_bitmap=] [up_limit=] [stream_timeout=] [frame_classifier=] = Configure MSCS request" }, - { "scs", wpa_cli_cmd_scs, NULL, - cli_cmd_flag_none, - "[scs_id=] [scs_up=<0-7>] [classifier_type=<4|10>] [classifier params based on classifier type] [tclas_processing=<0|1>] [scs_id=] ... = Send SCS request" }, - { "dscp_resp", wpa_cli_cmd_dscp_resp, NULL, - cli_cmd_flag_none, - "<[reset]>/<[solicited] [policy_id=1 status=0...]> [more] = Send DSCP response" }, - { "dscp_query", wpa_cli_cmd_dscp_query, NULL, - cli_cmd_flag_none, - "wildcard/domain_name= = Send DSCP Query" }, - { NULL, NULL, NULL, cli_cmd_flag_none, NULL } -}; - - /* * Prints command usage, lines are padded with the specified string. */ diff --git a/wpa_supplicant/wpa_cli_cmds.c b/wpa_supplicant/wpa_cli_cmds.c new file mode 100644 index 000000000..abecced0f --- /dev/null +++ b/wpa_supplicant/wpa_cli_cmds.c @@ -0,0 +1,3696 @@ +/* + * WPA CLI commands + * Copyright (c) 2004-2022, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "includes.h" + +#include "common/cli.h" +#include "common/wpa_ctrl.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/edit.h" +#include "utils/list.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "common/version.h" +#include "common/ieee802_11_defs.h" + +#define CMD_BUF_LEN 1024 + +#define VENDOR_ELEM_FRAME_ID \ + " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ + "3: Beacon (GO), 4: PD Req, 5: PD Resp, 6: GO Neg Req, " \ + "7: GO Neg Resp, 8: GO Neg Conf, 9: Inv Req, 10: Inv Resp, " \ + "11: Assoc Req (P2P), 12: Assoc Resp (P2P)" + +static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(creds); /* struct cli_txt_entry */ +#ifdef CONFIG_AP +static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */ +#endif /* CONFIG_AP */ + +static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args, + int argc, char *argv[]) +{ + char * buf = NULL; + int ret = 0; + if (argc < min_args) { + wpa_printf(MSG_INFO, "Invalid %s command - at least %d argument%s " + "required.\n", cmd, min_args, + min_args > 1 ? "s are" : " is"); + return -1; + } + buf = os_zalloc(sizeof(char) * CMD_BUF_LEN); + if (!buf){ + wpa_printf(MSG_ERROR, "Failed to allocate mem for command buf - %d\n", + CMD_BUF_LEN); + return -1; + } + memset(buf, '\0', CMD_BUF_LEN); + if (write_cmd(buf, CMD_BUF_LEN, cmd, argc-1, argv) < 0){ + ret = -1; + goto out; + } + ret = wpa_ctrl_command(ctrl, buf); + +out: + if (buf) + os_free(buf); + + return ret; +} + + +static const char *network_fields[] = { + "ssid", "scan_ssid", "bssid", "bssid_ignore", + "bssid_accept", "psk", "proto", "key_mgmt", + "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq", + "freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1", + "vht_center_freq2", "ht", "edmg", +#ifdef IEEE8021X_EAPOL + "eap", "identity", "anonymous_identity", "password", "ca_cert", + "ca_path", "client_cert", "private_key", "private_key_passwd", + "dh_file", "subject_match", "altsubject_match", + "check_cert_subject", + "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", + "client_cert2", "private_key2", "private_key2_passwd", + "dh_file2", "subject_match2", "altsubject_match2", + "check_cert_subject2", + "domain_suffix_match2", "domain_match2", "phase1", "phase2", + "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", + "pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id", + "engine", "engine2", "eapol_flags", "sim_num", + "openssl_ciphers", "erp", +#endif /* IEEE8021X_EAPOL */ + "wep_key0", "wep_key1", "wep_key2", "wep_key3", + "wep_tx_keyidx", "priority", +#ifdef IEEE8021X_EAPOL + "eap_workaround", "pac_file", "fragment_size", "ocsp", +#endif /* IEEE8021X_EAPOL */ + "mode", + "proactive_key_caching", "disabled", "id_str", + "ieee80211w", + "mixed_cell", "frequency", "fixed_freq", +#ifdef CONFIG_MESH + "no_auto_peer", "mesh_rssi_threshold", + "mesh_basic_rates", "dot11MeshMaxRetries", + "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout", + "dot11MeshHoldingTimeout", +#endif /* CONFIG_MESH */ + "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid", + "wpa_deny_ptk0_rekey", + "enable_edmg", "edmg_channel", +#ifdef CONFIG_P2P + "go_p2p_dev_addr", "p2p_client_list", "psk_list", +#endif /* CONFIG_P2P */ +#ifdef CONFIG_HT_OVERRIDES + "disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc", + "ht40_intolerant", "disable_max_amsdu", "ampdu_factor", + "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc", +#endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + "disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1", + "vht_rx_mcs_nss_2", "vht_rx_mcs_nss_3", "vht_rx_mcs_nss_4", + "vht_rx_mcs_nss_5", "vht_rx_mcs_nss_6", "vht_rx_mcs_nss_7", + "vht_rx_mcs_nss_8", "vht_tx_mcs_nss_1", "vht_tx_mcs_nss_2", + "vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5", + "vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8", +#endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + "disable_he", +#endif /* CONFIG_HE_OVERRIDES */ + "ap_max_inactivity", "dtim_period", "beacon_int", +#ifdef CONFIG_MACSEC + "macsec_policy", + "macsec_integ_only", + "macsec_replay_protect", + "macsec_replay_window", + "macsec_port", + "mka_priority", +#endif /* CONFIG_MACSEC */ +#ifdef CONFIG_HS20 + "update_identifier", +#endif /* CONFIG_HS20 */ + "mac_addr", "pbss", "wps_disabled" +}; + + +static char ** wpa_cli_complete_network(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(network_fields); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&networks); + break; + case 2: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(network_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; +} + +static char ** wpa_cli_complete_network_id(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + if (arg == 1) + return cli_txt_list_array(&networks); + return NULL; +} + +static void wpa_cli_show_network_variables(void) +{ + wpa_printf(MSG_INFO, "set_network variables:\n" + " ssid (network name, SSID)\n" + " psk (WPA passphrase or pre-shared key)\n" + " key_mgmt (key management protocol)\n" + " identity (EAP identity)\n" + " password (EAP password)\n" + " ...\n" + "\n" + "Note: Values are entered in the same format as the " + "configuration file is using,\n" + "i.e., strings values need to be inside double quotation " + "marks.\n" + "For example: set_network 1 ssid \"network name\"\n" + "\n" + "Please see wpa_supplicant.conf documentation for full list " + "of\navailable variables.\n"); +} + + +static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc == 0) { + wpa_cli_show_network_variables(); + return 0; + } + + if (argc < 3) { + wpa_printf(MSG_INFO, "Invalid SET_NETWORK command: needs three arguments\n" + "(network id, variable name, and value)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); +} + + +static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc == 0) { + wpa_cli_show_network_variables(); + return 0; + } + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid GET_NETWORK command: needs two arguments\n" + "(network id and variable name)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv); +} + +static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv); +} + + +static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ADD_NETWORK"); +} + + +static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DISCONNECT"); +} + + +static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc > 0 && os_strcmp(argv[0], "verbose") == 0) + return wpa_ctrl_command(ctrl, "STATUS-VERBOSE"); + if (argc > 0 && os_strcmp(argv[0], "wps") == 0) + return wpa_ctrl_command(ctrl, "STATUS-WPS"); + if (argc > 0 && os_strcmp(argv[0], "driver") == 0) + return wpa_ctrl_command(ctrl, "STATUS-DRIVER"); + return wpa_ctrl_command(ctrl, "STATUS"); +} + + + +static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc < 1) { + wpa_printf(MSG_INFO, "Invalid INTERFACE_ADD command: needs at least one " + "argument (interface name)\n" + "All arguments: ifname confname driver ctrl_interface " + "driver_param bridge_name [create]\n"); + return -1; + } + + /* + * INTERFACE_ADD TABTABTABTAB + * TAB[TAB[TAB]] + */ + res = os_snprintf(cmd, sizeof(cmd), + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", + argv[0], + argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", + argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", + argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : "", + argc > 7 ? argv[7] : ""); + if (os_snprintf_error(sizeof(cmd), res)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "INTERFACE_LIST"); +} + + +#if !defined(CONFIG_ZEPHYR) || (defined(CONFIG_ZEPHYR) && defined(CONFIG_WPA_CLI)) +static void wpa_cli_msg_cb(char *msg, size_t len) +{ + wpa_printf(MSG_INFO, "%s\n", msg); +} + +static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "IFNAME"); +} + + +static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PING"); +} + + +static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOG"); +} + + +static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv); +} + + +static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "MIB"); +} + + +static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PMKSA"); +} + + +static int wpa_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PMKSA_FLUSH"); +} + + +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + +static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv); +} + + +static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv); +} + + +#ifdef CONFIG_MESH + +static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv); +} + + +static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv); +} + +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + +static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 1) { + res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]); + if (os_snprintf_error(sizeof(cmd), res)) { + wpa_printf(MSG_INFO, "Too long SET command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); + } + + return wpa_cli_cmd(ctrl, "SET", 2, argc, argv); +} + + +static char ** wpa_cli_complete_set(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + const char *fields[] = { + /* runtime values */ + "EAPOL::heldPeriod", "EAPOL::authPeriod", "EAPOL::startPeriod", + "EAPOL::maxStart", "dot11RSNAConfigPMKLifetime", + "dot11RSNAConfigPMKReauthThreshold", "dot11RSNAConfigSATimeout", + "wps_fragment_size", "wps_version_number", "ampdu", + "tdls_testing", "tdls_disabled", "pno", "radio_disabled", + "uapsd", "ps", "wifi_display", "bssid_filter", "disallow_aps", + "no_keep_alive", + /* global configuration parameters */ + "ctrl_interface", "no_ctrl_interface", "ctrl_interface_group", + "eapol_version", "ap_scan", "bgscan", +#ifdef CONFIG_MESH + "user_mpm", "max_peer_links", "mesh_max_inactivity", + "dot11RSNASAERetransPeriod", +#endif /* CONFIG_MESH */ + "disable_scan_offload", "fast_reauth", "opensc_engine_path", + "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers", + "pcsc_reader", "pcsc_pin", "external_sim", "driver_param", + "dot11RSNAConfigPMKLifetime", + "dot11RSNAConfigPMKReauthThreshold", + "dot11RSNAConfigSATimeout", +#ifndef CONFIG_NO_CONFIG_WRITE + "update_config", +#endif /* CONFIG_NO_CONFIG_WRITE */ + "load_dynamic_eap", +#ifdef CONFIG_WPS + "uuid", "device_name", "manufacturer", "model_name", + "model_number", "serial_number", "device_type", "os_version", + "config_methods", "wps_cred_processing", "wps_vendor_ext_m1", +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + "sec_device_type", + "p2p_listen_reg_class", "p2p_listen_channel", + "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", + "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", + "p2p_group_idle", "p2p_passphrase_len", "p2p_pref_chan", + "p2p_no_go_freq", "p2p_add_cli_chan", + "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht", + "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface", + "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask", + "ip_addr_start", "ip_addr_end", "p2p_go_edmg", +#endif /* CONFIG_P2P */ + "country", "bss_max_count", "bss_expiration_age", + "bss_expiration_scan_count", "filter_ssids", "filter_rssi", + "max_num_sta", "disassoc_low_ack", "ap_isolate", +#ifdef CONFIG_HS20 + "hs20", +#endif /* CONFIG_HS20 */ + "interworking", "hessid", "access_network_type", "pbc_in_m1", + "go_interworking", "go_access_network_type", "go_internet", + "go_venue_group", "go_venue_type", + "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", + "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend", + "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", + "sae_groups", "dtim_period", "beacon_int", + "ap_vendor_elements", "ignore_old_scan_res", "freq_list", + "scan_cur_freq", "scan_res_valid_for_connect", + "sched_scan_interval", + "tdls_external_control", "osu_dir", "wowlan_triggers", + "p2p_search_delay", "mac_addr", "rand_addr_lifetime", + "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", + "reassoc_same_bss_optim", "wps_priority", + "ap_assocresp_elements", +#ifdef CONFIG_TESTING_OPTIONS + "ignore_auth_resp", +#endif /* CONFIG_TESTING_OPTIONS */ + "relative_rssi", "relative_band_adjust", + "extended_key_id", + }; + int i, num_fields = ARRAY_SIZE(fields); + + if (arg == 1) { + char **res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(fields[i]); + if (res[i] == NULL) + return res; + } + return res; + } + + if (arg > 1 && os_strncasecmp(str, "set bssid_filter ", 17) == 0) + return cli_txt_list_array(&bsses); + + return NULL; +} + +static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DUMP"); +} + + +static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS"); +} + + +static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); +} + + +static char ** wpa_cli_complete_get(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + const char *fields[] = { + "ctrl_interface", "ctrl_interface_group", + "eapol_version", "ap_scan", +#ifdef CONFIG_MESH + "user_mpm", "max_peer_links", "mesh_max_inactivity", +#endif /* CONFIG_MESH */ + "disable_scan_offload", "fast_reauth", "opensc_engine_path", + "pkcs11_engine_path", "pkcs11_module_path", "openssl_ciphers", + "pcsc_reader", "pcsc_pin", "external_sim", "driver_param", + "dot11RSNAConfigPMKLifetime", + "dot11RSNAConfigPMKReauthThreshold", + "dot11RSNAConfigSATimeout", +#ifndef CONFIG_NO_CONFIG_WRITE + "update_config", +#endif /* CONFIG_NO_CONFIG_WRITE */ +#ifdef CONFIG_WPS + "device_name", "manufacturer", "model_name", "model_number", + "serial_number", "config_methods", "wps_cred_processing", +#endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + "p2p_listen_reg_class", "p2p_listen_channel", + "p2p_oper_reg_class", "p2p_oper_channel", "p2p_go_intent", + "p2p_ssid_postfix", "persistent_reconnect", "p2p_intra_bss", + "p2p_group_idle", "p2p_passphrase_len", "p2p_add_cli_chan", + "p2p_optimize_listen_chan", "p2p_go_ht40", "p2p_go_vht", + "p2p_disabled", "p2p_go_ctwindow", "p2p_no_group_iface", + "p2p_ignore_shared_freq", "ip_addr_go", "ip_addr_mask", + "ip_addr_start", "ip_addr_end", +#endif /* CONFIG_P2P */ + "bss_max_count", "bss_expiration_age", + "bss_expiration_scan_count", "filter_ssids", "filter_rssi", + "max_num_sta", "disassoc_low_ack", "ap_isolate", +#ifdef CONFIG_HS20 + "hs20", +#endif /* CONFIG_HS20 */ + "interworking", "access_network_type", "pbc_in_m1", "autoscan", + "go_interworking", "go_access_network_type", "go_internet", + "go_venue_group", "go_venue_type", + "wps_nfc_dev_pw_id", "ext_password_backend", + "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", + "dtim_period", "beacon_int", "ignore_old_scan_res", + "scan_cur_freq", "scan_res_valid_for_connect", + "sched_scan_interval", + "sched_scan_start_delay", + "tdls_external_control", "osu_dir", "wowlan_triggers", + "p2p_search_delay", "mac_addr", "rand_addr_lifetime", + "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", + "reassoc_same_bss_optim", "extended_key_id" + }; + int i, num_fields = ARRAY_SIZE(fields); + + if (arg == 1) { + char **res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(fields[i]); + if (res[i] == NULL) + return res; + } + return res; + } + + return NULL; +} + + +static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LOGOFF"); +} + + +static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LOGON"); +} + + +static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "REASSOCIATE"); +} + + +static int wpa_cli_cmd_reattach(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "REATTACH"); +} + + +static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv); +} + + +static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv); +} + + +static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv); +} + + +static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv); +} + + +static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv); +} + + +static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc < 1) + res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0"); + else + res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]); + if (os_snprintf_error(sizeof(cmd), res)) { + wpa_printf(MSG_INFO, "Too long BSS_FLUSH command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv); +} + + +static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc == 0) { + wpa_printf(MSG_INFO, "Invalid WPS_PIN command: need one or two arguments:\n" + "- BSSID: use 'any' to select any\n" + "- PIN: optional, used only with devices that have no " + "display\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "WPS_CANCEL"); +} + + +#ifdef CONFIG_WPS_NFC + +static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv); +} + + +static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + int ret; + char *buf; + size_t buflen; + + if (argc != 1) { + wpa_printf(MSG_INFO, "Invalid 'wps_nfc_tag_read' command - one argument " + "is required.\n"); + return -1; + } + + buflen = 18 + os_strlen(argv[0]); + buf = os_malloc(buflen); + if (buf == NULL) + return -1; + os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]); + + ret = wpa_ctrl_command(ctrl, buf); + os_free(buf); + + return ret; +} + + +static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv); +} + + +static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv); +} + + +static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv); +} + +#endif /* CONFIG_WPS_NFC */ + + +static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 2) + res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", + argv[0], argv[1]); + else if (argc == 5 || argc == 6) { + char ssid_hex[2 * SSID_MAX_LEN + 1]; + char key_hex[2 * 64 + 1]; + int i; + + ssid_hex[0] = '\0'; + for (i = 0; i < SSID_MAX_LEN; i++) { + if (argv[2][i] == '\0') + break; + os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); + } + + key_hex[0] = '\0'; + if (argc == 6) { + for (i = 0; i < 64; i++) { + if (argv[5][i] == '\0') + break; + os_snprintf(&key_hex[i * 2], 3, "%02x", + argv[5][i]); + } + } + + res = os_snprintf(cmd, sizeof(cmd), + "WPS_REG %s %s %s %s %s %s", + argv[0], argv[1], ssid_hex, argv[3], argv[4], + key_hex); + } else { + wpa_printf(MSG_INFO, "Invalid WPS_REG command: need two arguments:\n" + "- BSSID of the target AP\n" + "- AP PIN\n"); + wpa_printf(MSG_INFO, "Alternatively, six arguments can be used to " + "reconfigure the AP:\n" + "- BSSID of the target AP\n" + "- AP PIN\n" + "- new SSID\n" + "- new auth (OPEN, WPAPSK, WPA2PSK)\n" + "- new encr (NONE, WEP, TKIP, CCMP)\n" + "- new key\n"); + return -1; + } + + if (os_snprintf_error(sizeof(cmd), res)) { + wpa_printf(MSG_INFO, "Too long WPS_REG command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "WPS_ER_STOP"); + +} + + +static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid WPS_ER_PIN command: need at least two " + "arguments:\n" + "- UUID: use 'any' to select any\n" + "- PIN: Enrollee PIN\n" + "optional: - Enrollee MAC address\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 2) { + wpa_printf(MSG_INFO, "Invalid WPS_ER_LEARN command: need two arguments:\n" + "- UUID: specify which AP to use\n" + "- PIN: AP PIN\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 2) { + wpa_printf(MSG_INFO, "Invalid WPS_ER_SET_CONFIG command: need two " + "arguments:\n" + "- UUID: specify which AP to use\n" + "- Network configuration id\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv); +} + + +static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc == 5 || argc == 6) { + char ssid_hex[2 * SSID_MAX_LEN + 1]; + char key_hex[2 * 64 + 1]; + int i; + + ssid_hex[0] = '\0'; + for (i = 0; i < SSID_MAX_LEN; i++) { + if (argv[2][i] == '\0') + break; + os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]); + } + + key_hex[0] = '\0'; + if (argc == 6) { + for (i = 0; i < 64; i++) { + if (argv[5][i] == '\0') + break; + os_snprintf(&key_hex[i * 2], 3, "%02x", + argv[5][i]); + } + } + + res = os_snprintf(cmd, sizeof(cmd), + "WPS_ER_CONFIG %s %s %s %s %s %s", + argv[0], argv[1], ssid_hex, argv[3], argv[4], + key_hex); + } else { + wpa_printf(MSG_INFO, "Invalid WPS_ER_CONFIG command: need six arguments:\n" + "- AP UUID\n" + "- AP PIN\n" + "- new SSID\n" + "- new auth (OPEN, WPAPSK, WPA2PSK)\n" + "- new encr (NONE, WEP, TKIP, CCMP)\n" + "- new key\n"); + return -1; + } + + if (os_snprintf_error(sizeof(cmd), res)) { + wpa_printf(MSG_INFO, "Too long WPS_ER_CONFIG command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +#ifdef CONFIG_WPS_NFC +static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 2) { + wpa_printf(MSG_INFO, "Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two " + "arguments:\n" + "- WPS/NDEF: token format\n" + "- UUID: specify which AP to use\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv); +} +#endif /* CONFIG_WPS_NFC */ + + +static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv); +} + +static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid IDENTITY command: needs two arguments " + "(network id and identity)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long IDENTITY command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long IDENTITY command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid PASSWORD command: needs two arguments " + "(network id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PASSWORD command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PASSWORD command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid NEW_PASSWORD command: needs two arguments " + "(network id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long NEW_PASSWORD command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long NEW_PASSWORD command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid PIN command: needs two arguments " + "(network id and pin)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PIN command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PIN command.\n"); + return -1; + } + pos += ret; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid OTP command: needs two arguments (network " + "id and password)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long OTP command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long OTP command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_sim(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid SIM command: needs two arguments " + "(network id and SIM operation response)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long SIM command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long SIM command.\n"); + return -1; + } + pos += ret; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PSK_PASSPHRASE command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PSK_PASSPHRASE command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256], *pos, *end; + int i, ret; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid PASSPHRASE command: needs two arguments " + "(network id and passphrase)\n"); + return -1; + } + + end = cmd + sizeof(cmd); + pos = cmd; + ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s", + argv[0], argv[1]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PASSPHRASE command.\n"); + return -1; + } + pos += ret; + for (i = 2; i < argc; i++) { + ret = os_snprintf(pos, end - pos, " %s", argv[i]); + if (os_snprintf_error(end - pos, ret)) { + wpa_printf(MSG_INFO, "Too long PASSPHRASE command.\n"); + return -1; + } + pos += ret; + } + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid BSSID command: needs two arguments (network " + "id and BSSID)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv); +} + + +static int wpa_cli_cmd_bssid_ignore(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSSID_IGNORE", 0, argc, argv); +} + + +static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv); +} + + +static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc == 0) { + wpa_cli_show_network_variables(); + return 0; + } + + if (argc < 3) { + wpa_printf(MSG_INFO, "Invalid DUP_NETWORK command: needs three arguments\n" + "(src netid, dest netid, and variable name)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "DUP_NETWORK", 3, argc, argv); +} + + +static char ** wpa_cli_complete_dup_network(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(network_fields); + char **res = NULL; + + switch (arg) { + case 1: + case 2: + res = cli_txt_list_array(&networks); + break; + case 3: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(network_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; +} + + +static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LIST_CREDS"); +} + + +static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ADD_CRED"); +} + + +static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv); +} + + +static const char * const cred_fields[] = { + "temporary", "priority", "sp_priority", "pcsc", "eap", + "update_identifier", "min_dl_bandwidth_home", "min_ul_bandwidth_home", + "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load", + "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password", + "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi", + "ca_cert_id", "cert_id", "key_id", "engine_id", "engine", + "milenage", "domain_suffix_match", "domain", "phase1", "phase2", + "roaming_consortium", "required_roaming_consortium", "excluded_ssid", + "roaming_partner", "provisioning_sp" +}; + + +static char ** wpa_cli_complete_cred(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(cred_fields); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&creds); + break; + case 2: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(cred_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; +} + + +static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc != 3) { + wpa_printf(MSG_INFO, "Invalid SET_CRED command: needs three arguments\n" + "(cred id, variable name, and value)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv); +} + + +static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc != 2) { + wpa_printf(MSG_INFO, "Invalid GET_CRED command: needs two arguments\n" + "(cred id, variable name)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv); +} + + +static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RECONNECT"); +} + + +static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SAVE_CONFIG"); +} + + +static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv); +} + + +static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); +} + + +static int wpa_cli_cmd_abort_scan(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ABORT_SCAN"); +} + + +static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv); +} + + +static char ** wpa_cli_complete_bss(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&bsses); + break; + } + + return res; +} + + +static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc < 1 || argc > 3) { + wpa_printf(MSG_INFO, "Invalid GET_CAPABILITY command: need at least one argument and max three arguments\n"); + return -1; + } + + if (argc > 1 && os_strcmp(argv[0], "key_mgmt") != 0 && + os_strncmp(argv[1], "iftype=", 7) == 0) { + wpa_printf(MSG_INFO, "Invalid GET_CAPABILITY command: 'iftype=' param is allowed only for 'key_mgmt'\n"); + return -1; + } + + if (argc == 2 && os_strcmp(argv[1], "strict") != 0 && + os_strncmp(argv[1], "iftype=", 7) != 0) { + wpa_printf(MSG_INFO, "Invalid GET_CAPABILITY command: the second argument, if any, must be 'strict' OR 'iftype='\n"); + return -1; + } + + if (argc == 3 && os_strcmp(argv[2], "strict") != 0) { + wpa_printf(MSG_INFO, "Invalid GET_CAPABILITY command: the third argument, if any, must be 'strict'\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv); +} + + +static char ** wpa_cli_complete_get_capability(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + const char *fields[] = { + "eap", "pairwise", "group", "group_mgmt", "key_mgmt", + "proto", "auth_alg", "modes", "channels", "freq", +#ifdef CONFIG_TDLS + "tdls", +#endif /* CONFIG_TDLS */ +#ifdef CONFIG_ERP + "erp", +#endif /* CONFIG_ERP */ +#ifdef CONFIG_FIPS + "fips", +#endif /* CONFIG_FIPS */ +#ifdef CONFIG_ACS + "acs", +#endif /* CONFIG_ACS */ + }; + const char *iftypes[] = { + "iftype=STATION", "iftype=AP", "iftype=P2P_CLIENT", + "iftype=P2P_GO", "iftype=AP_VLAN", "iftype=IBSS", "iftype=NAN", + "iftype=P2P_DEVICE", "iftype=MESH", + }; + int i, num_fields = ARRAY_SIZE(fields); + int num_iftypes = ARRAY_SIZE(iftypes); + char **res = NULL; + + if (arg == 1) { + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(fields[i]); + if (res[i] == NULL) + return res; + } + } + if (arg == 2) { + /* the second argument can be "iftype=" OR + * "strict" */ + res = os_calloc(num_iftypes + 2, sizeof(char *)); + if (!res) + return NULL; + res[0] = os_strdup("strict"); + if (!res[0]) + return res; + for (i = 0; i < num_iftypes; i++) { + res[i + 1] = os_strdup(iftypes[i]); + if (!res[i + 1]) + return res; + } + } + if (arg == 3) { + res = os_calloc(1 + 1, sizeof(char *)); + if (res == NULL) + return NULL; + res[0] = os_strdup("strict"); + } + return res; +} + +static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RECONFIGURE"); +} + + +static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "TERMINATE"); +} + + +#ifdef CONFIG_AP +static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "STA", 1, argc, argv); +} + + +static char ** wpa_cli_complete_sta(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + +static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd, + char *addr, size_t addr_len, int print) +{ + char buf[CMD_BUF_LEN], *pos; + size_t len; + int ret; + + if (ctrl_conn == NULL) { + wpa_printf(MSG_INFO, "Not connected to hostapd - command dropped.\n"); + return -1; + } + if (ifname_prefix) { + os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", + ifname_prefix, cmd); + buf[sizeof(buf) - 1] = '\0'; + cmd = buf; + } + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, + wpa_cli_msg_cb); + if (ret == -2) { + wpa_printf(MSG_INFO, "'%s' command timed out.\n", cmd); + return -2; + } else if (ret < 0) { + wpa_printf(MSG_INFO, "'%s' command failed.\n", cmd); + return -1; + } + + buf[len] = '\0'; + if (os_memcmp(buf, "FAIL", 4) == 0 || + os_memcmp(buf, "UNKNOWN COMMAND", 15) == 0) + return -1; + if (print) + wpa_printf(MSG_INFO, "%s", buf); + + pos = buf; + while (*pos != '\0' && *pos != '\n') + pos++; + *pos = '\0'; + os_strlcpy(addr, buf, addr_len); + return 0; +} + + +static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char addr[32], cmd[64]; + + if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1)) + return 0; + do { + os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); + } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0); + + return -1; +} + + +static int wpa_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char addr[32], cmd[64]; + + if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0)) + return 0; + do { + if (os_strcmp(addr, "") != 0) + wpa_printf(MSG_INFO, "%s\n", addr); + os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); + } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0); + + return 0; +} + + +static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv); +} + + +static char ** wpa_cli_complete_deauthenticate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + +static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv); +} + + +static char ** wpa_cli_complete_disassociate(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&stations); + break; + } + + return res; +} + + +static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv); +} + + +static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); +} + +#endif /* CONFIG_AP */ + + +static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SUSPEND"); +} + + +static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RESUME"); +} + + +#ifdef CONFIG_TESTING_OPTIONS +static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DROP_SA"); +} +#endif /* CONFIG_TESTING_OPTIONS */ + + +static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv); +} + + +#ifdef CONFIG_MESH + +static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv); +} + + +static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv); +} + + +static int wpa_cli_cmd_mesh_link_probe(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MESH_LINK_PROBE", 1, argc, argv); +} + +#endif /* CONFIG_MESH */ + + +#ifdef CONFIG_P2P + +static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv); +} + + +static char ** wpa_cli_complete_p2p_find(const char *str, int pos) +{ + char **res = NULL; + int arg = get_cmd_arg_num(str, pos); + + res = os_calloc(6, sizeof(char *)); + if (res == NULL) + return NULL; + res[0] = os_strdup("type=social"); + if (res[0] == NULL) { + os_free(res); + return NULL; + } + res[1] = os_strdup("type=progressive"); + if (res[1] == NULL) + return res; + res[2] = os_strdup("delay="); + if (res[2] == NULL) + return res; + res[3] = os_strdup("dev_id="); + if (res[3] == NULL) + return res; + if (arg == 1) + res[4] = os_strdup("[timeout]"); + + return res; +} + + +static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_STOP_FIND"); +} + + +static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv); +} + + +static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv); +} + + +static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv); +} + + +static char ** wpa_cli_complete_p2p_connect(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&p2p_peers); + break; + } + + return res; +} + + +static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv); +} + + +static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv); +} + + +static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&p2p_groups); + break; + } + + return res; +} + + +static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv); +} + + +static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 2 && argc != 3) { + wpa_printf(MSG_INFO, "Invalid P2P_PROV_DISC command: needs at least " + "two arguments, address and config method\n" + "(display, keypad, or pbc) and an optional join\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv); +} + + +static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE"); +} + + +static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[CMD_BUF_LEN]; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Invalid P2P_SERV_DISC_REQ command: needs two " + "or more arguments (address and TLVs)\n"); + return -1; + } + + if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0) + return -1; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[CMD_BUF_LEN]; + int res; + + if (argc != 4) { + wpa_printf(MSG_INFO, "Invalid P2P_SERV_DISC_RESP command: needs four " + "arguments (freq, address, dialog token, and TLVs)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s", + argv[0], argv[1], argv[2], argv[3]); + if (os_snprintf_error(sizeof(cmd), res)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE"); +} + + +static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH"); +} + + +static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc < 3) { + wpa_printf(MSG_INFO, "Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv); +} + + +static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc < 5 || argc > 6) { + wpa_printf(MSG_INFO, "Invalid P2P_SERVICE_REP command: needs 5-6 " + "arguments\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv); +} + + +static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[CMD_BUF_LEN]; + int res; + + if (argc != 2 && argc != 3) { + wpa_printf(MSG_INFO, "Invalid P2P_SERVICE_DEL command: needs two or three " + "arguments\n"); + return -1; + } + + if (argc == 3) + res = os_snprintf(cmd, sizeof(cmd), + "P2P_SERVICE_DEL %s %s %s", + argv[0], argv[1], argv[2]); + else + res = os_snprintf(cmd, sizeof(cmd), + "P2P_SERVICE_DEL %s %s", + argv[0], argv[1]); + if (os_snprintf_error(sizeof(cmd), res)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv); +} + + +static char ** wpa_cli_complete_p2p_peer(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&p2p_peers); + break; + } + + return res; +} + + +static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, const char *cmd, + char *addr, size_t addr_len, + int discovered) +{ + char buf[CMD_BUF_LEN], *pos; + size_t len; + int ret; + + if (ctrl_conn == NULL) + return -1; + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, + wpa_cli_msg_cb); + if (ret == -2) { + wpa_printf(MSG_INFO, "'%s' command timed out.\n", cmd); + return -2; + } else if (ret < 0) { + wpa_printf(MSG_INFO, "'%s' command failed.\n", cmd); + return -1; + } + + buf[len] = '\0'; + if (os_memcmp(buf, "FAIL", 4) == 0) + return -1; + + pos = buf; + while (*pos != '\0' && *pos != '\n') + pos++; + *pos++ = '\0'; + os_strlcpy(addr, buf, addr_len); + if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL) + wpa_printf(MSG_INFO, "%s\n", addr); + return 0; +} + + +static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char addr[32], cmd[64]; + int discovered; + + discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0; + + if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST", + addr, sizeof(addr), discovered)) + return -1; + do { + os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); + } while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr), + discovered) == 0); + + return 0; +} + + +static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv); +} + + +static char ** wpa_cli_complete_p2p_set(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + const char *fields[] = { + "discoverability", + "managed", + "listen_channel", + "ssid_postfix", + "noa", + "ps", + "oppps", + "ctwindow", + "disabled", + "conc_pref", + "force_long_sd", + "peer_filter", + "cross_connect", + "go_apsd", + "client_apsd", + "disallow_freq", + "disc_int", + "per_sta_psk", + }; + int i, num_fields = ARRAY_SIZE(fields); + + if (arg == 1) { + char **res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(fields[i]); + if (res[i] == NULL) + return res; + } + return res; + } + + if (arg == 2 && os_strncasecmp(str, "p2p_set peer_filter ", 20) == 0) + return cli_txt_list_array(&p2p_peers); + + return NULL; +} + + +static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_FLUSH"); +} + + +static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "P2P_CANCEL"); +} + + +static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 0 && argc != 2 && argc != 4) { + wpa_printf(MSG_INFO, "Invalid P2P_PRESENCE_REQ command: needs two arguments " + "(preferred duration, interval; in microsecods).\n" + "Optional second pair can be used to provide " + "acceptable values.\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv); +} + + +static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + if (argc != 0 && argc != 2) { + wpa_printf(MSG_INFO, "Invalid P2P_EXT_LISTEN command: needs two arguments " + "(availability period, availability interval; in " + "millisecods).\n" + "Extended Listen Timing can be cancelled with this " + "command when used without parameters.\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv); +} + + +static int wpa_cli_cmd_p2p_remove_client(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_REMOVE_CLIENT", 1, argc, argv); +} + +#endif /* CONFIG_P2P */ + + +static int wpa_cli_cmd_vendor_elem_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_ADD", 2, argc, argv); +} + + +static int wpa_cli_cmd_vendor_elem_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_GET", 1, argc, argv); +} + + +static int wpa_cli_cmd_vendor_elem_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR_ELEM_REMOVE", 2, argc, argv); +} + + +#ifdef CONFIG_WIFI_DISPLAY + +static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[100]; + int res; + + if (argc != 1 && argc != 2) { + wpa_printf(MSG_INFO, "Invalid WFD_SUBELEM_SET command: needs one or two " + "arguments (subelem, hexdump)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s", + argv[0], argc > 1 ? argv[1] : ""); + if (os_snprintf_error(sizeof(cmd), res)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[100]; + int res; + + if (argc != 1) { + wpa_printf(MSG_INFO, "Invalid WFD_SUBELEM_GET command: needs one " + "argument (subelem)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s", + argv[0]); + if (os_snprintf_error(sizeof(cmd), res)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + return wpa_ctrl_command(ctrl, cmd); +} +#endif /* CONFIG_WIFI_DISPLAY */ + + +#ifdef CONFIG_INTERWORKING +static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "FETCH_ANQP"); +} + + +static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP"); +} + + +static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv); +} + + +static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv); +} + + +static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); +} + + +static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv); +} + + +static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv); +} +#endif /* CONFIG_INTERWORKING */ + + +#ifdef CONFIG_HS20 + +static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv); +} + + +static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[512]; + + if (argc == 0) { + wpa_printf(MSG_INFO, "Command needs one or two arguments (dst mac addr and " + "optional home realm)\n"); + return -1; + } + + if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST", + argc, argv) < 0) + return -1; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[512]; + + if (argc < 2) { + wpa_printf(MSG_INFO, "Command needs two arguments (dst mac addr and " + "icon name)\n"); + return -1; + } + + if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0) + return -1; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "FETCH_OSU"); +} + + +static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU"); +} + +#endif /* CONFIG_HS20 */ + + +static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv); +} + + +static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv); +} + + +static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv); +} + + +static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv); +} + + +static int wpa_cli_cmd_tdls_link_status(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_LINK_STATUS", 1, argc, argv); +} + + +static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv); +} + + +static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv); +} + + +static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "WMM_AC_STATUS"); +} + + +static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv); +} + + +static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv); +} + + +static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "SIGNAL_POLL"); +} + + +static int wpa_cli_cmd_signal_monitor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SIGNAL_MONITOR", 0, argc, argv); +} + + +static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "PKTCNT_POLL"); +} + + +static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "REAUTHENTICATE"); +} + + +#ifdef CONFIG_AUTOSCAN + +static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc == 0) + return wpa_ctrl_command(ctrl, "AUTOSCAN "); + + return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv); +} + +#endif /* CONFIG_AUTOSCAN */ + + +#ifdef CONFIG_WNM + +static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv); +} + + +static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv); +} + +#endif /* CONFIG_WNM */ + + +static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc == 0) + return -1; + return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]); +} + +static int wpa_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "VENDOR", 1, argc, argv); +} + + +static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "FLUSH"); +} + + +static int wpa_cli_cmd_radio_work(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "RADIO_WORK", 1, argc, argv); +} + + +static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv); +} + + +static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv); +} + + +static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "TWT_TEARDOWN", 0, argc, argv); +} + + +static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ERP_FLUSH"); +} + + +static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv); +} + + +static int wpa_cli_cmd_get_pref_freq_list(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "GET_PREF_FREQ_LIST", 1, argc, argv); +} + + +static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv); +} + + +static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv); +} + + +#ifdef CONFIG_DPP + +static int wpa_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN"); +} + + +static int wpa_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); +} + + +#ifdef CONFIG_DPP2 + +static int wpa_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP"); +} + + +static int wpa_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv); +} + + +static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP"); +} + +#endif /* CONFIG_DPP2 */ +#endif /* CONFIG_DPP */ + + +static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd) +{ + char buf[512], *pos, *bssid = NULL, *freq = NULL, *level = NULL, + *flags = NULL, *ssid = NULL; + size_t len; + int ret, id = -1; + + if (!ctrl_conn) + return -1; + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, + wpa_cli_msg_cb); + if (ret == -2) { + wpa_printf(MSG_INFO, "'%s' command timed out.\n", cmd); + return -2; + } else if (ret < 0) { + wpa_printf(MSG_INFO, "'%s' command failed.\n", cmd); + return -1; + } + + buf[len] = '\0'; + if (os_memcmp(buf, "FAIL", 4) == 0) + return -1; + + pos = buf; + while (*pos != '\0') { + if (str_starts(pos, "id=")) + id = atoi(pos + 3); + if (str_starts(pos, "bssid=")) + bssid = pos + 6; + if (str_starts(pos, "freq=")) + freq = pos + 5; + if (str_starts(pos, "level=")) + level = pos + 6; + if (str_starts(pos, "flags=")) + flags = pos + 6; + if (str_starts(pos, "ssid=")) + ssid = pos + 5; + + while (*pos != '\0' && *pos != '\n') + pos++; + *pos++ = '\0'; + } + if (id != -1) + wpa_printf(MSG_INFO, "%s\t%s\t%s\t%s\t%s\n", bssid ? bssid : "N/A", + freq ? freq : "N/A", level ? level : "N/A", + flags ? flags : "N/A", ssid ? ssid : "N/A"); + return id; +} + + +static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[64]; + int id = -1; + unsigned int mask; + + wpa_printf(MSG_INFO, "bssid / frequency / signal level / flags / ssid\n"); + + mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ | + WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID; + do { + if (id < 0) + os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x", + mask); + else + os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x", + id, mask); + id = wpa_ctrl_command_bss(ctrl, cmd); + } while (id >= 0); + + return 0; +} + + +#ifdef CONFIG_PASN + +static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv); +} + + +static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv); +} + +static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PTKSA_CACHE_LIST", 0, argc, argv); +} + + +static int wpa_cli_cmd_pasn_deauth(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "PASN_DEAUTH", 1, argc, argv); +} + +#endif /* CONFIG_PASN */ + + +static int wpa_cli_cmd_mscs(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "MSCS", 1, argc, argv); +} + + +static int wpa_cli_cmd_scs(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "SCS", 2, argc, argv); +} + + +static int wpa_cli_cmd_dscp_resp(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DSCP_RESP", 1, argc, argv); +} + + +static int wpa_cli_cmd_dscp_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DSCP_QUERY", 1, argc, argv); +} + +#endif /* !CONFIG_ZEPHYR || (CONFIG_ZEPHYR && CONFIG_WPA_CLI)*/ + + +enum wpa_cli_cmd_flags { + cli_cmd_flag_none = 0x00, + cli_cmd_flag_sensitive = 0x01 +}; + +struct wpa_cli_cmd { + const char *cmd; + int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); + char ** (*completion)(const char *str, int pos); + enum wpa_cli_cmd_flags flags; + const char *usage; +}; + +static const struct wpa_cli_cmd wpa_cli_commands[] = { + { "status", wpa_cli_cmd_status, NULL, + cli_cmd_flag_none, + "[verbose] = get current WPA/EAPOL/EAP status" }, + { "set_network", wpa_cli_cmd_set_network, wpa_cli_complete_network, + cli_cmd_flag_sensitive, + " = set network variables (shows\n" + " list of variables when run without arguments)" }, + { "get_network", wpa_cli_cmd_get_network, wpa_cli_complete_network, + cli_cmd_flag_none, + " = get network variables" }, + { "list_networks", wpa_cli_cmd_list_networks, NULL, + cli_cmd_flag_none, + "= list configured networks" }, + { "select_network", wpa_cli_cmd_select_network, + wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = select a network (disable others)" }, + { "enable_network", wpa_cli_cmd_enable_network, + wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = enable a network" }, + { "disable_network", wpa_cli_cmd_disable_network, + wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = disable a network" }, + { "add_network", wpa_cli_cmd_add_network, NULL, + cli_cmd_flag_none, + "= add a network" }, + { "remove_network", wpa_cli_cmd_remove_network, + wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = remove a network" }, + { "disconnect", wpa_cli_cmd_disconnect, NULL, + cli_cmd_flag_none, + "= disconnect and wait for reassociate/reconnect command before\n" + " connecting" }, + { "interface_add", wpa_cli_cmd_interface_add, NULL, + cli_cmd_flag_none, + " \n" + " = adds new interface, all " + "parameters but\n" + " are optional. Supported types are station ('sta') and " + "AP ('ap')" }, + { "interface_remove", wpa_cli_cmd_interface_remove, NULL, + cli_cmd_flag_none, + " = removes the interface" }, + { "interface_list", wpa_cli_cmd_interface_list, NULL, + cli_cmd_flag_none, + "= list available interfaces" }, +#if !defined(CONFIG_ZEPHYR) || (defined(CONFIG_ZEPHYR) && defined(CONFIG_WPA_CLI)) + { "ifname", wpa_cli_cmd_ifname, NULL, + cli_cmd_flag_none, + "= get current interface name" }, + { "ping", wpa_cli_cmd_ping, NULL, + cli_cmd_flag_none, + "= pings wpa_supplicant" }, + { "relog", wpa_cli_cmd_relog, NULL, + cli_cmd_flag_none, + "= re-open log-file (allow rolling logs)" }, + { "note", wpa_cli_cmd_note, NULL, + cli_cmd_flag_none, + " = add a note to wpa_supplicant debug log" }, + { "mib", wpa_cli_cmd_mib, NULL, + cli_cmd_flag_none, + "= get MIB variables (dot1x, dot11)" }, + { "set", wpa_cli_cmd_set, wpa_cli_complete_set, + cli_cmd_flag_none, + "= set variables (shows list of variables when run without " + "arguments)" }, + { "dump", wpa_cli_cmd_dump, NULL, + cli_cmd_flag_none, + "= dump config variables" }, + { "get", wpa_cli_cmd_get, wpa_cli_complete_get, + cli_cmd_flag_none, + " = get information" }, + { "driver_flags", wpa_cli_cmd_driver_flags, NULL, + cli_cmd_flag_none, + "= list driver flags" }, + { "logon", wpa_cli_cmd_logon, NULL, + cli_cmd_flag_none, + "= IEEE 802.1X EAPOL state machine logon" }, + { "logoff", wpa_cli_cmd_logoff, NULL, + cli_cmd_flag_none, + "= IEEE 802.1X EAPOL state machine logoff" }, + { "pmksa", wpa_cli_cmd_pmksa, NULL, + cli_cmd_flag_none, + "= show PMKSA cache" }, + { "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL, + cli_cmd_flag_none, + "= flush PMKSA cache entries" }, +#ifdef CONFIG_PMKSA_CACHE_EXTERNAL + { "pmksa_get", wpa_cli_cmd_pmksa_get, NULL, + cli_cmd_flag_none, + " = fetch all stored PMKSA cache entries" }, + { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL, + cli_cmd_flag_sensitive, + " = store PMKSA cache entry from external storage" }, +#ifdef CONFIG_MESH + { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL, + cli_cmd_flag_none, + " = fetch all stored mesh PMKSA cache entries" }, + { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL, + cli_cmd_flag_sensitive, + " = store mesh PMKSA cache entry from external storage" }, +#endif /* CONFIG_MESH */ +#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + { "reassociate", wpa_cli_cmd_reassociate, NULL, + cli_cmd_flag_none, + "= force reassociation" }, + { "reattach", wpa_cli_cmd_reattach, NULL, + cli_cmd_flag_none, + "= force reassociation back to the same BSS" }, + { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss, + cli_cmd_flag_none, + " = force preauthentication" }, + { "identity", wpa_cli_cmd_identity, wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = configure identity for an SSID" }, + { "password", wpa_cli_cmd_password, wpa_cli_complete_network_id, + cli_cmd_flag_sensitive, + " = configure password for an SSID" }, + { "new_password", wpa_cli_cmd_new_password, + wpa_cli_complete_network_id, cli_cmd_flag_sensitive, + " = change password for an SSID" }, + { "pin", wpa_cli_cmd_pin, wpa_cli_complete_network_id, + cli_cmd_flag_sensitive, + " = configure pin for an SSID" }, + { "otp", wpa_cli_cmd_otp, wpa_cli_complete_network_id, + cli_cmd_flag_sensitive, + " = configure one-time-password for an SSID" + }, + { "psk_passphrase", wpa_cli_cmd_psk_passphrase, + wpa_cli_complete_network_id, cli_cmd_flag_sensitive, + " = configure PSK/passphrase for an SSID" }, + { "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id, + cli_cmd_flag_sensitive, + " = configure private key passphrase\n" + " for an SSID" }, + { "sim", wpa_cli_cmd_sim, wpa_cli_complete_network_id, + cli_cmd_flag_sensitive, + " = report SIM operation result" }, + { "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id, + cli_cmd_flag_none, + " = set preferred BSSID for an SSID" }, + { "bssid_ignore", wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss, + cli_cmd_flag_none, + " = add a BSSID to the list of temporarily ignored BSSs\n" + "bssid_ignore clear = clear the list of temporarily ignored BSSIDs\n" + "bssid_ignore = display the list of temporarily ignored BSSIDs" }, + { "blacklist", /* deprecated alias for bssid_ignore */ + wpa_cli_cmd_bssid_ignore, wpa_cli_complete_bss, + cli_cmd_flag_none, + "= deprecated alias for bssid_ignore" }, + { "log_level", wpa_cli_cmd_log_level, NULL, + cli_cmd_flag_none, + " [] = update the log level/timestamp\n" + "log_level = display the current log level and log options" }, + { "dup_network", wpa_cli_cmd_dup_network, wpa_cli_complete_dup_network, + cli_cmd_flag_none, + " = duplicate network variables" + }, + { "list_creds", wpa_cli_cmd_list_creds, NULL, + cli_cmd_flag_none, + "= list configured credentials" }, + { "add_cred", wpa_cli_cmd_add_cred, NULL, + cli_cmd_flag_none, + "= add a credential" }, + { "remove_cred", wpa_cli_cmd_remove_cred, NULL, + cli_cmd_flag_none, + " = remove a credential" }, + { "set_cred", wpa_cli_cmd_set_cred, wpa_cli_complete_cred, + cli_cmd_flag_sensitive, + " = set credential variables" }, + { "get_cred", wpa_cli_cmd_get_cred, wpa_cli_complete_cred, + cli_cmd_flag_none, + " = get credential variables" }, + { "save_config", wpa_cli_cmd_save_config, NULL, + cli_cmd_flag_none, + "= save the current configuration" }, + { "reconnect", wpa_cli_cmd_reconnect, NULL, + cli_cmd_flag_none, + "= like reassociate, but only takes effect if already disconnected" + }, + { "scan", wpa_cli_cmd_scan, NULL, + cli_cmd_flag_none, + "= request new BSS scan" }, + { "scan_results", wpa_cli_cmd_scan_results, NULL, + cli_cmd_flag_none, + "= get latest scan results" }, + { "abort_scan", wpa_cli_cmd_abort_scan, NULL, + cli_cmd_flag_none, + "= request ongoing scan to be aborted" }, + { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss, + cli_cmd_flag_none, + "< | > = get detailed scan result info" }, + { "get_capability", wpa_cli_cmd_get_capability, + wpa_cli_complete_get_capability, cli_cmd_flag_none, + " " + "= get capabilities" }, + { "reconfigure", wpa_cli_cmd_reconfigure, NULL, + cli_cmd_flag_none, + "= force wpa_supplicant to re-read its configuration file" }, + { "terminate", wpa_cli_cmd_terminate, NULL, + cli_cmd_flag_none, + "= terminate wpa_supplicant" }, + { "ap_scan", wpa_cli_cmd_ap_scan, NULL, + cli_cmd_flag_none, + " = set ap_scan parameter" }, + { "scan_interval", wpa_cli_cmd_scan_interval, NULL, + cli_cmd_flag_none, + " = set scan_interval parameter (in seconds)" }, + { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL, + cli_cmd_flag_none, + " = set BSS expiration age parameter" }, + { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL, + cli_cmd_flag_none, + " = set BSS expiration scan count parameter" }, + { "bss_flush", wpa_cli_cmd_bss_flush, NULL, + cli_cmd_flag_none, + " = set BSS flush age (0 by default)" }, + { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss, + cli_cmd_flag_none, + " = request over-the-DS FT with " }, + { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss, + cli_cmd_flag_none, + "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" }, + { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss, + cli_cmd_flag_sensitive, + " [PIN] = start WPS PIN method (returns PIN, if not " + "hardcoded)" }, + { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL, + cli_cmd_flag_sensitive, + " = verify PIN checksum" }, + { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none, + "Cancels the pending WPS operation" }, +#ifdef CONFIG_WPS_NFC + { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss, + cli_cmd_flag_none, + "[BSSID] = start Wi-Fi Protected Setup: NFC" }, + { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL, + cli_cmd_flag_none, + " = build configuration token" }, + { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL, + cli_cmd_flag_none, + " = create password token" }, + { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL, + cli_cmd_flag_sensitive, + " = report read NFC tag with WPS data" }, + { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL, + cli_cmd_flag_none, + " = create NFC handover request" }, + { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL, + cli_cmd_flag_none, + " = create NFC handover select" }, + { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL, + cli_cmd_flag_none, + " = report completed " + "NFC handover" }, +#endif /* CONFIG_WPS_NFC */ + { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss, + cli_cmd_flag_sensitive, + " = start WPS Registrar to configure an AP" }, + { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL, + cli_cmd_flag_sensitive, + "[params..] = enable/disable AP PIN" }, + { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL, + cli_cmd_flag_none, + "[IP address] = start Wi-Fi Protected Setup External Registrar" }, + { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL, + cli_cmd_flag_none, + "= stop Wi-Fi Protected Setup External Registrar" }, + { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL, + cli_cmd_flag_sensitive, + " = add an Enrollee PIN to External Registrar" }, + { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL, + cli_cmd_flag_none, + " = accept an Enrollee PBC using External Registrar" }, + { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL, + cli_cmd_flag_sensitive, + " = learn AP configuration" }, + { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL, + cli_cmd_flag_none, + " = set AP configuration for enrolling" }, + { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL, + cli_cmd_flag_sensitive, + " = configure AP" }, +#ifdef CONFIG_WPS_NFC + { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL, + cli_cmd_flag_none, + " = build NFC configuration token" }, +#endif /* CONFIG_WPS_NFC */ + { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL, + cli_cmd_flag_none, + " = request RSN authentication with in IBSS" }, +#ifdef CONFIG_AP + { "sta", wpa_cli_cmd_sta, wpa_cli_complete_sta, + cli_cmd_flag_none, + " = get information about an associated station (AP)" }, + { "all_sta", wpa_cli_cmd_all_sta, NULL, + cli_cmd_flag_none, + "= get information about all associated stations (AP)" }, + { "list_sta", wpa_cli_cmd_list_sta, NULL, + cli_cmd_flag_none, + "= list all stations (AP)" }, + { "deauthenticate", wpa_cli_cmd_deauthenticate, + wpa_cli_complete_deauthenticate, cli_cmd_flag_none, + " = deauthenticate a station" }, + { "disassociate", wpa_cli_cmd_disassociate, + wpa_cli_complete_disassociate, cli_cmd_flag_none, + " = disassociate a station" }, + { "chan_switch", wpa_cli_cmd_chanswitch, NULL, + cli_cmd_flag_none, + " [sec_channel_offset=] [center_freq1=]" + " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]" + " = CSA parameters" }, + { "update_beacon", wpa_cli_cmd_update_beacon, NULL, + cli_cmd_flag_none, + "= update Beacon frame contents"}, +#endif /* CONFIG_AP */ + { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, + "= notification of suspend/hibernate" }, + { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none, + "= notification of resume/thaw" }, +#ifdef CONFIG_TESTING_OPTIONS + { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, + "= drop SA without deauth/disassoc (test command)" }, +#endif /* CONFIG_TESTING_OPTIONS */ + { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, + cli_cmd_flag_none, + " = roam to the specified BSS" }, +#ifdef CONFIG_MESH + { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL, + cli_cmd_flag_none, + "[ifname] = Create a new mesh interface" }, + { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL, + cli_cmd_flag_none, + " = join a mesh network (disable others)" }, + { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL, + cli_cmd_flag_none, + " = Remove mesh group interface" }, + { "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL, + cli_cmd_flag_none, + " = Remove a mesh peer" }, + { "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL, + cli_cmd_flag_none, + " [duration=] = Add a mesh peer" }, + { "mesh_link_probe", wpa_cli_cmd_mesh_link_probe, NULL, + cli_cmd_flag_none, + " [payload=] = Probe a mesh link for a given peer by injecting a frame." }, +#endif /* CONFIG_MESH */ +#ifdef CONFIG_P2P + { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find, + cli_cmd_flag_none, + "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" }, + { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none, + "= stop P2P Devices search" }, + { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL, + cli_cmd_flag_none, + " adv_id= conncap= [info=] = provision with a P2P ASP Device" }, + { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL, + cli_cmd_flag_none, + " adv_id= [role] [info=] = provision with a P2P ASP Device" }, + { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect, + cli_cmd_flag_none, + " <\"pbc\"|PIN> [ht40] = connect to a P2P Device" }, + { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none, + "[timeout] = listen for P2P Devices for up-to timeout seconds" }, + { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, + wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none, + " = remove P2P group interface (terminate group if GO)" }, + { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none, + "[ht40] = add a new P2P group (local end as GO)" }, + { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL, + cli_cmd_flag_none, + " = Get peer interface address on local GO using peer Device Address" }, + { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, + " = request provisioning discovery" }, + { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL, + cli_cmd_flag_none, + "= get the passphrase for a group (GO only)" }, + { "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, + " = schedule service discovery request" }, + { "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req, + NULL, cli_cmd_flag_none, + " = cancel pending service discovery request" }, + { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL, + cli_cmd_flag_none, + " = service discovery response" }, + { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL, + cli_cmd_flag_none, + "= indicate change in local services" }, + { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL, + cli_cmd_flag_none, + " = set external processing of service discovery" }, + { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL, + cli_cmd_flag_none, + "= remove all stored service entries" }, + { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL, + cli_cmd_flag_none, + " = add a local " + "service" }, + { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL, + cli_cmd_flag_none, + "asp [] = replace " + "local ASP service" }, + { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL, + cli_cmd_flag_none, + " [|service] = remove a local " + "service" }, + { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer, + cli_cmd_flag_none, + " = reject connection attempts from a specific peer" }, + { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL, + cli_cmd_flag_none, + " [peer=addr] = invite peer" }, + { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none, + "[discovered] = list known (optionally, only fully discovered) P2P " + "peers" }, + { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer, + cli_cmd_flag_none, + "
= show information about known P2P peer" }, + { "p2p_set", wpa_cli_cmd_p2p_set, wpa_cli_complete_p2p_set, + cli_cmd_flag_none, + " = set a P2P parameter" }, + { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none, + "= flush P2P state" }, + { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none, + "= cancel P2P group formation" }, + { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, + "
= unauthorize a peer" }, + { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL, + cli_cmd_flag_none, + "[ ] [ ] = request GO " + "presence" }, + { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL, + cli_cmd_flag_none, + "[ ] = set extended listen timing" }, + { "p2p_remove_client", wpa_cli_cmd_p2p_remove_client, + wpa_cli_complete_p2p_peer, cli_cmd_flag_none, + " = remove a peer from all groups" }, +#endif /* CONFIG_P2P */ + { "vendor_elem_add", wpa_cli_cmd_vendor_elem_add, NULL, + cli_cmd_flag_none, + " = add vendor specific IEs to frame(s)\n" + VENDOR_ELEM_FRAME_ID }, + { "vendor_elem_get", wpa_cli_cmd_vendor_elem_get, NULL, + cli_cmd_flag_none, + " = get vendor specific IE(s) to frame(s)\n" + VENDOR_ELEM_FRAME_ID }, + { "vendor_elem_remove", wpa_cli_cmd_vendor_elem_remove, NULL, + cli_cmd_flag_none, + " = remove vendor specific IE(s) in frame(s)\n" + VENDOR_ELEM_FRAME_ID }, +#ifdef CONFIG_WIFI_DISPLAY + { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL, + cli_cmd_flag_none, + " [contents] = set Wi-Fi Display subelement" }, + { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL, + cli_cmd_flag_none, + " = get Wi-Fi Display subelement" }, +#endif /* CONFIG_WIFI_DISPLAY */ +#ifdef CONFIG_INTERWORKING + { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none, + "= fetch ANQP information for all APs" }, + { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL, + cli_cmd_flag_none, + "= stop fetch_anqp operation" }, + { "interworking_select", wpa_cli_cmd_interworking_select, NULL, + cli_cmd_flag_none, + "[auto] = perform Interworking network selection" }, + { "interworking_connect", wpa_cli_cmd_interworking_connect, + wpa_cli_complete_bss, cli_cmd_flag_none, + " = connect using Interworking credentials" }, + { "interworking_add_network", wpa_cli_cmd_interworking_add_network, + wpa_cli_complete_bss, cli_cmd_flag_none, + " = connect using Interworking credentials" }, + { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, + cli_cmd_flag_none, + " [,]... = request ANQP information" }, + { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss, + cli_cmd_flag_none, + " [QueryReq] = GAS request" }, + { "gas_response_get", wpa_cli_cmd_gas_response_get, + wpa_cli_complete_bss, cli_cmd_flag_none, + " [start,len] = Fetch last GAS response" }, +#endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_HS20 + { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss, + cli_cmd_flag_none, + " [,]... = request HS 2.0 ANQP information" + }, + { "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list, + wpa_cli_complete_bss, cli_cmd_flag_none, + " = get HS20 nai home realm list" }, + { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request, + wpa_cli_complete_bss, cli_cmd_flag_none, + " = get Hotspot 2.0 OSU icon" }, + { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none, + "= fetch OSU provider information from all APs" }, + { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL, + cli_cmd_flag_none, + "= cancel fetch_osu command" }, +#endif /* CONFIG_HS20 */ + { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL, + cli_cmd_flag_none, + "<0/1> = disable/enable automatic reconnection" }, + { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL, + cli_cmd_flag_none, + " = request TDLS discovery with " }, + { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL, + cli_cmd_flag_none, + " = request TDLS setup with " }, + { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL, + cli_cmd_flag_none, + " = tear down TDLS with " }, + { "tdls_link_status", wpa_cli_cmd_tdls_link_status, NULL, + cli_cmd_flag_none, + " = TDLS link status with " }, + { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL, + cli_cmd_flag_none, + " [nominal_msdu_size=#] " + "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] " + "= add WMM-AC traffic stream" }, + { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL, + cli_cmd_flag_none, + " = delete WMM-AC traffic stream" }, + { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL, + cli_cmd_flag_none, + "= show status for Wireless Multi-Media Admission-Control" }, + { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL, + cli_cmd_flag_none, + " [sec_channel_offset=] [center_freq1=] " + "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching " + "with TDLS peer" }, + { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL, + cli_cmd_flag_none, + " = disable channel switching with TDLS peer " }, + { "signal_poll", wpa_cli_cmd_signal_poll, NULL, + cli_cmd_flag_none, + "= get signal parameters" }, + { "signal_monitor", wpa_cli_cmd_signal_monitor, NULL, + cli_cmd_flag_none, + "= set signal monitor parameters" }, + { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL, + cli_cmd_flag_none, + "= get TX/RX packet counters" }, + { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL, + cli_cmd_flag_none, + "= trigger IEEE 802.1X/EAPOL reauthentication" }, +#ifdef CONFIG_AUTOSCAN + { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none, + "[params] = Set or unset (if none) autoscan parameters" }, +#endif /* CONFIG_AUTOSCAN */ +#ifdef CONFIG_WNM + { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none, + " [interval=#] = enter/exit WNM-Sleep mode" }, + { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none, + " [list]" + " [neighbor=,,,,[,]" + " = Send BSS Transition Management Query" }, +#endif /* CONFIG_WNM */ + { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, + " = Sent unprocessed command" }, + { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, + "= flush wpa_supplicant state" }, + { "radio_work", wpa_cli_cmd_radio_work, NULL, cli_cmd_flag_none, + "= radio_work " }, + { "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none, + " [] = Send vendor command" + }, + { "neighbor_rep_request", + wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none, + "[ssid=] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)" + }, + { "twt_setup", + wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none, + "[dialog=] [exponent=] [mantissa=] [min_twt=] [setup_cmd=] [twt=] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=] [control=] = Send TWT Setup frame" + }, + { "twt_teardown", + wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none, + "[flags=] = Send TWT Teardown frame" + }, + { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none, + "= flush ERP keys" }, + { "mac_rand_scan", + wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none, + " enable=<0/1> [addr=mac-address " + "mask=mac-address-mask] = scan MAC randomization" + }, + { "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL, + cli_cmd_flag_none, + " = retrieve preferred freq list for the specified interface type" }, + { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL, + cli_cmd_flag_none, + " = start P2P listen offload" }, + { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL, + cli_cmd_flag_none, + "= stop P2P listen offload" }, +#ifdef CONFIG_DPP + { "dpp_qr_code", wpa_cli_cmd_dpp_qr_code, NULL, cli_cmd_flag_none, + "report a scanned DPP URI from a QR Code" }, + { "dpp_bootstrap_gen", wpa_cli_cmd_dpp_bootstrap_gen, NULL, + cli_cmd_flag_sensitive, + "type= [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" }, + { "dpp_bootstrap_remove", wpa_cli_cmd_dpp_bootstrap_remove, NULL, + cli_cmd_flag_none, + "*| = remove DPP bootstrap information" }, + { "dpp_bootstrap_get_uri", wpa_cli_cmd_dpp_bootstrap_get_uri, NULL, + cli_cmd_flag_none, + " = get DPP bootstrap URI" }, + { "dpp_bootstrap_info", wpa_cli_cmd_dpp_bootstrap_info, NULL, + cli_cmd_flag_none, + " = show DPP bootstrap information" }, + { "dpp_bootstrap_set", wpa_cli_cmd_dpp_bootstrap_set, NULL, + cli_cmd_flag_none, + " [conf=..] [ssid=] [ssid_charset=#] [psk=] [pass=] [configurator=] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" }, + { "dpp_auth_init", wpa_cli_cmd_dpp_auth_init, NULL, cli_cmd_flag_none, + "peer= [own=] = initiate DPP bootstrapping" }, + { "dpp_listen", wpa_cli_cmd_dpp_listen, NULL, cli_cmd_flag_none, + " = start DPP listen" }, + { "dpp_stop_listen", wpa_cli_cmd_dpp_stop_listen, NULL, + cli_cmd_flag_none, + "= stop DPP listen" }, + { "dpp_configurator_add", wpa_cli_cmd_dpp_configurator_add, NULL, + cli_cmd_flag_sensitive, + "[curve=..] [key=..] = add DPP configurator" }, + { "dpp_configurator_remove", wpa_cli_cmd_dpp_configurator_remove, NULL, + cli_cmd_flag_none, + "*| = remove DPP configurator" }, + { "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key, + NULL, cli_cmd_flag_none, + " = Get DPP configurator's private key" }, + { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL, + cli_cmd_flag_none, + "conf= configurator= = generate self DPP configuration" }, + { "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL, + cli_cmd_flag_sensitive, + "add PKEX code" }, + { "dpp_pkex_remove", wpa_cli_cmd_dpp_pkex_remove, NULL, + cli_cmd_flag_none, + "*| = remove DPP pkex information" }, +#ifdef CONFIG_DPP2 + { "dpp_controller_start", wpa_cli_cmd_dpp_controller_start, NULL, + cli_cmd_flag_none, + "[tcp_port=] [role=..] = start DPP controller" }, + { "dpp_controller_stop", wpa_cli_cmd_dpp_controller_stop, NULL, + cli_cmd_flag_none, + "= stop DPP controller" }, + { "dpp_chirp", wpa_cli_cmd_dpp_chirp, NULL, + cli_cmd_flag_none, + "own= iter= = start DPP chirp" }, + { "dpp_stop_chirp", wpa_cli_cmd_dpp_stop_chirp, NULL, + cli_cmd_flag_none, + "= stop DPP chirp" }, +#endif /* CONFIG_DPP2 */ +#endif /* CONFIG_DPP */ + { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none, + "= list all BSS entries (scan results)" }, +#ifdef CONFIG_PASN + { "pasn_auth_start", wpa_cli_cmd_pasn_auth_start, NULL, + cli_cmd_flag_none, + "bssid= akmp= cipher= group= nid= = Start PASN authentication" }, + { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL, + cli_cmd_flag_none, + "= Stop PASN authentication" }, + { "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL, + cli_cmd_flag_none, + "= Get the PTKSA Cache" }, + { "pasn_deauth", wpa_cli_cmd_pasn_deauth, NULL, + cli_cmd_flag_none, + "bssid= = Remove PASN PTKSA state" }, +#endif /* CONFIG_PASN */ + { "mscs", wpa_cli_cmd_mscs, NULL, + cli_cmd_flag_none, + " [up_bitmap=] [up_limit=] [stream_timeout=] [frame_classifier=] = Configure MSCS request" }, + { "scs", wpa_cli_cmd_scs, NULL, + cli_cmd_flag_none, + "[scs_id=] [scs_up=<0-7>] [classifier_type=<4|10>] [classifier params based on classifier type] [tclas_processing=<0|1>] [scs_id=] ... = Send SCS request" }, + { "dscp_resp", wpa_cli_cmd_dscp_resp, NULL, + cli_cmd_flag_none, + "<[reset]>/<[solicited] [policy_id=1 status=0...]> [more] = Send DSCP response" }, + { "dscp_query", wpa_cli_cmd_dscp_query, NULL, + cli_cmd_flag_none, + "wildcard/domain_name= = Send DSCP Query" }, +#endif /* !CONFIG_ZEPHYR || (CONFIG_ZEPHYR && CONFIG_WPA_CLI)*/ + { NULL, NULL, NULL, cli_cmd_flag_none, NULL } +}; + +int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + const struct wpa_cli_cmd *cmd, *match = NULL; + int count; + int ret = 0; + + if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) { + ifname_prefix = argv[0] + 7; + argv = &argv[1]; + argc--; + } else + ifname_prefix = NULL; + + if (argc == 0) + return -1; + + count = 0; + cmd = wpa_cli_commands; + while (cmd->cmd) { + if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) + { + match = cmd; + if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { + /* we have an exact match */ + count = 1; + break; + } + count++; + } + cmd++; + } + + if (count > 1) { + wpa_printf(MSG_INFO, "Ambiguous command '%s'; possible commands:", argv[0]); + cmd = wpa_cli_commands; + while (cmd->cmd) { + if (os_strncasecmp(cmd->cmd, argv[0], + os_strlen(argv[0])) == 0) { + wpa_printf(MSG_INFO, " %s", cmd->cmd); + } + cmd++; + } + wpa_printf(MSG_INFO, "\n"); + ret = 1; + } else if (count == 0) { + wpa_printf(MSG_INFO, "Unknown command '%s'\n", argv[0]); + ret = 1; + } else { + ret = match->handler(ctrl, argc, &argv[1]); + } + + return ret; +} \ No newline at end of file diff --git a/wpa_supplicant/wpa_cli_zephyr.c b/wpa_supplicant/wpa_cli_zephyr.c new file mode 100644 index 000000000..9b4217023 --- /dev/null +++ b/wpa_supplicant/wpa_cli_zephyr.c @@ -0,0 +1,416 @@ +/* + * WPA Supplicant - command line interface for wpa_supplicant daemon + * for Zephyr (based on wpa_cli.c) + * Copyright (c) 2004-2022, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "includes.h" + +#include "common/cli.h" +#include "common/wpa_ctrl.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/edit.h" +#include "utils/list.h" +#include "wpa_supplicant_i.h" +#include "ctrl_iface.h" +#include "common/version.h" +#include "common/ieee802_11_defs.h" + +#include "supp_main.h" +#include "wpa_cli_zephyr.h" +#include "ctrl_iface_zephyr.h" + +#define CMD_BUF_LEN 1024 +#define MAX_CMD_SIZE 512 +#define MAX_RESPONSE_SIZE 512 +#define DEFAULT_IFNAME "wlan0" +#define MAX_ARGS 32 + +struct wpa_ctrl *ctrl_conn; +struct wpa_ctrl *global_ctrl_conn; +char *ifname_prefix = NULL; +extern struct wpa_global *global; + +static void wpa_cli_msg_cb(char *msg, size_t len) +{ + wpa_printf(MSG_INFO, "%s\n", msg); +} + +static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print, char *resp) +{ + char buf[CMD_BUF_LEN] = { 0 }; + size_t len; + int ret; + + if (ctrl_conn == NULL && global_ctrl_conn == NULL) { + wpa_printf(MSG_ERROR, "Not connected to wpa_supplicant - command dropped.\n"); + return -1; + } + if (ifname_prefix) { + os_snprintf(buf, sizeof(buf), "IFNAME=%s %s", + ifname_prefix, cmd); + buf[sizeof(buf) - 1] = '\0'; + cmd = buf; + } + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, + wpa_cli_msg_cb); + if (ret == -2) { + wpa_printf(MSG_ERROR, "'%s' command timed out.\n", cmd); + return -2; + } else if (ret < 0) { + wpa_printf(MSG_ERROR, "'%s' command failed.\n", cmd); + return -1; + } + + if (resp) { + /* Remove the LF */ + os_memcpy(resp, buf, len - 1); + } + +#ifndef CONFIG_WPA_CLI + /* This is not interactive */ + if (os_strncmp(buf, "OK\n", len) == 0 || + os_strncmp(buf, "FAIL\n", len) == 0) + { + print = 0; + } +#endif + + if (print) { + buf[len] = '\0'; + printf("%s", buf); + } + return 0; +} + +static int wpa_ctrl_command_resp(struct wpa_ctrl *ctrl, const char *cmd, char *resp) +{ + return _wpa_ctrl_command(ctrl, cmd, 0, resp); +} + +static void wpa_cli_close_connection(void) +{ + if (ctrl_conn == NULL) + return; + + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; +} + +static int wpa_cli_open_connection(struct wpa_supplicant *wpa_s) +{ + ctrl_conn = wpa_ctrl_open(wpa_s->ctrl_iface->sock_pair[0]); + if (ctrl_conn == NULL) { + wpa_printf(MSG_ERROR, "Failed to open control connection to %d", + wpa_s->ctrl_iface->sock_pair[0]); + return -1; + } + + return 0; +} + +static int wpa_cli_open_global_ctrl(void) +{ + global_ctrl_conn = wpa_ctrl_open(global->ctrl_iface->sock_pair[0]); + if (global_ctrl_conn == NULL) { + wpa_printf(MSG_ERROR, "Failed to open global control connection to %d", + global->ctrl_iface->sock_pair[0]); + return -1; + } + + return 0; +} + +static void wpa_cli_close_global_ctrl(void) +{ + if (global_ctrl_conn == NULL) + return; + + wpa_ctrl_close(global_ctrl_conn); + global_ctrl_conn = NULL; +} + + +/* Lifted from zephyr shell_utils.c to handle escapes */ +static inline uint16_t supp_strlen(const char *str) +{ + return str == NULL ? 0U : (uint16_t)strlen(str); +} + +static char make_argv(char **ppcmd, uint8_t c) +{ + char *cmd = *ppcmd; + char quote = 0; + + while (1) { + c = *cmd; + + if (c == '\0') { + break; + } + + if (quote == c) { + memmove(cmd, cmd + 1, supp_strlen(cmd)); + quote = 0; + continue; + } + + if (quote && c == '\\') { + char t = *(cmd + 1); + + if (t == quote) { + memmove(cmd, cmd + 1, + supp_strlen(cmd)); + cmd += 1; + continue; + } + + if (t == '0') { + uint8_t i; + uint8_t v = 0U; + + for (i = 2U; i < (2 + 3); i++) { + t = *(cmd + i); + + if (t >= '0' && t <= '7') { + v = (v << 3) | (t - '0'); + } else { + break; + } + } + + if (i > 2) { + memmove(cmd, cmd + (i - 1), + supp_strlen(cmd) - (i - 2)); + *cmd++ = v; + continue; + } + } + + if (t == 'x') { + uint8_t i; + uint8_t v = 0U; + + for (i = 2U; i < (2 + 2); i++) { + t = *(cmd + i); + + if (t >= '0' && t <= '9') { + v = (v << 4) | (t - '0'); + } else if ((t >= 'a') && + (t <= 'f')) { + v = (v << 4) | (t - 'a' + 10); + } else if ((t >= 'A') && (t <= 'F')) { + v = (v << 4) | (t - 'A' + 10); + } else { + break; + } + } + + if (i > 2) { + memmove(cmd, cmd + (i - 1), + supp_strlen(cmd) - (i - 2)); + *cmd++ = v; + continue; + } + } + } + + if (!quote && isspace((int) c)) { + break; + } + + cmd += 1; + } + *ppcmd = cmd; + + return quote; +} + + +char supp_make_argv(size_t *argc, const char **argv, char *cmd, + uint8_t max_argc) +{ + char quote = 0; + char c; + + *argc = 0; + do { + c = *cmd; + if (c == '\0') { + break; + } + + if (isspace((int) c)) { + *cmd++ = '\0'; + continue; + } + + argv[(*argc)++] = cmd; + if (*argc == max_argc) { + break; + } + quote = make_argv(&cmd, c); + } while (true); + + return quote; +} + +int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd) +{ + return _wpa_ctrl_command(ctrl, cmd, 1, NULL); +} + +/* Public APIs */ + +int z_global_wpa_ctrl_init(void) +{ + int ret; + + ret = wpa_cli_open_global_ctrl(); + if (ret < 0) { + wpa_printf(MSG_INFO, "Failed to initialize global control interface: %d", ret); + return ret; + } + + return ret; +} + + +void z_global_wpa_ctrl_deinit(void) +{ + return wpa_cli_close_global_ctrl(); +} + +int z_wpa_ctrl_init(void *wpa_s) +{ + int ret; + struct wpa_supplicant *supp = wpa_s; + + ret = wpa_cli_open_connection(supp); + if (ret < 0) { + wpa_printf(MSG_INFO, "Failed to initialize control interface: %s: %d", supp->ifname, ret); + return ret; + } + + return ret; +} + +void z_wpa_ctrl_deinit(void) +{ + wpa_cli_close_connection(); +} + +int z_wpa_ctrl_zephyr_cmd(int argc, const char *argv[]) +{ + return wpa_request(ctrl_conn, argc , (char **) argv); +} + +int z_wpa_cli_cmd_v(const char *fmt, ...) +{ + va_list cmd_args; + int argc; + const char *argv[MAX_ARGS] = {0}; + char cmd[MAX_CMD_SIZE] = {0}; + + va_start(cmd_args, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, cmd_args); + va_end(cmd_args); + + (void)supp_make_argv(&argc, &argv[0], cmd, MAX_ARGS); + + wpa_printf(MSG_DEBUG, "Calling wpa_cli: %s, argc: %d\n", cmd, argc); + for (int i = 0; i < argc; i++) + wpa_printf(MSG_DEBUG, "argv[%d]: %s\n", i, argv[i]); + + return z_wpa_ctrl_zephyr_cmd(argc, argv); +} + +int z_wpa_ctrl_add_network(struct add_network_resp *resp) +{ + int ret; + char buf[MAX_RESPONSE_SIZE] = {0}; + + ret = wpa_ctrl_command_resp(ctrl_conn, "ADD_NETWORK", buf); + if (ret) { + return ret; + } + + ret = sscanf((const char *)buf, "%d", &resp->network_id); + if (ret < 0) { + wpa_printf(MSG_INFO, "Failed to parse ADD_NETWORK response: %s", + strerror(errno)); + return -1; + } + + return 0; +} + +int z_wpa_ctrl_signal_poll(struct signal_poll_resp *resp) +{ + int ret; + char buf[MAX_RESPONSE_SIZE] = {0}; + + ret = wpa_ctrl_command_resp(ctrl_conn, "SIGNAL_POLL", buf); + if (ret) { + return ret; + } + + ret = sscanf((const char *)buf, "RSSI=%d", &resp->rssi); + if (ret < 0) { + wpa_printf(MSG_INFO, "Failed to parse SIGNAL_POLL response: %s", + strerror(errno)); + return -1; + } + + return 0; +} + +int z_wpa_ctrl_status(struct status_resp *resp) +{ + int ret; + char buf[MAX_RESPONSE_SIZE] = {0}; + + ret = wpa_ctrl_command_resp(ctrl_conn, "STATUS", buf); + if (ret) { + return ret; + } + + ret = sscanf((const char *)buf, "bssid=%%*\nfreq=%%*\nssid=%s", resp->ssid); + if (ret < 0) { + wpa_printf(MSG_INFO, "Failed to parse STATUS response: %s", + strerror(errno)); + return -1; + } + resp->ssid_len = strlen(resp->ssid); + + return 0; +} + +int z_wpa_global_ctrl_zephyr_cmd(int argc, const char *argv[]) +{ + return wpa_request(global_ctrl_conn, argc , (char **) argv); +} + +int z_wpa_cli_global_cmd_v(const char *fmt, ...) +{ + va_list cmd_args; + int argc; + const char *argv[MAX_ARGS] = {0}; + char cmd[MAX_CMD_SIZE]; + + va_start(cmd_args, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, cmd_args); + va_end(cmd_args); + + (void)supp_make_argv(&argc, &argv[0], cmd, MAX_ARGS); + + wpa_printf(MSG_DEBUG, "Calling wpa_cli: %s, argc: %d\n", cmd, argc); + for (int i = 0; i < argc; i++) + wpa_printf(MSG_DEBUG, "argv[%d]: %s\n", i, argv[i]); + + return z_wpa_global_ctrl_zephyr_cmd(argc, argv); +} diff --git a/wpa_supplicant/wpa_cli_zephyr.h b/wpa_supplicant/wpa_cli_zephyr.h new file mode 100644 index 000000000..57e4e4fee --- /dev/null +++ b/wpa_supplicant/wpa_cli_zephyr.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef __WPA_CLI_ZEPHYR_H_ +#define __WPA_CLI_ZEPHYR_H_ + +#include + +#define SSID_MAX_LEN 32 + +/* Public data structures - no serialization done, so, non-nested only */ +struct add_network_resp { + int network_id; +}; + +struct signal_poll_resp { + int rssi; +}; + +struct status_resp { + char ssid_len; + char ssid[SSID_MAX_LEN + 1]; +}; + +/* Public APIs */ +int z_wpa_ctrl_init(void *wpa_s); +void z_wpa_ctrl_deinit(void); +int z_wpa_ctrl_zephyr_cmd(int argc, const char *argv[]); +int z_wpa_cli_cmd_v(const char *fmt, ...); + +int z_wpa_ctrl_add_network(struct add_network_resp *resp); +int z_wpa_ctrl_signal_poll(struct signal_poll_resp *resp); +int z_wpa_ctrl_status(struct status_resp *resp); + +/* Global control interface */ +int z_global_wpa_ctrl_init(void); +void z_global_wpa_ctrl_deinit(void); +int z_wpa_global_ctrl_zephyr_cmd(int argc, const char *argv[]); +int z_wpa_cli_global_cmd_v(const char *fmt, ...); + +#endif /* __WPA_CLI_ZEPHYR_H_ */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index d89ee17e4..0feec5252 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -10,6 +10,10 @@ * functions for managing network connections. */ +#ifdef CONFIG_ZEPHYR +#include +#endif /* CONFIG_ZEPHYR */ + #include "includes.h" #ifdef CONFIG_MATCH_IFACE #include @@ -905,6 +909,27 @@ void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s) } } +// TODO: This WAR is needed as we always lose the first frame after association (DHCP), +// and IP assignment gets delayed (esp. with exponential backoff in Zephyr DHCP client), so +// we send out a dummy frame that will be lost, and then DHCP will go through smoothly. +// +// Remove this once the first frame issue is fixed. +static void dhcp_war(struct wpa_supplicant *wpa_s) +{ + int len = 30, res = -1; + char *buf; + + buf = os_malloc(len); + if (buf == NULL) + return; + + memset(buf, 0xAA, len); + + res = l2_packet_send(wpa_s->l2, wpa_s->bssid, ntohs(0x8989), buf, len); + wpa_printf(MSG_DEBUG, "DHCP WAR: TX frame res=%d", res); + os_free(buf); +} + /** * wpa_supplicant_set_state - Set current connection state @@ -1012,9 +1037,13 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_s->after_wps = 0; wpa_s->known_wps_freq = 0; wpas_p2p_completed(wpa_s); + dhcp_war(wpa_s); sme_sched_obss_scan(wpa_s, 1); +#ifdef CONFIG_ZEPHYR + send_wifi_mgmt_event(wpa_s->ifname, NET_EVENT_WIFI_CMD_CONNECT_RESULT, 0); +#endif /* CONFIG_ZEPHYR */ #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) if (!fils_hlp_sent && ssid && ssid->eap.erp) update_fils_connect_params = true; @@ -1156,6 +1185,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration file '%s' - exiting", wpa_s->confanother); + os_free(conf); return -1; } @@ -6223,7 +6253,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); wpa_dbg(wpa_s, MSG_DEBUG, - "Starting radio work '%s'@%p after %ld.%06ld second wait", + "Starting radio work '%s'@%p after %lld.%06lld second wait", work->type, work, diff.sec, diff.usec); work->started = 1; work->time = now; @@ -6421,7 +6451,7 @@ void radio_work_done(struct wpa_radio_work *work) os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); - wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds", + wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %lld.%06lld seconds", work->type, work, started ? "done" : "canceled", diff.sec, diff.usec); radio_work_free(work); @@ -8187,6 +8217,7 @@ void wpas_request_disconnection(struct wpa_supplicant *wpa_s) } +#ifndef CONFIG_ZEPHYR void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, struct wpa_used_freq_data *freqs_data, unsigned int len) @@ -8201,6 +8232,7 @@ void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, i, cur->freq, cur->flags); } } +#endif /* CONFIG_ZEPHYR */ /* @@ -8253,7 +8285,9 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, } } +#ifndef CONFIG_ZEPHYR dump_freq_data(wpa_s, "completed iteration", freqs_data, idx); +#endif /* CONFIG_ZEPHYR */ return idx; } @@ -8577,6 +8611,17 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s, return 0; } +int wpa_drv_get_conn_info(struct wpa_supplicant *wpa_s, struct wpa_conn_info *ci) +{ + int res; + + if (!wpa_s->driver->get_conn_info) + return -1; + + res = wpa_s->driver->get_conn_info(wpa_s->drv_priv, ci); + + return res; +} int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_signal_info *si) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 5d2f23d1b..e79cd6260 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -960,6 +960,9 @@ struct wpa_supplicant { unsigned int connection_vht:1; unsigned int connection_he:1; unsigned int disable_mbo_oce:1; + unsigned int connection_a:1; + unsigned int connection_b:1; + unsigned int connection_g:1; struct os_reltime last_mac_addr_change; int last_mac_addr_style; diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt new file mode 100644 index 000000000..aa2a93f89 --- /dev/null +++ b/zephyr/CMakeLists.txt @@ -0,0 +1,339 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +if(CONFIG_WPA_SUPP) + +zephyr_library() + +set(HOSTAP_BASE ${CMAKE_CURRENT_SOURCE_DIR}/../) +set(WPA_SUPPLICANT_BASE ${HOSTAP_BASE}/wpa_supplicant) +set(COMMON_SRC_BASE ${HOSTAP_BASE}/src) + +set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -lnosys") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMISSING_SYSCALL_NAMES") + +zephyr_compile_definitions( + CONFIG_ZEPHYR +) + +zephyr_include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${HOSTAP_BASE}/ + ${WPA_SUPPLICANT_BASE}/ + ${COMMON_SRC_BASE}/ +) + +zephyr_library_compile_definitions( + TLS_DEFAULT_CIPHERS=\""DEFAULT:!EXP:!LOW"\" + CONFIG_SHA256 + CONFIG_SME + CONFIG_NO_CONFIG_WRITE + CONFIG_NO_CONFIG_BLOBS + CONFIG_WPA_S_ZEPHYR_L2_WIFI_MGMT + #CONFIG_NO_STDOUT_DEBUG + CONFIG_CTRL_IFACE + CONFIG_CTRL_IFACE_ZEPHYR + CONFIG_NO_RANDOM_POOL + CONFIG_MBO + CONFIG_WNM + ) + +zephyr_library_include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${HOSTAP_BASE}/ + ${COMMON_SRC_BASE}/utils + ${COMMON_SRC_BASE}/drivers + ${HOSTAP_BASE}/src + ${ZEPHYR_BASE}/include + ${ZEPHYR_BASE}/include/net +) + +zephyr_library_sources( + ${COMMON_SRC_BASE}/common/wpa_common.c + ${COMMON_SRC_BASE}/common/ieee802_11_common.c + ${COMMON_SRC_BASE}/common/hw_features_common.c + ${COMMON_SRC_BASE}/common/wpa_ctrl.c + ${COMMON_SRC_BASE}/common/cli.c + + ${COMMON_SRC_BASE}/drivers/driver_common.c + ${COMMON_SRC_BASE}/drivers/drivers.c + ${COMMON_SRC_BASE}/l2_packet/l2_packet_zephyr.c + ${COMMON_SRC_BASE}/drivers/driver_zephyr.c + ${COMMON_SRC_BASE}/utils/common.c + ${COMMON_SRC_BASE}/utils/wpabuf.c + ${COMMON_SRC_BASE}/utils/bitfield.c + ${COMMON_SRC_BASE}/utils/eloop.c + ${COMMON_SRC_BASE}/utils/os_zephyr.c + ${COMMON_SRC_BASE}/utils/radiotap.c + ${WPA_SUPPLICANT_BASE}/config.c + ${WPA_SUPPLICANT_BASE}/notify.c + ${WPA_SUPPLICANT_BASE}/bss.c + ${WPA_SUPPLICANT_BASE}/eap_register.c + ${WPA_SUPPLICANT_BASE}/op_classes.c + ${WPA_SUPPLICANT_BASE}/rrm.c + ${WPA_SUPPLICANT_BASE}/wmm_ac.c + ${WPA_SUPPLICANT_BASE}/config_none.c + ${WPA_SUPPLICANT_BASE}/sme.c + ${WPA_SUPPLICANT_BASE}/wpa_supplicant.c + ${WPA_SUPPLICANT_BASE}/events.c + ${WPA_SUPPLICANT_BASE}/bssid_ignore.c + ${WPA_SUPPLICANT_BASE}/wpas_glue.c + ${WPA_SUPPLICANT_BASE}/scan.c + ${WPA_SUPPLICANT_BASE}/robust_av.c + ${WPA_SUPPLICANT_BASE}/ctrl_iface.c + ${WPA_SUPPLICANT_BASE}/mbo.c + ${WPA_SUPPLICANT_BASE}/wnm_sta.c + ${WPA_SUPPLICANT_BASE}/wpa_cli_cmds.c + ${WPA_SUPPLICANT_BASE}/ctrl_iface_zephyr.c + ${WPA_SUPPLICANT_BASE}/wpa_cli_zephyr.c + # Zephyr main + src/supp_main.c + src/utils/wpa_debug.c + src/supp_api.c + src/supp_events.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_CLI + src/wpa_cli.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_AP + ${WPA_SUPPLICANT_BASE}/ap.c + ${COMMON_SRC_BASE}/ap/ap_config.c + ${COMMON_SRC_BASE}/ap/ap_drv_ops.c + ${COMMON_SRC_BASE}/ap/ap_list.c + ${COMMON_SRC_BASE}/ap/ap_mlme.c + ${COMMON_SRC_BASE}/ap/authsrv.c + ${COMMON_SRC_BASE}/ap/beacon.c + ${COMMON_SRC_BASE}/ap/bss_load.c + ${COMMON_SRC_BASE}/ap/dfs.c + ${COMMON_SRC_BASE}/ap/drv_callbacks.c + ${COMMON_SRC_BASE}/ap/eap_user_db.c + ${COMMON_SRC_BASE}/ap/hostapd.c + ${COMMON_SRC_BASE}/ap/hw_features.c + ${COMMON_SRC_BASE}/ap/ieee802_11_auth.c + ${COMMON_SRC_BASE}/ap/ieee802_11.c + ${COMMON_SRC_BASE}/ap/ieee802_11_he.c + ${COMMON_SRC_BASE}/ap/ieee802_11_ht.c + ${COMMON_SRC_BASE}/ap/ieee802_11_shared.c + ${COMMON_SRC_BASE}/ap/ieee802_11_vht.c + ${COMMON_SRC_BASE}/ap/ieee802_1x.c + ${COMMON_SRC_BASE}/ap/neighbor_db.c + ${COMMON_SRC_BASE}/ap/p2p_hostapd.c + ${COMMON_SRC_BASE}/ap/pmksa_cache_auth.c + ${COMMON_SRC_BASE}/ap/preauth_auth.c + ${COMMON_SRC_BASE}/ap/rrm.c + ${COMMON_SRC_BASE}/ap/sta_info.c + ${COMMON_SRC_BASE}/ap/tkip_countermeasures.c + ${COMMON_SRC_BASE}/ap/utils.c + ${COMMON_SRC_BASE}/ap/wmm.c + + ${COMMON_SRC_BASE}/ap/wpa_auth.c + ${COMMON_SRC_BASE}/ap/wpa_auth_ie.c + ${COMMON_SRC_BASE}/ap/wpa_auth_ft.c + ${COMMON_SRC_BASE}/ap/wpa_auth_glue.c + + ${COMMON_SRC_BASE}/eap_common/eap_common.c + ${COMMON_SRC_BASE}/eap_server/eap_server.c + ${COMMON_SRC_BASE}/eap_server/eap_server_identity.c + ${COMMON_SRC_BASE}/eap_server/eap_server_methods.c + ${COMMON_SRC_BASE}/eapol_auth/eapol_auth_sm.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_AP + CONFIG_AP + CONFIG_NO_RADIUS + CONFIG_NO_VLAN + CONFIG_NO_ACCOUNTING + CONFIG_NEED_AP_MLME + CONFIG_IEEE80211AX + CONFIG_EAP_SERVER + CONFIG_EAP_SERVER_IDENTITY +) + + +zephyr_library_sources_ifndef(CONFIG_WPA_SUPP_CRYPTO + ${COMMON_SRC_BASE}/crypto/crypto_none.c +) + +zephyr_library_compile_definitions_ifndef(CONFIG_WPA_SUPP_CRYPTO + CONFIG_NO_WPA + CONFIG_CRYPTO_INTERNAL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_CRYPTO + CONFIG_WEP +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_CRYPTO + ${COMMON_SRC_BASE}/common/wpa_common.c + ${COMMON_SRC_BASE}/rsn_supp/wpa.c + ${COMMON_SRC_BASE}/rsn_supp/preauth.c + ${COMMON_SRC_BASE}/rsn_supp/wpa_ie.c + + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls-bignum.c + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls-ec.c + ${COMMON_SRC_BASE}/crypto/crypto_mbedtls.c + ${COMMON_SRC_BASE}/crypto/tls_mbedtls.c + ${COMMON_SRC_BASE}/crypto/aes-wrap.c + ${COMMON_SRC_BASE}/crypto/aes-unwrap.c + ${COMMON_SRC_BASE}/crypto/rc4.c + #${COMMON_SRC_BASE}/crypto/random.c + ${COMMON_SRC_BASE}/crypto/sha1-prf.c + ${COMMON_SRC_BASE}/crypto/sha256-prf.c + ${COMMON_SRC_BASE}/crypto/sha256-prf.c + ${COMMON_SRC_BASE}/crypto/sha384-prf.c +) + + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_WPA3 + ${COMMON_SRC_BASE}/common/sae.c + ${COMMON_SRC_BASE}/common/dragonfly.c + + ${COMMON_SRC_BASE}/crypto/dh_groups.c + ${COMMON_SRC_BASE}/crypto/sha256-kdf.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_WPA3 + CONFIG_SAE + CONFIG_ECC +) + +zephyr_library_include_directories_ifdef(CONFIG_WPA_SUPP_CRYPTO + ${CMAKE_SOURCE_DIR} +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_P2P + ${WPA_SUPPLICANT_BASE}/p2p_supplicant.c + ${WPA_SUPPLICANT_BASE}/p2p_supplicant_sd.c + ${COMMON_SRC_BASE}/p2p/p2p.c + ${COMMON_SRC_BASE}/p2p/p2p_utils.c + ${COMMON_SRC_BASE}/p2p/p2p_parse.c + ${COMMON_SRC_BASE}/p2p/p2p_build.c + ${COMMON_SRC_BASE}/p2p/p2p_go_neg.c + ${COMMON_SRC_BASE}/p2p/p2p_sd.c + ${COMMON_SRC_BASE}/p2p/p2p_pd.c + ${COMMON_SRC_BASE}/p2p/p2p_invitation.c + ${COMMON_SRC_BASE}/p2p/p2p_dev_disc.c + ${COMMON_SRC_BASE}/p2p/p2p_group.c + ${COMMON_SRC_BASE}/ap/p2p_hostapd.c + ${COMMON_SRC_BASE}/common/gas.c + ${WPA_SUPPLICANT_BASE}/gas_query.c + ${WPA_SUPPLICANT_BASE}/offchannel.c +) +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_WPS + ${WPA_SUPPLICANT_BASE}/wps_supplicant.c + ${COMMON_SRC_BASE}/utils/uuid.c + ${COMMON_SRC_BASE}/eap_peer/eap_wsc.c + ${COMMON_SRC_BASE}/eap_common/eap_wsc_common.c + ${COMMON_SRC_BASE}/wps/wps.c + ${COMMON_SRC_BASE}/ap/wps_hostapd.c + ${COMMON_SRC_BASE}/wps/wps_common.c + ${COMMON_SRC_BASE}/wps/wps_attr_parse.c + ${COMMON_SRC_BASE}/wps/wps_attr_build.c + ${COMMON_SRC_BASE}/wps/wps_attr_process.c + ${COMMON_SRC_BASE}/wps/wps_dev_attr.c + ${COMMON_SRC_BASE}/wps/wps_enrollee.c + ${COMMON_SRC_BASE}/wps/wps_registrar.c + ${COMMON_SRC_BASE}/crypto/dh_groups.c + ${COMMON_SRC_BASE}/crypto/dh_group5.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_P2P + CONFIG_P2P + CONFIG_GAS + CONFIG_OFFCHANNEL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_WPS + CONFIG_WPS + CONFIG_EAP_WSC +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_CRYPTO_ENTERPRISE + ${COMMON_SRC_BASE}/eap_peer/eap_tls.c + ${COMMON_SRC_BASE}/eap_peer/eap_tls_common.c + + + ${COMMON_SRC_BASE}/eap_peer/eap_peap.c + ${COMMON_SRC_BASE}/eap_common/eap_peap_common.c + ${COMMON_SRC_BASE}/eap_peer/eap_ttls.c + ${COMMON_SRC_BASE}/eap_peer/eap_md5.c + ${COMMON_SRC_BASE}/eap_peer/eap_mschapv2.c + ${COMMON_SRC_BASE}/eap_common/chap.c + ${COMMON_SRC_BASE}/eap_peer/mschapv2.c + ${COMMON_SRC_BASE}/eap_peer/eap_leap.c + + ${COMMON_SRC_BASE}/eap_peer/eap_psk.c + ${COMMON_SRC_BASE}/eap_common/eap_psk_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_fast.c + ${COMMON_SRC_BASE}/eap_peer/eap_fast_pac.c + ${COMMON_SRC_BASE}/eap_common/eap_fast_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_pax.c + ${COMMON_SRC_BASE}/eap_common/eap_pax_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_sake.c + ${COMMON_SRC_BASE}/eap_common/eap_sake_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_gpsk.c + ${COMMON_SRC_BASE}/eap_common/eap_gpsk_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_pwd.c + ${COMMON_SRC_BASE}/eap_common/eap_pwd_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_eke.c + ${COMMON_SRC_BASE}/eap_common/eap_eke_common.c + + ${COMMON_SRC_BASE}/eap_peer/eap_ikev2.c + ${COMMON_SRC_BASE}/eap_peer/ikev2.c + ${COMMON_SRC_BASE}/eap_common/eap_ikev2_common.c + ${COMMON_SRC_BASE}/eap_common/ikev2_common.c + + # common + ${COMMON_SRC_BASE}/crypto/sha384-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha256-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha1-tlsprf.c + ${COMMON_SRC_BASE}/crypto/sha1-tprf.c + ${COMMON_SRC_BASE}/crypto/ms_funcs.c + ${COMMON_SRC_BASE}/crypto/aes-eax.c + # MD4 removed from MbedTLS + ${COMMON_SRC_BASE}/crypto/md4-internal + ${COMMON_SRC_BASE}/crypto/aes-encblock.c + +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_CRYPTO_ENTERPRISE + CONFIG_EAP_TLS + CONFIG_IEEE8021X_EAPOL + CONFIG_EAP_PEAP + CONFIG_EAP_TTLS + CONFIG_EAP_MD5 + CONFIG_EAP_MSCHAPv2 + CONFIG_EAP_LEAP + CONFIG_EAP_PSK + CONFIG_EAP_FAST + CONFIG_EAP_PAX + CONFIG_EAP_SAKE + CONFIG_EAP_GPSK + CONFIG_EAP_PWD + CONFIG_EAP_EKE + CONFIG_EAP_IKEv2 +) + +zephyr_library_sources_ifdef(CONFIG_WPA_SUPP_EAPOL + ${COMMON_SRC_BASE}/eapol_supp/eapol_supp_sm.c + ${COMMON_SRC_BASE}/eap_peer/eap.c + ${COMMON_SRC_BASE}/eap_peer/eap_methods.c + ${COMMON_SRC_BASE}/eap_common/eap_common.c + ${COMMON_SRC_BASE}/rsn_supp/pmksa_cache.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WPA_SUPP_EAPOL + IEEE8021X_EAPOL +) +endif() diff --git a/zephyr/Kconfig b/zephyr/Kconfig new file mode 100644 index 000000000..19c2243b1 --- /dev/null +++ b/zephyr/Kconfig @@ -0,0 +1,125 @@ +# Nordic WiFi driver for nRF52840 and nRF5340 +# +# Copyright (c) 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config WPA_SUPP + bool "WPA supplicant support" + depends on NET_SOCKETS + # Need full POSIX from libc, Zephyr's POSIX support is only partial + depends on !POSIX_API + select POSIX_CLOCK + select NET_SOCKETS_PACKET + select NET_SOCKETPAIR + select NET_L2_WIFI_MGMT + select EXPERIMENTAL if !SOC_SERIES_NRF53X && !SOC_SERIES_NRF91X + help + WPA supplicant implements 802.1X related functions. + +if WPA_SUPP + +config WPA_SUPP_THREAD_STACK_SIZE + int "Stack size for wpa_supplicant thread" + default 8192 + +config WPA_SUPP_IFACE_WQ_STACK_SIZE + int "Stack size for wpa_supplicant iface workqueue" + default 4096 + +config WEP + bool "WEP (Legacy crypto) support" + +config WPA_SUPP_CRYPTO + bool "Crypto support for WiFi" + select WEP + select MBEDTLS + select NRF_SECURITY + select MBEDTLS_CIPHER_MODE_CBC + select MBEDTLS_CIPHER_MODE_CTR + select MBEDTLS_LEGACY_CRYPTO_C + select MBEDTLS_ECP_C + select MBEDTLS_CTR_DRBG_C + select MBEDTLS_ENTROPY_C + select MBEDTLS_PK_WRITE_C + select MBEDTLS_KEY_EXCHANGE_ALL_ENABLED + default y + +# Needed for internal entropy +config MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + default n if WPA_SUPP_CRYPTO + +# To fix MAC_MD5 Kconfig warning +config NET_TCP_ISN_RFC6528 + default n if WPA_SUPP_CRYPTO + +config WPA_SUPP_CRYPTO_ENTERPRISE + bool "Enterprise Crypto support for WiFi" + +config WPA_SUPP_WPA3 + bool "WPA3 support" + select WPA_SUPP_CRYPTO + default y + +config WPA_SUPP_AP + bool "AP mode support" + select WPA_SUPP_CRYPTO + +config WPA_SUPP_WPS + bool "WPS support" + +config WPA_SUPP_P2P + bool "P2P mode support" + select WPA_SUPP_AP + select WPA_SUPP_WPS + +config WPA_SUPP_EAPOL + bool "Enable EAPoL supplicant" + +config WPA_CLI + bool "CLI support for wpa_supplicant" + default n + +config NET_SOCKETPAIR_BUFFER_SIZE + default 4096 + +config POSIX_MAX_FDS + # l2_packet - 1 + # ctrl_iface - 2 * socketpairs = 4(local and global) + # z_wpa_event_sock - 1 socketpair = 2 + default 7 if !POSIX_API + +# Control interface is stack heavy (buffers + snprintfs) +# Making calls to RPU from net_mgmt callbacks (status - RSSI) +config NET_MGMT_EVENT_STACK_SIZE + default 4096 + +config NET_SOCKETS_POLL_MAX + default 4 + +module = WPA_SUPP +module-str = WPA supplicant +source "subsys/logging/Kconfig.template.log_config" + +config WPA_SUPP_DEBUG_LEVEL + int "Min compiled-in debug message level for WPA supplicant" + default 0 if WPA_SUPP_LOG_LEVEL_DBG # MSG_EXCESSIVE + default 3 if WPA_SUPP_LOG_LEVEL_INF # MSG_INFO + default 4 if WPA_SUPP_LOG_LEVEL_WRN # MSG_WARNING + default 5 if WPA_SUPP_LOG_LEVEL_ERR # MSG_ERROR + default 6 + help + Minimum priority level of a debug message emitted by WPA supplicant that + is compiled-in the firmware. See wpa_debug.h file of the supplicant for + available levels and functions for emitting the messages. Note that + runtime filtering can also be configured in addition to the compile-time + filtering. + +config WPA_SUPP_DEBUG_SHOW_KEYS + bool "Show keys in debug output" + help + This option can be used to show keys (e.g., PSK, EAP session keys) in + debug log messages. This can be used to debug key derivation and + authentication issues. Please do not enable this option in production. +endif diff --git a/zephyr/module.yml b/zephyr/module.yml new file mode 100644 index 000000000..9c43bc6e5 --- /dev/null +++ b/zephyr/module.yml @@ -0,0 +1,3 @@ +build: + cmake: ./zephyr + kconfig: ./zephyr/Kconfig diff --git a/zephyr/src/supp_api.c b/zephyr/src/supp_api.c new file mode 100644 index 000000000..333a89476 --- /dev/null +++ b/zephyr/src/supp_api.c @@ -0,0 +1,396 @@ +/** + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include + +#include +#include + +#include "includes.h" +#include "common.h" +#include "common/defs.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_api.h" +#include "wpa_cli_zephyr.h" + +extern struct k_sem wpa_supplicant_ready_sem; +extern struct wpa_global *global; + +enum requested_ops { + CONNECT = 0, + DISCONNECT +}; + +enum status_thread_state { + STATUS_THREAD_STOPPED = 0, + STATUS_THREAD_RUNNING, +}; + +#define OP_STATUS_POLLING_INTERVAL 1 + +#define CONNECTION_SUCCESS 0 +#define CONNECTION_FAILURE 1 +#define CONNECTION_TERMINATED 2 + +#define _wpa_cli_cmd_v(cmd, ...) \ + do { \ + if (z_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, "Failed to execute wpa_cli command: %s", cmd); \ + goto out; \ + } \ + } while (0) + +K_MUTEX_DEFINE(wpa_supplicant_mutex); + + +struct wpa_supp_api_ctrl { + const struct device *dev; + enum requested_ops requested_op; + enum status_thread_state status_thread_state; + int connection_timeout; // in seconds + struct k_work_sync sync; + bool terminate; +}; + +static struct wpa_supp_api_ctrl wpa_supp_api_ctrl; + +static void supp_shell_connect_status(struct k_work *work); + +static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, + supp_shell_connect_status); + +static inline struct wpa_supplicant * get_wpa_s_handle(const struct device *dev) +{ + return z_wpas_get_handle_by_ifname(dev->name); +} + +static void supp_shell_connect_status(struct k_work *work) +{ + static int seconds_counter = 0; + int status = CONNECTION_SUCCESS; + struct wpa_supplicant *wpa_s; + struct wpa_supp_api_ctrl *ctrl = &wpa_supp_api_ctrl; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + if (ctrl->status_thread_state == STATUS_THREAD_RUNNING && ctrl->terminate) { + status = CONNECTION_TERMINATED; + goto out; + } + + wpa_s = get_wpa_s_handle(ctrl->dev); + if (!wpa_s) { + status = CONNECTION_FAILURE; + goto out; + } + + if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { + if (ctrl->connection_timeout > 0 && seconds_counter++ > ctrl->connection_timeout) { + _wpa_cli_cmd_v("disconnect"); + status = CONNECTION_FAILURE; + goto out; + } + + k_work_reschedule(&wpa_supp_status_work, K_SECONDS(OP_STATUS_POLLING_INTERVAL)); + ctrl->status_thread_state = STATUS_THREAD_RUNNING; + k_mutex_unlock(&wpa_supplicant_mutex); + return; + } +out: + seconds_counter = 0; + + ctrl->status_thread_state = STATUS_THREAD_STOPPED; + k_mutex_unlock(&wpa_supplicant_mutex); +} + +static inline void wpa_supp_restart_status_work(void) +{ + /* Terminate synchronously */ + wpa_supp_api_ctrl.terminate = 1; + k_work_flush_delayable(&wpa_supp_status_work, + &wpa_supp_api_ctrl.sync); + wpa_supp_api_ctrl.terminate = 0; + + /* Start afresh */ + k_work_reschedule(&wpa_supp_status_work, + K_MSEC(10)); +} + +static inline int chan_to_freq(int chan) +{ + /* We use global channel list here and also use the widest + * op_class for 5GHz channels as there is no user input + * for these (yet). + */ + int freq = ieee80211_chan_to_freq(NULL, 81, chan); + + if (freq <= 0) { + freq = ieee80211_chan_to_freq(NULL, 128, chan); + } + + if (freq <= 0) { + wpa_printf(MSG_ERROR, "Invalid channel %d", chan); + return -1; + } + + return freq; +} + + +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + struct add_network_resp resp = {0}; + + if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) { + wpa_printf(MSG_ERROR, + "Interface %s is down, dropping connect", + dev->name); + return -1; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -1; + goto out; + } + + _wpa_cli_cmd_v("remove_network all"); + ret = z_wpa_ctrl_add_network(&resp); + if (ret) { + goto out; + } + + wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); + + _wpa_cli_cmd_v("set_network %d ssid \"%s\"", resp.network_id, params->ssid); + _wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id); + _wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id); + _wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id); + if (params->security != WIFI_SECURITY_TYPE_NONE) { + if (params->security == WIFI_SECURITY_TYPE_SAE) { + if (params->sae_password) { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password); + } else { + _wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk); + } + _wpa_cli_cmd_v("set_network %d key_mgmt SAE", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { + _wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id); + } else if (params->security == WIFI_SECURITY_TYPE_PSK) { + _wpa_cli_cmd_v( "set_network %d psk \"%s\"", + resp.network_id, params->psk); + _wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", + resp.network_id); + } else { + ret = -1; + wpa_printf(MSG_ERROR, "Unsupported security type: %d", + params->security); + goto out; + } + + if (params->mfp) { + _wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp); + } + } + + /* enable and select network */ + _wpa_cli_cmd_v("enable_network %d", resp.network_id); + + if (params->channel != WIFI_CHANNEL_ANY) { + int freq = chan_to_freq(params->channel); + if (freq < 0) { + ret = -1; + goto out; + } + z_wpa_cli_cmd_v("set_network %d scan_freq %d", + resp.network_id, freq); + } + _wpa_cli_cmd_v("select_network %d", resp.network_id); + + z_wpa_cli_cmd_v("select_network %d", resp.network_id); + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = CONNECT; + wpa_supp_api_ctrl.connection_timeout = params->timeout; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (!ret) { + wpa_supp_restart_status_work(); + } + + return ret; +} + +int z_wpa_supplicant_disconnect(const struct device *dev) +{ + struct wpa_supplicant *wpa_s; + int ret = 0; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -EINVAL; + goto out; + } + wpa_supp_api_ctrl.dev = dev; + wpa_supp_api_ctrl.requested_op = DISCONNECT; + _wpa_cli_cmd_v("disconnect"); + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (!ret) { + wpa_supp_restart_status_work(); + } + + return ret; +} + + +static inline enum wifi_frequency_bands wpas_band_to_zephyr(enum wpa_radio_work_band band) +{ + switch(band) { + case BAND_2_4_GHZ: + return WIFI_FREQ_BAND_2_4_GHZ; + case BAND_5_GHZ: + return WIFI_FREQ_BAND_5_GHZ; + default: + return WIFI_FREQ_BAND_UNKNOWN; + } +} + +static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt) +{ + switch(key_mgmt) { + case WPA_KEY_MGMT_NONE: + return WIFI_SECURITY_TYPE_NONE; + case WPA_KEY_MGMT_PSK: + return WIFI_SECURITY_TYPE_PSK; + case WPA_KEY_MGMT_PSK_SHA256: + return WIFI_SECURITY_TYPE_PSK_SHA256; + case WPA_KEY_MGMT_SAE: + return WIFI_SECURITY_TYPE_SAE; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; + } +} + + +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status) +{ + struct wpa_supplicant *wpa_s; + int ret = -1; + struct wpa_signal_info *si = NULL; + struct wpa_conn_info *conn_info = NULL; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + goto out; + } + + si = os_zalloc(sizeof(struct wpa_signal_info)); + if (!si) { + goto out; + } + + status->state = wpa_s->wpa_state; /* 1-1 Mapping */ + + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 channel; + struct signal_poll_resp signal_poll; + + os_memcpy(status->bssid, wpa_s->bssid, WIFI_MAC_ADDR_LEN); + status->band = wpas_band_to_zephyr(wpas_freq_to_band(wpa_s->assoc_freq)); + status->security = wpas_key_mgmt_to_zephyr(ssid->key_mgmt); + status->mfp = ssid->ieee80211w; /* Same mapping */ + ieee80211_freq_to_chan(wpa_s->assoc_freq, &channel); + status->channel = channel; + + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + struct status_resp cli_status; + + if (ssid_len == 0) { + int _res = z_wpa_ctrl_status(&cli_status); + + if (_res < 0) + ssid_len = 0; + else + ssid_len = cli_status.ssid_len; + _ssid = cli_status.ssid; + } + os_memcpy(status->ssid, _ssid, ssid_len); + status->ssid_len = ssid_len; + status->iface_mode = ssid->mode; + if (wpa_s->connection_set == 1) { + status->link_mode = wpa_s->connection_he ? WIFI_6 : + wpa_s->connection_vht ? WIFI_5 : + wpa_s->connection_ht ? WIFI_4 : + wpa_s->connection_g ? WIFI_3 : + wpa_s->connection_a ? WIFI_2 : + wpa_s->connection_b ? WIFI_1 : WIFI_0; + } else { + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + } + } + ret = z_wpa_ctrl_signal_poll(&signal_poll); + if (!ret) { + status->rssi = signal_poll.rssi; + } else { + wpa_printf(MSG_WARNING, "%s:Failed to read RSSI\n", + __func__); + status->rssi = -WPA_INVALID_NOISE; + ret = 0; + } + + conn_info = os_zalloc(sizeof(struct wpa_conn_info)); + if (!conn_info) { + wpa_printf(MSG_ERROR, "%s:Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + goto out; + } + ret = wpa_drv_get_conn_info(wpa_s, conn_info); + if (!ret) { + status->beacon_interval = conn_info->beacon_interval; + status->dtim_period = conn_info->dtim_period; + } else { + wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n", + __func__); + status->beacon_interval = 0; + status->dtim_period = 0; + ret = 0; + } + } else { + ret = 0; + } +out: + os_free(si); + k_mutex_unlock(&wpa_supplicant_mutex); + return ret; +} diff --git a/zephyr/src/supp_api.h b/zephyr/src/supp_api.h new file mode 100644 index 000000000..756812488 --- /dev/null +++ b/zephyr/src/supp_api.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + */ + +#ifndef ZEPHYR_SUPP_MGMT_H +#define ZEPHYR_SUPP_MGMT_H + +#include + +#define MAX_SSID_LEN 32 +#define MAC_ADDR_LEN 6 + +/** + * @brief Request a connection + * + * @param iface_name: Wi-Fi interface name to use + * @param params: Connection details + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_connect(const struct device *dev, + struct wifi_connect_req_params *params); +/** + * @brief Forces station to disconnect and stops any subsequent scan + * or connection attempts + * + * @param iface_name: Wi-Fi interface name to use + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_disconnect(const struct device *dev); + +/** + * @brief + * + * @param iface_name: Wi-Fi interface name to use + * @param wifi_iface_status: Status structure to fill + * + * @return: 0 for OK; -1 for ERROR + */ +int z_wpa_supplicant_status(const struct device *dev, + struct wifi_iface_status *status); +#endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/zephyr/src/supp_events.c b/zephyr/src/supp_events.c new file mode 100644 index 000000000..36af43614 --- /dev/null +++ b/zephyr/src/supp_events.c @@ -0,0 +1,29 @@ +#include "supp_events.h" + +#include "includes.h" +#include "common.h" + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, int status) +{ + const struct device *dev = device_get_binding(ifname); + struct net_if *iface = net_if_lookup_by_dev(dev); + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WIFI_CMD_CONNECT_RESULT: + wifi_mgmt_raise_connect_result_event(iface, status); + break; + case NET_EVENT_WIFI_CMD_DISCONNECT_RESULT: + wifi_mgmt_raise_disconnect_result_event(iface, status); + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} diff --git a/zephyr/src/supp_events.h b/zephyr/src/supp_events.h new file mode 100644 index 000000000..4290fea34 --- /dev/null +++ b/zephyr/src/supp_events.h @@ -0,0 +1,8 @@ +#ifndef __SUPP_EVENTS_H__ +#define __SUPP_EVENTS_H__ + +#include + +int send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, int status); + +#endif /* __SUPP_EVENTS_H__ */ \ No newline at end of file diff --git a/zephyr/src/supp_main.c b/zephyr/src/supp_main.c new file mode 100644 index 000000000..983601f24 --- /dev/null +++ b/zephyr/src/supp_main.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * WPA Supplicant / main() function for Zephyr OS + * Copyright (c) 2003-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +LOG_MODULE_REGISTER(wpa_supplicant, LOG_LEVEL_DBG); + +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" + +#include "fst/fst.h" +#include "includes.h" +#include "p2p_supplicant.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "wpa_cli_zephyr.h" + +K_SEM_DEFINE(z_wpas_ready_sem, 0, 1); +#include + +/* Should match with the driver name */ +#define DEFAULT_IFACE_NAME "wlan0" + +static struct net_mgmt_event_callback cb; +struct k_mutex iface_up_mutex; + +struct wpa_global *global; + +static int z_wpas_event_sockpair[2]; + +static void z_wpas_start(void); +static void z_wpas_iface_work_handler(struct k_work *item); + +K_THREAD_DEFINE(z_wpa_s_tid, + CONFIG_WPA_SUPP_THREAD_STACK_SIZE, + z_wpas_start, + NULL, + NULL, + NULL, + 0, + 0, + 0); + +static K_THREAD_STACK_DEFINE(z_wpas_iface_wq_stack, + CONFIG_WPA_SUPP_IFACE_WQ_STACK_SIZE); + +/* TODO: Debug why wsing system workqueue blocks the driver dedicated + * workqueue? + */ +static struct k_work_q z_wpas_iface_wq; +static K_WORK_DEFINE(z_wpas_iface_work, + z_wpas_iface_work_handler); + +K_MUTEX_DEFINE(z_wpas_event_mutex); + +#ifdef CONFIG_MATCH_IFACE +static int z_wpas_init_match(struct wpa_global *global) +{ + /* + * The assumption is that the first driver is the primary driver and + * will handle the arrival / departure of interfaces. + */ + if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { + global->drv_priv[0] = wpa_drivers[0]->global_init(global); + if (!global->drv_priv[0]) { + wpa_printf(MSG_ERROR, + "Failed to initialize driver '%s'", + wpa_drivers[0]->name); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_MATCH_IFACE */ + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char* ifname) +{ + struct wpa_supplicant *wpa_s = NULL; + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(2)); + + if (ret) { + wpa_printf(MSG_ERROR, "%s: WPA supplicant not ready: %d", __func__, ret); + return NULL; + } + + k_sem_give(&z_wpas_ready_sem); + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (!wpa_s) { + wpa_printf(MSG_ERROR, + "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); + return NULL; + } + + return wpa_s; +} + +static int z_wpas_get_iface_count(void) +{ + struct wpa_supplicant *wpa_s; + unsigned count = 0; + + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + count += 1; + } + return count; +} + +#define Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS 1000 +#define Z_WPA_S_IFACE_NOTIFY_RETRY_MS 10 + +static int z_wpas_add_interface(const char* ifname) +{ + struct wpa_supplicant *wpa_s; + int ret; + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + wpa_printf(MSG_DEBUG, "Adding interface %s\n", ifname); + + ret = z_wpa_cli_global_cmd_v("interface_add %s %s %s %s", + ifname, "zephyr", "zephyr", "zephyr"); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add interface: %s", ifname); + return -1; + } + + /* This cannot be through control interface as need the handle */ + while (retry ++ < count && !wpa_supplicant_get_iface(global, ifname)) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + wpa_s = wpa_supplicant_get_iface(global, ifname); + if (wpa_s == NULL) { + wpa_printf(MSG_ERROR, "Failed to add iface: %s", ifname); + return -1; + } + wpa_s->conf->filter_ssids = 1; + wpa_s->conf->ap_scan= 1; + + /* Default interface, kick start wpa_supplicant */ + if (z_wpas_get_iface_count() == 1) { + k_mutex_unlock(&iface_up_mutex); + } + + z_wpa_ctrl_init(wpa_s); + + return 0; +} + +static int z_wpas_remove_interface(const char* ifname) +{ + int ret; + union wpa_event_data *event = os_zalloc(sizeof(*event)); + struct wpa_supplicant *wpa_s = wpa_supplicant_get_iface(global, ifname); + int retry = 0, count = Z_WPA_S_IFACE_NOTIFY_TIMEOUT_MS / Z_WPA_S_IFACE_NOTIFY_RETRY_MS; + + if (!event) { + wpa_printf(MSG_ERROR, "Failed to allocate event data"); + return -1; + } + + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle for %s", ifname); + return -1; + } + + wpa_printf(MSG_DEBUG, "Remove interface %s\n", ifname); + + os_memcpy(event->interface_status.ifname, ifname, IFNAMSIZ); + event->interface_status.ievent = EVENT_INTERFACE_REMOVED; + + struct wpa_supplicant_event_msg msg = { + .global = true, + .ctx = global, + .event = EVENT_INTERFACE_STATUS, + .data = event, + }; + + z_wpas_send_event(&msg); + + while (retry++ < count && + wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + k_sleep(K_MSEC(Z_WPA_S_IFACE_NOTIFY_RETRY_MS)); + } + + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + wpa_printf(MSG_ERROR, "Failed to notify remove interface: %s", ifname); + return -1; + } + + ret = z_wpa_cli_global_cmd_v("interface_remove %s", ifname); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to remove interface: %s", ifname); + return -1; + } + + return 0; +} + +static void iface_event_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + const char *ifname = iface->if_dev->dev->name; + + wpa_printf(MSG_DEBUG, "Event: %d", mgmt_event); + if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { + z_wpas_add_interface(ifname); + } else if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { + z_wpas_remove_interface(ifname); + } +} + +static void register_iface_events(void) +{ + k_mutex_init(&iface_up_mutex); + + k_mutex_lock(&iface_up_mutex, K_FOREVER); + net_mgmt_init_event_callback(&cb, iface_event_handler, + NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN); + net_mgmt_add_event_callback(&cb); +} + +static void wait_for_interface_up(const char* iface_name) +{ + if (z_wpas_get_iface_count() == 0) { + k_mutex_lock(&iface_up_mutex, K_FOREVER); + } +} + +#include "config.h" +static void iface_cb(struct net_if *iface, void *user_data) +{ + const char *ifname = iface->if_dev->dev->name; + + if (ifname == NULL) { + return; + } + + if (strncmp(ifname, DEFAULT_IFACE_NAME, strlen(ifname)) != 0) + { + return; + } + + /* Check default interface */ + if (net_if_is_admin_up(iface)) { + z_wpas_add_interface(ifname); + } + + register_iface_events(); +} + + +static void z_wpas_iface_work_handler(struct k_work *item) +{ + ARG_UNUSED(item); + + int ret = k_sem_take(&z_wpas_ready_sem, K_SECONDS(5)); + if (ret) { + wpa_printf(MSG_ERROR, "Timed out waiting for wpa_supplicant"); + return; + } + + net_if_foreach(iface_cb, NULL); + wait_for_interface_up(DEFAULT_IFACE_NAME); + + k_sem_give(&z_wpas_ready_sem); +} + +static void z_wpas_event_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +{ + int ret; + ARG_UNUSED(eloop_ctx); + ARG_UNUSED(sock_ctx); + struct wpa_supplicant_event_msg msg; + + ret = recv(sock, &msg, sizeof(msg), 0); + + if (ret < 0) { + wpa_printf(MSG_ERROR, "Failed to recv the message: %s", strerror(errno)); + return; + } + + if (ret != sizeof(msg)) { + wpa_printf(MSG_ERROR, "Received incomplete message: got: %d, expected:%d", + ret, sizeof(msg)); + return; + } + + wpa_printf(MSG_DEBUG, "Passing message %d to wpa_supplicant", msg.event); + + if (msg.global) { + wpa_supplicant_event_global(msg.ctx, msg.event, msg.data); + } else { + wpa_supplicant_event(msg.ctx, msg.event, msg.data); + } + + if (msg.data) { + if (msg.event == EVENT_AUTH) { + union wpa_event_data *data = msg.data; + + os_free((char *)data->auth.ies); + } + os_free(msg.data); + } +} + +static int register_wpa_event_sock(void) +{ + int ret; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, z_wpas_event_sockpair); + + if (ret != 0) { + wpa_printf(MSG_ERROR, "Failed to initialize socket: %s", strerror(errno)); + return -1; + } + + eloop_register_read_sock(z_wpas_event_sockpair[0], z_wpas_event_sock_handler, NULL, NULL); + + return 0; +} + +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg) +{ + int ret; + unsigned int retry = 0; + + k_mutex_lock(&z_wpas_event_mutex, K_FOREVER); + + if (z_wpas_event_sockpair[1] < 0) { + goto err; + } + +retry_send: + ret = send(z_wpas_event_sockpair[1], msg, sizeof(*msg), 0); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) { + k_msleep(2); + if (retry++ < 3) { + goto retry_send; + } else { + wpa_printf(MSG_WARNING, "Event send fail (max retries): %s", + strerror(errno)); + goto err; + } + } else { + wpa_printf(MSG_WARNING, "Event send fail: %s", + strerror(errno)); + goto err; + } + } + + ret = 0; +err: + k_mutex_unlock(&z_wpas_event_mutex); + return -1; +} + +static void z_wpas_start(void) +{ + struct wpa_params params; + int exitcode = -1; + k_work_queue_init(&z_wpas_iface_wq); + + k_work_queue_start(&z_wpas_iface_wq, + z_wpas_iface_wq_stack, + K_THREAD_STACK_SIZEOF(z_wpas_iface_wq_stack), + 7, + NULL); + + os_memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = CONFIG_WPA_SUPP_DEBUG_LEVEL; + + exitcode = 0; + global = wpa_supplicant_init(¶ms); + if (global == NULL) { + wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant"); + exitcode = -1; + goto out; + } else { + wpa_printf(MSG_INFO, "Successfully initialized " + "wpa_supplicant"); + } + + if (fst_global_init()) { + wpa_printf(MSG_ERROR, "Failed to initialize FST"); + exitcode = -1; + goto out; + } + +#if defined (CONFIG_WPA_SUPP_LOG_LEVEL_DBG) && defined (CONFIG_WPA_SUPP_DEBUG_SHOW_KEYS) + wpa_supplicant_set_debug_params(global, MSG_DEBUG, 1, 1); +#elif defined (CONFIG_WPA_SUPP_LOG_LEVEL_DBG) + wpa_supplicant_set_debug_params(global, MSG_DEBUG, 1, 0); +#else + wpa_supplicant_set_debug_params(global, MSG_INFO, 0, 0); +#endif + +#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) + if (!fst_global_add_ctrl(fst_ctrl_cli)) { + wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); + } +#endif + z_global_wpa_ctrl_init(); + + register_wpa_event_sock(); + + k_work_submit_to_queue(&z_wpas_iface_wq, &z_wpas_iface_work); + +#ifdef CONFIG_MATCH_IFACE + if (exitcode == 0) { + exitcode = z_wpas_init_match(global); + } +#endif /* CONFIG_MATCH_IFACE */ + + if (exitcode == 0) { + k_sem_give(&z_wpas_ready_sem); + exitcode = wpa_supplicant_run(global); + } + + eloop_unregister_read_sock(z_wpas_event_sockpair[0]); + + z_wpa_ctrl_deinit(); + z_global_wpa_ctrl_deinit(); + wpa_supplicant_deinit(global); + + fst_global_deinit(); + + close(z_wpas_event_sockpair[0]); + close(z_wpas_event_sockpair[1]); + +out: +#ifdef CONFIG_MATCH_IFACE + os_free(params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ + os_free(params.pid_file); + + wpa_printf(MSG_INFO, "z_wpas_start: exitcode %d", exitcode); + return; +} diff --git a/zephyr/src/supp_main.h b/zephyr/src/supp_main.h new file mode 100644 index 000000000..d7bd862b2 --- /dev/null +++ b/zephyr/src/supp_main.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#ifndef __SUPP_MAIN_H_ +#define __SUPP_MAIN_H_ + +#include "wpa_supplicant_i.h" + +struct wpa_supplicant *z_wpas_get_handle_by_ifname(const char* ifname); +struct wpa_supplicant_event_msg { + bool global; + void *ctx; + unsigned int event; + void *data; +}; +int z_wpas_send_event(const struct wpa_supplicant_event_msg *msg); +#endif /* __SUPP_MAIN_H_ */ diff --git a/zephyr/src/utils/wpa_debug.c b/zephyr/src/utils/wpa_debug.c new file mode 100644 index 000000000..159d56c18 --- /dev/null +++ b/zephyr/src/utils/wpa_debug.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "wpa_debug.h" + +#include + +#define WPA_DEBUG_MAX_LINE_LENGTH 256 + +LOG_MODULE_REGISTER(wpa_supp, CONFIG_WPA_SUPP_LOG_LEVEL); + +int wpa_debug_level = MSG_INFO; +int wpa_debug_show_keys = 0; +int wpa_debug_timestamp = 0; + +#ifndef CONFIG_NO_STDOUT_DEBUG + +void wpa_printf_impl(int level, const char *fmt, ...) +{ + va_list ap; + char buffer[WPA_DEBUG_MAX_LINE_LENGTH]; + + if (level < wpa_debug_level) + return; + + va_start(ap, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); + + switch (level) { + case MSG_ERROR: + LOG_ERR("%s", buffer); + break; + case MSG_WARNING: + LOG_WRN("%s", buffer); + break; + case MSG_INFO: + LOG_INF("%s", buffer); + break; + case MSG_DEBUG: + case MSG_MSGDUMP: + case MSG_EXCESSIVE: + printf("%s\n", buffer); + break; + default: + break; + } + + forced_memzero(buffer, sizeof(buffer)); +} + +static void _wpa_hexdump(int level, const char *title, const u8 *buf, size_t len, int show) +{ + size_t i; + const char *content; + char *content_buf = NULL; + + if (level < wpa_debug_level) + return; + + if (buf == NULL) { + content = " [NULL]"; + } else if (show) { + content = content_buf = os_malloc(3 * len + 1); + + if (content == NULL) { + wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to allocate message buffer"); + return; + } + + for (i = 0; i < len; i++) { + os_snprintf(&content_buf[i * 3], 4, " %02x", buf[i]); + } + } else { + content = " [REMOVED]"; + } + + wpa_printf(level, "%s - hexdump(len=%lu):%s", title, (unsigned long)len, content); + bin_clear_free(content_buf, 3 * len + 1); +} + +void wpa_hexdump_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, 1); +} + +void wpa_hexdump_key_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); +} + +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, size_t len, int show) +{ + const char *content; + + if (level < wpa_debug_level) { + return; + } + + if (buf == NULL) { + content = " [NULL]"; + } else if (show) { + content = ""; + } else { + content = " [REMOVED]"; + } + + wpa_printf(level, "%s - hexdump_ascii(len=%lu):%s", title, (unsigned long)len, content); + + if (buf == NULL || !show) { + return; + } + + switch (level) { + case MSG_ERROR: + LOG_HEXDUMP_ERR(buf, len, ""); + break; + case MSG_WARNING: + LOG_HEXDUMP_WRN(buf, len, ""); + break; + case MSG_INFO: + LOG_HEXDUMP_INF(buf, len, ""); + break; + case MSG_DEBUG: + case MSG_MSGDUMP: + case MSG_EXCESSIVE: + LOG_HEXDUMP_DBG(buf, len, ""); + break; + default: + break; + } +} + +void wpa_hexdump_ascii_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, 1); +} + +void wpa_hexdump_ascii_key_impl(int level, const char *title, const void *buf, size_t len) +{ + _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); +} + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + +#ifndef CONFIG_NO_WPA_MSG + +static wpa_msg_cb_func wpa_msg_cb = NULL; + +void wpa_msg_register_cb(wpa_msg_cb_func func) +{ + wpa_msg_cb = func; +} + +static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; + +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) +{ + wpa_msg_ifname_cb = func; +} + +void wpa_msg_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + char prefix[130]; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + prefix[0] = '\0'; + if (wpa_msg_ifname_cb) { + const char *ifname = wpa_msg_ifname_cb(ctx); + if (ifname) { + int res = os_snprintf(prefix, sizeof(prefix), "%s: ", ifname); + if (os_snprintf_error(sizeof(prefix), res)) + prefix[0] = '\0'; + } + } + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s%s", prefix, buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_ctrl_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + if (!wpa_msg_cb) + return; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_ctrl_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + if (!wpa_msg_cb) + return; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_global_ctrl: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_no_global_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len); + bin_clear_free(buf, buflen); +} + +void wpa_msg_global_only_impl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer", __func__); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_printf(level, "%s", buf); + if (wpa_msg_cb) + wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len); + os_free(buf); +} + +#endif /* CONFIG_NO_WPA_MSG */ + +#ifndef CONFIG_NO_HOSTAPD_LOGGER + +static hostapd_logger_cb_func hostapd_logger_cb = NULL; + +void hostapd_logger_register_cb(hostapd_logger_cb_func func) +{ + hostapd_logger_cb = func; +} + +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + if (hostapd_logger_cb) + hostapd_logger_cb(ctx, addr, module, level, buf, len); + else if (addr) + wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", MAC2STR(addr), buf); + else + wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); + bin_clear_free(buf, buflen); +} + +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + +const char *debug_level_str(int level) +{ + switch (level) { + case MSG_EXCESSIVE: + return "EXCESSIVE"; + case MSG_MSGDUMP: + return "MSGDUMP"; + case MSG_DEBUG: + return "DEBUG"; + case MSG_INFO: + return "INFO"; + case MSG_WARNING: + return "WARNING"; + case MSG_ERROR: + return "ERROR"; + default: + return "?"; + } +} + +int str_to_debug_level(const char *s) +{ + if (os_strcasecmp(s, "EXCESSIVE") == 0) + return MSG_EXCESSIVE; + if (os_strcasecmp(s, "MSGDUMP") == 0) + return MSG_MSGDUMP; + if (os_strcasecmp(s, "DEBUG") == 0) + return MSG_DEBUG; + if (os_strcasecmp(s, "INFO") == 0) + return MSG_INFO; + if (os_strcasecmp(s, "WARNING") == 0) + return MSG_WARNING; + if (os_strcasecmp(s, "ERROR") == 0) + return MSG_ERROR; + return -1; +} diff --git a/zephyr/src/utils/wpa_debug.h b/zephyr/src/utils/wpa_debug.h new file mode 100644 index 000000000..5843cedf1 --- /dev/null +++ b/zephyr/src/utils/wpa_debug.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* + * wpa_supplicant/hostapd / Debug prints + * Copyright (c) 2002-2013, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + +#include + +#include + +extern int wpa_debug_level; +extern int wpa_debug_show_keys; +extern int wpa_debug_timestamp; + +enum { MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR }; + +/** + * wpa_debug_level_enabled - determine if the given priority level is enabled + * by compile-time configuration. + * + * @level: priority level of a message + */ +#define wpa_debug_level_enabled(level) (CONFIG_WPA_SUPP_DEBUG_LEVEL <= (level)) + +/** + * wpa_debug_cond_run - run the action if the given condition is met + * + * @cond: condition expression + * @action: action to run + */ +#define wpa_debug_cond_run(cond, action) \ + do { \ + if (cond) { \ + action; \ + } \ + } while (0) + + +#ifdef CONFIG_NO_STDOUT_DEBUG + +#define wpa_printf(args...) do { } while (0) +#define wpa_hexdump(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf(l,t,b) do { } while (0) +#define wpa_hexdump_key(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf_key(l,t,b) do { } while (0) +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) +#define wpa_dbg(args...) do { } while (0) + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +/** + * wpa_printf - conditional printf + * + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. + */ +#define wpa_printf(level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_printf_impl(level, fmt, ##__VA_ARGS__)) + +void wpa_printf_impl(int level, const char *fmt, ...) PRINTF_FORMAT(2, 3); + +/** + * wpa_hexdump - conditional hex dump + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump. + */ +#define wpa_hexdump(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), wpa_hexdump_impl(level, title, buf, len)) + +void wpa_hexdump_impl(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, const struct wpabuf *buf) +{ + wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump. This works like wpa_hexdump(), but by default, does + * not include secret keys (passwords, etc.) in debug output. + */ +#define wpa_hexdump_key(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_key_impl(level, title, buf, len)) + +void wpa_hexdump_key_impl(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf_key(int level, const char *title, const struct wpabuf *buf) +{ + wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump with both the hex numbers and ASCII characters (for + * printable range) shown. 16 bytes per line will be shown. + */ +#define wpa_hexdump_ascii(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_ascii_impl(level, title, buf, len)) + +void wpa_hexdump_ascii_impl(int level, const char *title, const void *buf, size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of the message + * @buf: data buffer to be dumped + * @len: length of the buffer + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. The contents of buf is + * printed out as hex dump with both the hex numbers and ASCII characters (for + * printable range) shown. 16 bytes per line will be shown. This works like + * wpa_hexdump_ascii(), but by default, does not include secret keys + * (passwords, etc.) in debug output. + */ +#define wpa_hexdump_ascii_key(level, title, buf, len) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_hexdump_ascii_key_impl(level, title, buf, len)); + +void wpa_hexdump_ascii_key_impl(int level, const char *title, const void *buf, size_t len); + +/* + * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce + * binary size. As such, it should be used with debugging messages that are not + * needed in the control interface while wpa_msg() has to be used for anything + * that needs to shown to control interface monitors. + */ +#define wpa_dbg(args...) wpa_msg(args) + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NO_WPA_MSG + +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_ctrl(args...) do { } while (0) +#define wpa_msg_global(args...) do { } while (0) +#define wpa_msg_global_ctrl(args...) do { } while (0) +#define wpa_msg_no_global(args...) do { } while (0) +#define wpa_msg_global_only(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) +#define wpa_msg_register_ifname_cb(f) do { } while (0) + +#else /* CONFIG_NO_WPA_MSG */ + +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * The output is directed to Zephyr logging subsystem. This function is like + * wpa_printf(), but it also sends the same message to all attached ctrl_iface + * monitors. + */ +#define wpa_msg(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +#define wpa_msg_ctrl(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_ctrl_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_ctrl_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global - Global printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output as a global event, + * i.e., without being specific to an interface. For backwards compatibility, + * an old style event is also delivered on one of the interfaces (the one + * specified by the context data). + */ +#define wpa_msg_global(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only to the + * attached global ctrl_iface monitors. In other words, it can be used for + * frequent events that do not need to be sent to syslog. + */ +#define wpa_msg_global_ctrl(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_ctrl_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_ctrl_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_no_global - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it does not send the output as a global + * event. + */ +#define wpa_msg_no_global(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_no_global_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_no_global_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_global_only - Conditional printf for ctrl_iface monitors + * + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only as a + * global event. + */ +#define wpa_msg_global_only(ctx, level, fmt, ...) \ + wpa_debug_cond_run(wpa_debug_level_enabled(level), \ + wpa_msg_global_only_impl(ctx, level, fmt, ##__VA_ARGS__)) + +void wpa_msg_global_only_impl(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +enum wpa_msg_type { + WPA_MSG_PER_INTERFACE, + WPA_MSG_GLOBAL, + WPA_MSG_NO_GLOBAL, + WPA_MSG_ONLY_GLOBAL, +}; + +typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, const char *txt, + size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); + +typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); + +#endif /* CONFIG_NO_WPA_MSG */ + + +#ifdef CONFIG_NO_HOSTAPD_LOGGER + +#define hostapd_logger(args...) do { } while (0) +#define hostapd_logger_register_cb(f) do { } while (0) + +#else /* CONFIG_NO_HOSTAPD_LOGGER */ + +#define HOSTAPD_MODULE_IEEE80211 0x00000001 +#define HOSTAPD_MODULE_IEEE8021X 0x00000002 +#define HOSTAPD_MODULE_RADIUS 0x00000004 +#define HOSTAPD_MODULE_WPA 0x00000008 +#define HOSTAPD_MODULE_DRIVER 0x00000010 +#define HOSTAPD_MODULE_MLME 0x00000040 + +enum hostapd_logger_level { + HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, + HOSTAPD_LEVEL_DEBUG = 1, + HOSTAPD_LEVEL_INFO = 2, + HOSTAPD_LEVEL_NOTICE = 3, + HOSTAPD_LEVEL_WARNING = 4 +}; + +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, const char *fmt, ...) + PRINTF_FORMAT(5, 6); + +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, unsigned int module, int level, + const char *txt, size_t len); + +/** + * hostapd_logger_register_cb - Register callback function for hostapd_logger() + * @func: Callback function (NULL to unregister) + */ +void hostapd_logger_register_cb(hostapd_logger_cb_func func); + +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + + +/* CONFIG_DEBUG_FILE is not supported by Zephyr */ + +static inline int wpa_debug_open_file(const char *path) { return 0; } +static inline int wpa_debug_reopen_file(void) { return 0; } +static inline void wpa_debug_close_file(void) {} +static inline void wpa_debug_setup_stdout(void) {} + + +/* CONFIG_DEBUG_SYSLOG is not supported by Zephyr */ + +static inline void wpa_debug_open_syslog(void) {} +static inline void wpa_debug_close_syslog(void) {} + + +/* CONFIG_DEBUG_LINUX_TRACING is not supported by Zephyr */ + +static inline int wpa_debug_open_linux_tracing(void) { return 0; } +static inline void wpa_debug_close_linux_tracing(void) {} + + +#ifdef EAPOL_TEST +#define WPA_ASSERT __ASSERT +#else +#define WPA_ASSERT(a) do {} while (0) +#endif + + +const char * debug_level_str(int level); +int str_to_debug_level(const char *s); + +#endif /* WPA_DEBUG_H */ diff --git a/zephyr/src/wpa_cli.c b/zephyr/src/wpa_cli.c new file mode 100644 index 000000000..3ad1e5d9f --- /dev/null +++ b/zephyr/src/wpa_cli.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* @file + * @brief wpa_cli implementation for Zephyr OS + */ + +#include +#include +#include + +#include "wpa_cli_zephyr.h" + +static int cmd_wpa_cli(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + ARG_UNUSED(sh); + + if (argc == 1) { + shell_error(sh, "Missing argument"); + return -EINVAL; + } + + /* Remove wpa_cli from the argument list */ + return z_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); +} + +/* Persisting with "wpa_cli" naming for compatibility with Wi-Fi + * certification applications and scripts. + */ +SHELL_CMD_REGISTER(wpa_cli, + NULL, + "wpa_cli commands (only for internal use)", + cmd_wpa_cli);