Commit b5b11bbf authored by Krishna T's avatar Krishna T Committed by Fabio Baltieri
Browse files

wifi_mgmt: Add new API for Wi-Fi status



A new net_mgmt command and event are added for interface status,
depending on the implementation the status can be returned when polled
or an unsolicited event can be send by driver whenever there is a change
in status.

This is planned to be implemented only by upcoming wpa_supplicant,
offload implementation is left for driver developers.

Signed-off-by: default avatarKrishna T <krishna.t@nordicsemi.no>
parent 123fa543
Loading
Loading
Loading
Loading
+191 −0
Original line number Diff line number Diff line
@@ -26,6 +26,26 @@ enum wifi_security_type {
	WIFI_SECURITY_TYPE_UNKNOWN
};

/**
 * wifi_security_txt - Get the security type as a text string
 */
static inline const char *wifi_security_txt(enum wifi_security_type security)
{
	switch (security) {
	case WIFI_SECURITY_TYPE_NONE:
		return "OPEN";
	case WIFI_SECURITY_TYPE_PSK:
		return "WPA2-PSK";
	case WIFI_SECURITY_TYPE_PSK_SHA256:
		return "WPA2-PSK-SHA256";
	case WIFI_SECURITY_TYPE_SAE:
		return "WPA3-SAE";
	case WIFI_SECURITY_TYPE_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

/* Management frame protection (IEEE 802.11w) options */
enum wifi_mfp_options {
	WIFI_MFP_DISABLE = 0,
@@ -37,6 +57,24 @@ enum wifi_mfp_options {
	WIFI_MFP_UNKNOWN
};

/**
 * wifi_mfp_txt - Get the MFP as a text string
 */
static inline const char *wifi_mfp_txt(enum wifi_mfp_options mfp)
{
	switch (mfp) {
	case WIFI_MFP_DISABLE:
		return "Disable";
	case WIFI_MFP_OPTIONAL:
		return "Optional";
	case WIFI_MFP_REQUIRED:
		return "Required";
	case WIFI_MFP_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

enum wifi_frequency_bands {
	WIFI_FREQ_BAND_2_4_GHZ = 0,
	WIFI_FREQ_BAND_5_GHZ,
@@ -47,6 +85,24 @@ enum wifi_frequency_bands {
	WIFI_FREQ_BAND_UNKNOWN
};

/**
 * wifi_mode_txt - Get the interface mode type as a text string
 */
static inline const char *wifi_band_txt(enum wifi_frequency_bands band)
{
	switch (band) {
	case WIFI_FREQ_BAND_2_4_GHZ:
		return "2.4GHz";
	case WIFI_FREQ_BAND_5_GHZ:
		return "5GHz";
	case WIFI_FREQ_BAND_6_GHZ:
		return "6GHz";
	case WIFI_FREQ_BAND_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

#define WIFI_SSID_MAX_LEN 32
#define WIFI_PSK_MAX_LEN 64
#define WIFI_MAC_ADDR_LEN 6
@@ -54,4 +110,139 @@ enum wifi_frequency_bands {
#define WIFI_CHANNEL_MAX 233
#define WIFI_CHANNEL_ANY 255

/* Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc */
enum wifi_iface_state {
	WIFI_STATE_DISCONNECTED = 0,
	WIFI_STATE_INTERFACE_DISABLED,
	WIFI_STATE_INACTIVE,
	WIFI_STATE_SCANNING,
	WIFI_STATE_AUTHENTICATING,
	WIFI_STATE_ASSOCIATING,
	WIFI_STATE_ASSOCIATED,
	WIFI_STATE_4WAY_HANDSHAKE,
	WIFI_STATE_GROUP_HANDSHAKE,
	WIFI_STATE_COMPLETED,

	__WIFI_STATE_AFTER_LAST,
	WIFI_STATE_MAX = __WIFI_STATE_AFTER_LAST - 1,
	WIFI_STATE_UNKNOWN
};

/**
 * wifi_state_txt - Get the connection state name as a text string
 */
static inline const char *wifi_state_txt(enum wifi_iface_state state)
{
	switch (state) {
	case WIFI_STATE_DISCONNECTED:
		return "DISCONNECTED";
	case WIFI_STATE_INACTIVE:
		return "INACTIVE";
	case WIFI_STATE_INTERFACE_DISABLED:
		return "INTERFACE_DISABLED";
	case WIFI_STATE_SCANNING:
		return "SCANNING";
	case WIFI_STATE_AUTHENTICATING:
		return "AUTHENTICATING";
	case WIFI_STATE_ASSOCIATING:
		return "ASSOCIATING";
	case WIFI_STATE_ASSOCIATED:
		return "ASSOCIATED";
	case WIFI_STATE_4WAY_HANDSHAKE:
		return "4WAY_HANDSHAKE";
	case WIFI_STATE_GROUP_HANDSHAKE:
		return "GROUP_HANDSHAKE";
	case WIFI_STATE_COMPLETED:
		return "COMPLETED";
	case WIFI_STATE_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

/* Based on https://w1.fi/wpa_supplicant/devel/structwpa__ssid.html#a625821e2acfc9014f3b3de6e6593ffb7 */
enum wifi_iface_mode {
	WIFI_MODE_INFRA = 0,
	WIFI_MODE_IBSS = 1,
	WIFI_MODE_AP = 2,
	WIFI_MODE_P2P_GO = 3,
	WIFI_MODE_P2P_GROUP_FORMATION = 4,
	WIFI_MODE_MESH = 5,

	__WIFI_MODE_AFTER_LAST,
	WIFI_MODE_MAX = __WIFI_MODE_AFTER_LAST - 1,
	WIFI_MODE_UNKNOWN
};

/**
 * wifi_mode_txt - Get the interface mode type as a text string
 */
static inline const char *wifi_mode_txt(enum wifi_iface_mode mode)
{
	switch (mode) {
	case WIFI_MODE_INFRA:
		return "STATION";
	case WIFI_MODE_IBSS:
		return "ADHOC";
	case WIFI_MODE_AP:
		return "ACCESS POINT";
	case WIFI_MODE_P2P_GO:
		return "P2P GROUP OWNER";
	case WIFI_MODE_P2P_GROUP_FORMATION:
		return "P2P GROUP FORMATION";
	case WIFI_MODE_MESH:
		return "MESH";
	case WIFI_MODE_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

/* As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations */
enum wifi_link_mode {
	WIFI_0 = 0,
	WIFI_1,
	WIFI_2,
	WIFI_3,
	WIFI_4,
	WIFI_5,
	WIFI_6,
	WIFI_6E,
	WIFI_7,

	__WIFI_LINK_MODE_AFTER_LAST,
	WIFI_LINK_MODE_MAX = __WIFI_LINK_MODE_AFTER_LAST - 1,
	WIFI_LINK_MODE_UNKNOWN
};

/**
 * wifi_link_mode_txt - Get the link mode type as a text string
 */
static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode)
{
	switch (link_mode) {
	case WIFI_0:
		return "WIFI 0 (802.11)";
	case WIFI_1:
		return "WIFI 1 (802.11b)";
	case WIFI_2:
		return "WIFI 2 (802.11a)";
	case WIFI_3:
		return "WIFI 3 (802.11g)";
	case WIFI_4:
		return "WIFI 4 (802.11n/HT)";
	case WIFI_5:
		return "WIFI 5 (802.11ac/VHT)";
	case WIFI_6:
		return "WIFI 6 (802.11ax/HE)";
	case WIFI_6E:
		return "WIFI 6E (802.11ax 6GHz/HE)";
	case WIFI_7:
		return "WIFI 7 (802.11be/EHT)";
	case WIFI_LINK_MODE_UNKNOWN:
	default:
		return "UNKNOWN";
	}
}

#endif /* ZEPHYR_INCLUDE_NET_WIFI_H_ */
+27 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ enum net_request_wifi_cmd {
	NET_REQUEST_WIFI_CMD_DISCONNECT,
	NET_REQUEST_WIFI_CMD_AP_ENABLE,
	NET_REQUEST_WIFI_CMD_AP_DISABLE,
	NET_REQUEST_WIFI_CMD_IFACE_STATUS,
};

#define NET_REQUEST_WIFI_SCAN					\
@@ -62,11 +63,17 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_ENABLE);

NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE);

#define NET_REQUEST_WIFI_IFACE_STATUS				\
	(_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_IFACE_STATUS)

NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS);

enum net_event_wifi_cmd {
	NET_EVENT_WIFI_CMD_SCAN_RESULT = 1,
	NET_EVENT_WIFI_CMD_SCAN_DONE,
	NET_EVENT_WIFI_CMD_CONNECT_RESULT,
	NET_EVENT_WIFI_CMD_DISCONNECT_RESULT,
	NET_EVENT_WIFI_CMD_IFACE_STATUS,
};

#define NET_EVENT_WIFI_SCAN_RESULT				\
@@ -81,6 +88,9 @@ enum net_event_wifi_cmd {
#define NET_EVENT_WIFI_DISCONNECT_RESULT			\
	(_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_RESULT)

#define NET_EVENT_WIFI_IFACE_STATUS						\
	(_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_IFACE_STATUS)


/* Each result is provided to the net_mgmt_event_callback
 * via its info attribute (see net_mgmt.h)
@@ -120,6 +130,20 @@ struct wifi_status {
	int status;
};

struct wifi_iface_status {
	int state; /* enum wifi_iface_state */
	unsigned int ssid_len;
	char ssid[WIFI_SSID_MAX_LEN];
	char bssid[WIFI_MAC_ADDR_LEN];
	enum wifi_frequency_bands band;
	unsigned int channel;
	enum wifi_iface_mode iface_mode;
	enum wifi_link_mode link_mode;
	enum wifi_security_type security;
	enum wifi_mfp_options mfp;
	int rssi;
};

#include <zephyr/net/net_if.h>

typedef void (*scan_result_cb_t)(struct net_if *iface, int status,
@@ -149,6 +173,7 @@ struct net_wifi_mgmt_offload {
	int (*ap_enable)(const struct device *dev,
			 struct wifi_connect_req_params *params);
	int (*ap_disable)(const struct device *dev);
	int (*iface_status)(const struct device *dev, struct wifi_iface_status *status);
};

/* Make sure that the network interface API is properly setup inside
@@ -158,7 +183,8 @@ BUILD_ASSERT(offsetof(struct net_wifi_mgmt_offload, wifi_iface) == 0);

void wifi_mgmt_raise_connect_result_event(struct net_if *iface, int status);
void wifi_mgmt_raise_disconnect_result_event(struct net_if *iface, int status);

void wifi_mgmt_raise_iface_status_event(struct net_if *iface,
		struct wifi_iface_status *iface_status);
#ifdef __cplusplus
}
#endif
+35 −0
Original line number Diff line number Diff line
@@ -164,3 +164,38 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface,
}

NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE, wifi_ap_disable);

static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface,
			  void *data, size_t len)
{
	int ret;
	const struct device *dev = net_if_get_device(iface);
	struct net_wifi_mgmt_offload *off_api =
		(struct net_wifi_mgmt_offload *) dev->api;
	struct wifi_iface_status *status = data;

	if (off_api == NULL || off_api->iface_status == NULL) {
		return -ENOTSUP;
	}

	if (!data || len != sizeof(*status)) {
		return -EINVAL;
	}

	ret = off_api->iface_status(dev, status);

	if (ret) {
		return ret;
	}

	return 0;
}
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS, wifi_iface_status);

void wifi_mgmt_raise_iface_status_event(struct net_if *iface,
		struct wifi_iface_status *iface_status)
{
	net_mgmt_event_notify_with_info(NET_EVENT_WIFI_IFACE_STATUS,
					iface, iface_status,
					sizeof(struct wifi_iface_status));
}
+47 −1
Original line number Diff line number Diff line
@@ -266,6 +266,51 @@ static int cmd_wifi_scan(const struct shell *shell, size_t argc, char *argv[])
	return 0;
}

static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[])
{
	struct net_if *iface = net_if_get_default();
	struct wifi_iface_status status = { 0 };

	context.shell = sh;

	if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status,
				sizeof(struct wifi_iface_status))) {
		shell_fprintf(sh, SHELL_WARNING, "Status request failed\n");

		return -ENOEXEC;
	}

	shell_fprintf(sh, SHELL_NORMAL, "Status: successful\n");
	shell_fprintf(sh, SHELL_NORMAL, "==================\n");
	shell_fprintf(sh, SHELL_NORMAL, "State: %s\n", wifi_state_txt(status.state));

	if (status.state >= WIFI_STATE_ASSOCIATED) {
		uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];

		shell_fprintf(sh, SHELL_NORMAL, "Interface Mode: %s\n",
				wifi_mode_txt(status.iface_mode));
		shell_fprintf(sh, SHELL_NORMAL, "Link Mode: %s\n",
				wifi_link_mode_txt(status.link_mode));
		shell_fprintf(sh, SHELL_NORMAL, "SSID: %-32s\n", status.ssid);
		shell_fprintf(sh, SHELL_NORMAL, "BSSID: %s\n",
					  net_sprint_ll_addr_buf(status.bssid,
					  WIFI_MAC_ADDR_LEN, mac_string_buf,
					  sizeof(mac_string_buf))
					 );
		shell_fprintf(sh, SHELL_NORMAL, "Band: %s\n",
				wifi_band_txt(status.band));
		shell_fprintf(sh, SHELL_NORMAL, "Channel: %d\n", status.channel);
		shell_fprintf(sh, SHELL_NORMAL, "Security: %s\n",
				wifi_security_txt(status.security));
		shell_fprintf(sh, SHELL_NORMAL, "MFP: %s\n",
				wifi_mfp_txt(status.mfp));
		shell_fprintf(sh, SHELL_NORMAL, "RSSI: %d\n", status.rssi);
	}


	return 0;
}

static int cmd_wifi_ap_enable(const struct shell *shell, size_t argc,
			      char *argv[])
{
@@ -319,11 +364,12 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands,
	SHELL_CMD(connect, NULL,
		  "\"<SSID>\"\n<channel number (optional), "
		  "0 means all>\n"
		  "<PSK (optional: valid only for secured SSIDs)>",
		  "<PSK (optional: valid only for secured SSIDs)>"
		  cmd_wifi_connect),
	SHELL_CMD(disconnect, NULL, "Disconnect from Wifi AP",
		  cmd_wifi_disconnect),
	SHELL_CMD(scan, NULL, "Scan Wifi AP", cmd_wifi_scan),
	SHELL_CMD(status, NULL, "Status of Wi-Fi interface", cmd_wifi_status),
	SHELL_CMD(ap, &wifi_cmd_ap, "Access Point mode commands", NULL),
	SHELL_SUBCMD_SET_END
);