MCUXpresso_MIMXRT1021xxxxx/components/edgefast_wifi/source/wpl_nxp.c
Yilin Sun 763d32be90
Updated SDK to v2.15.000
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-03-15 22:23:36 +08:00

860 lines
22 KiB
C

/*
* Copyright 2020-2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "wpl.h"
#ifndef WPL_NO_WLAN_INIT
#include "wlan_bt_fw.h"
#endif
#include "wlan.h"
#include "wifi.h"
#include "wm_net.h"
#include <wm_os.h>
#include "dhcp-server.h"
#include <stdio.h>
#include "event_groups.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define MAX_JSON_NETWORK_RECORD_LENGTH 185
#define WPL_SYNC_TIMEOUT_MS portMAX_DELAY
#define UAP_NETWORK_NAME "uap-network"
#define EVENT_BIT(event) (1 << event)
#define WPL_SYNC_INIT_GROUP EVENT_BIT(WLAN_REASON_INITIALIZED) | EVENT_BIT(WLAN_REASON_INITIALIZATION_FAILED)
#define WPL_SYNC_CONNECT_GROUP \
EVENT_BIT(WLAN_REASON_SUCCESS) | EVENT_BIT(WLAN_REASON_CONNECT_FAILED) | \
EVENT_BIT(WLAN_REASON_NETWORK_NOT_FOUND) | EVENT_BIT(WLAN_REASON_NETWORK_AUTH_FAILED) | \
EVENT_BIT(WLAN_REASON_ADDRESS_FAILED)
#define WPL_SYNC_DISCONNECT_GROUP EVENT_BIT(WLAN_REASON_USER_DISCONNECT)
#define WPL_SYNC_UAP_START_GROUP EVENT_BIT(WLAN_REASON_UAP_SUCCESS) | EVENT_BIT(WLAN_REASON_UAP_START_FAILED)
#define WPL_SYNC_UAP_STOP_GROUP EVENT_BIT(WLAN_REASON_UAP_STOPPED) | EVENT_BIT(WLAN_REASON_UAP_STOP_FAILED)
#define EVENT_SCAN_DONE 23
#define WPL_SYNC_SCAN_GROUP EVENT_BIT(EVENT_SCAN_DONE)
typedef enum _wpl_state
{
WPL_NOT_INITIALIZED,
WPL_INITIALIZED,
WPL_STARTED,
} wpl_state_t;
/*******************************************************************************
* Variables
******************************************************************************/
static wpl_state_t s_wplState = WPL_NOT_INITIALIZED;
static bool s_wplStaConnected = false;
static bool s_wplUapActivated = false;
static EventGroupHandle_t s_wplSyncEvent = NULL;
static linkLostCb_t s_linkLostCb = NULL;
static char *ssids_json = NULL;
/*******************************************************************************
* Prototypes
******************************************************************************/
int wlan_event_callback(enum wlan_event_reason reason, void *data);
static int WLP_process_results(unsigned int count);
/*******************************************************************************
* Code
******************************************************************************/
/* Callback Function passed to WLAN Connection Manager. The callback function
* gets called when there are WLAN Events that need to be handled by the
* application.
*/
int wlan_event_callback(enum wlan_event_reason reason, void *data)
{
#ifdef WPL_DEBUG
PRINTF("-------- wlan_event_callback %d --------\r\n", reason);
#endif
if (s_wplState >= WPL_INITIALIZED)
{
xEventGroupSetBits(s_wplSyncEvent, EVENT_BIT(reason));
}
switch (reason)
{
case WLAN_REASON_SUCCESS:
if (s_wplStaConnected)
{
s_linkLostCb(true);
}
break;
case WLAN_REASON_AUTH_SUCCESS:
break;
case WLAN_REASON_CONNECT_FAILED:
case WLAN_REASON_NETWORK_NOT_FOUND:
case WLAN_REASON_NETWORK_AUTH_FAILED:
if (s_wplStaConnected)
{
s_linkLostCb(false);
}
break;
case WLAN_REASON_ADDRESS_SUCCESS:
break;
case WLAN_REASON_ADDRESS_FAILED:
break;
case WLAN_REASON_LINK_LOST:
if (s_wplStaConnected)
{
s_linkLostCb(false);
}
break;
case WLAN_REASON_CHAN_SWITCH:
break;
case WLAN_REASON_WPS_DISCONNECT:
break;
case WLAN_REASON_USER_DISCONNECT:
break;
case WLAN_REASON_INITIALIZED:
break;
case WLAN_REASON_INITIALIZATION_FAILED:
break;
case WLAN_REASON_PS_ENTER:
break;
case WLAN_REASON_PS_EXIT:
break;
case WLAN_REASON_UAP_SUCCESS:
break;
case WLAN_REASON_UAP_CLIENT_ASSOC:
#ifdef WPL_DEBUG
PRINTF("Client => ");
print_mac((const char *)data);
PRINTF("Associated with Soft AP\r\n");
#endif
break;
case WLAN_REASON_UAP_CLIENT_DISSOC:
#ifdef WPL_DEBUG
PRINTF("Client => ");
print_mac((const char *)data);
PRINTF("Dis-Associated from Soft AP\r\n");
#endif
break;
case WLAN_REASON_UAP_START_FAILED:
break;
case WLAN_REASON_UAP_STOP_FAILED:
break;
case WLAN_REASON_UAP_STOPPED:
break;
default:
#ifdef WPL_DEBUG
PRINTF("Unknown Wifi CB Reason %d\r\n", reason);
#endif
break;
}
return WM_SUCCESS;
}
wpl_ret_t WPL_Init(void)
{
wpl_ret_t status = WPLRET_SUCCESS;
if (s_wplState != WPL_NOT_INITIALIZED)
{
status = WPLRET_FAIL;
}
if (status == WPLRET_SUCCESS)
{
if (s_wplSyncEvent == NULL)
{
s_wplSyncEvent = xEventGroupCreate();
}
if (s_wplSyncEvent == NULL)
{
status = WPLRET_FAIL;
}
}
#ifndef WPL_NO_WLAN_INIT
if (status == WPLRET_SUCCESS)
{
const int ret = wlan_init(wlan_fw_bin, wlan_fw_bin_len);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
#endif
if (status == WPLRET_SUCCESS)
{
s_wplState = WPL_INITIALIZED;
}
return status;
}
wpl_ret_t WPL_Start(linkLostCb_t callbackFunction)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
EventBits_t syncBit;
if (s_wplState != WPL_INITIALIZED)
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
xEventGroupClearBits(s_wplSyncEvent, WPL_SYNC_INIT_GROUP);
ret = wlan_start(wlan_event_callback);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
syncBit = xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_INIT_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(WLAN_REASON_INITIALIZED))
{
s_linkLostCb = callbackFunction;
status = WPLRET_SUCCESS;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_INITIALIZATION_FAILED))
{
status = WPLRET_FAIL;
}
else
{
status = WPLRET_TIMEOUT;
}
}
if (status == WPLRET_SUCCESS)
{
s_wplState = WPL_STARTED;
}
return status;
}
wpl_ret_t WPL_Stop(void)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
if (s_wplState != WPL_STARTED)
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
ret = wlan_stop();
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
s_wplState = WPL_INITIALIZED;
}
return status;
}
wpl_ret_t WPL_Start_AP(char *ssid, char *password, int chan)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
enum wlan_security_type security = WLAN_SECURITY_NONE;
EventBits_t syncBit;
struct wlan_network uap_network;
if ((s_wplState != WPL_STARTED) || (s_wplUapActivated != false))
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
if ((strlen(ssid) == 0) || (strlen(ssid) > IEEEtypes_SSID_SIZE))
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
if (strlen(password) == 0)
{
security = WLAN_SECURITY_NONE;
}
else if ((strlen(password) >= WPL_WIFI_PASSWORD_MIN_LEN) && (strlen(password) <= WPL_WIFI_PASSWORD_LENGTH))
{
security = WLAN_SECURITY_WPA2;
}
else
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
wlan_initialize_uap_network(&uap_network);
memcpy(uap_network.ssid, ssid, strlen(ssid));
uap_network.ip.ipv4.address = ipaddr_addr(WPL_WIFI_AP_IP_ADDR);
uap_network.ip.ipv4.gw = ipaddr_addr(WPL_WIFI_AP_IP_ADDR);
uap_network.channel = chan;
uap_network.security.type = security;
uap_network.security.psk_len = strlen(password);
strncpy(uap_network.security.psk, password, strlen(password));
}
if (status == WPLRET_SUCCESS)
{
ret = wlan_add_network(&uap_network);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
xEventGroupClearBits(s_wplSyncEvent, WPL_SYNC_UAP_START_GROUP);
ret = wlan_start_network(uap_network.name);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
else
{
syncBit =
xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_UAP_START_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(WLAN_REASON_UAP_SUCCESS))
{
status = WPLRET_SUCCESS;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_UAP_START_FAILED))
{
status = WPLRET_FAIL;
}
else
{
status = WPLRET_TIMEOUT;
}
}
if (status != WPLRET_SUCCESS)
{
wlan_remove_network(uap_network.name);
}
}
if (status == WPLRET_SUCCESS)
{
ret = dhcp_server_start(net_get_uap_handle());
if (ret != WM_SUCCESS)
{
wlan_stop_network(uap_network.name);
wlan_remove_network(uap_network.name);
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
s_wplUapActivated = true;
}
return status;
}
wpl_ret_t WPL_Stop_AP(void)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
EventBits_t syncBit;
if ((s_wplState != WPL_STARTED) || (s_wplUapActivated != true))
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
dhcp_server_stop();
xEventGroupClearBits(s_wplSyncEvent, WPL_SYNC_UAP_START_GROUP);
ret = wlan_stop_network(UAP_NETWORK_NAME);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
else
{
syncBit =
xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_UAP_STOP_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(WLAN_REASON_UAP_STOPPED))
{
status = WPLRET_SUCCESS;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_UAP_STOP_FAILED))
{
status = WPLRET_FAIL;
}
else
{
status = WPLRET_TIMEOUT;
}
}
}
if (status == WPLRET_SUCCESS)
{
ret = wlan_remove_network(UAP_NETWORK_NAME);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
s_wplUapActivated = false;
}
return status;
}
static int WLP_process_results(unsigned int count)
{
int ret = 0;
struct wlan_scan_result scan_result = {0};
uint32_t ssids_json_len = count * MAX_JSON_NETWORK_RECORD_LENGTH;
/* Add length of "{"networks":[]}" */
ssids_json_len += 15;
ssids_json = pvPortMalloc(ssids_json_len);
if (ssids_json == NULL)
{
PRINTF("[!] Memory allocation failed\r\n");
xEventGroupSetBits(s_wplSyncEvent, EVENT_BIT(EVENT_SCAN_DONE));
return WM_FAIL;
}
/* Start building JSON */
strcpy(ssids_json, "{\"networks\":[");
uint32_t ssids_json_idx = strlen(ssids_json);
for (int i = 0; i < count; i++)
{
wlan_get_scan_result(i, &scan_result);
PRINTF("%s\r\n", scan_result.ssid);
PRINTF(" BSSID : %02X:%02X:%02X:%02X:%02X:%02X\r\n", (unsigned int)scan_result.bssid[0],
(unsigned int)scan_result.bssid[1], (unsigned int)scan_result.bssid[2],
(unsigned int)scan_result.bssid[3], (unsigned int)scan_result.bssid[4],
(unsigned int)scan_result.bssid[5]);
PRINTF(" RSSI : %ddBm\r\n", -(int)scan_result.rssi);
PRINTF(" Channel : %d\r\n", (int)scan_result.channel);
char security[40];
security[0] = '\0';
if (scan_result.wpa2_entp)
{
strcat(security, "WPA2_ENTP ");
}
if (scan_result.wep)
{
strcat(security, "WEP ");
}
if (scan_result.wpa)
{
strcat(security, "WPA ");
}
if (scan_result.wpa2)
{
strcat(security, "WPA2 ");
}
if (scan_result.wpa3_sae)
{
strcat(security, "WPA3_SAE ");
}
if (i != 0)
{
/* Add ',' separator before next entry */
ssids_json[ssids_json_idx++] = ',';
}
ret = snprintf(
ssids_json + ssids_json_idx, ssids_json_len - ssids_json_idx - 1,
"{\"ssid\":\"%s\",\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\"signal\":\"%ddBm\",\"channel\":%d,"
"\"security\":\"%s\"}",
scan_result.ssid, (unsigned int)scan_result.bssid[0], (unsigned int)scan_result.bssid[1],
(unsigned int)scan_result.bssid[2], (unsigned int)scan_result.bssid[3], (unsigned int)scan_result.bssid[4],
(unsigned int)scan_result.bssid[5], -(int)scan_result.rssi, (int)scan_result.channel, security);
if (ret > 0)
{
ssids_json_idx += ret;
}
else
{
PRINTF("[!] JSON creation failed\r\n");
vPortFree(ssids_json);
ssids_json = NULL;
xEventGroupSetBits(s_wplSyncEvent, EVENT_BIT(EVENT_SCAN_DONE));
return WM_FAIL;
}
}
/* End of JSON "]}" */
strcpy(ssids_json + ssids_json_idx, "]}");
xEventGroupSetBits(s_wplSyncEvent, EVENT_BIT(EVENT_SCAN_DONE));
return WM_SUCCESS;
}
char *WPL_Scan(void)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
EventBits_t syncBit;
if (s_wplState != WPL_STARTED)
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
ret = wlan_scan(WLP_process_results);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
syncBit = xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_SCAN_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(EVENT_SCAN_DONE))
{
status = WPLRET_SUCCESS;
}
else
{
status = WPLRET_TIMEOUT;
}
}
if (status == WPLRET_SUCCESS)
{
return ssids_json;
}
return NULL;
}
wpl_ret_t WPL_AddNetworkWithSecurity(char *ssid, char *password, char *label, wpl_security_t security)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
struct wlan_network sta_network;
memset(&sta_network, 0, sizeof(struct wlan_network));
if (s_wplState != WPL_STARTED)
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
if ((strlen(label) == 0) || (strlen(label) > (WLAN_NETWORK_NAME_MAX_LENGTH - 1)))
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
if ((strlen(ssid) == 0) || (strlen(ssid) > IEEEtypes_SSID_SIZE))
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
size_t password_len = strlen(password);
if (password_len == 0)
{
sta_network.security.type = WLAN_SECURITY_NONE;
}
else if ((password_len >= WPL_WIFI_PASSWORD_MIN_LEN) && (password_len <= WPL_WIFI_PASSWORD_LENGTH))
{
switch (security)
{
case WPL_SECURITY_WILDCARD:
sta_network.security.type = WLAN_SECURITY_WILDCARD;
sta_network.security.mfpc = true;
sta_network.security.mfpr = true;
sta_network.security.password_len = password_len;
strncpy(sta_network.security.password, password, password_len);
sta_network.security.psk_len = password_len;
strncpy(sta_network.security.psk, password, password_len);
break;
case WPL_SECURITY_WPA3_SAE:
sta_network.security.type = WLAN_SECURITY_WPA3_SAE;
sta_network.security.mfpc = true;
sta_network.security.mfpr = true;
sta_network.security.password_len = strlen(password);
strncpy(sta_network.security.password, password, strlen(password));
break;
default:
PRINTF("[!] Unimplemented security type (%d)\r\n", security);
status = WPLRET_BAD_PARAM;
break;
}
}
else
{
status = WPLRET_BAD_PARAM;
}
}
strcpy(sta_network.name, label);
strcpy(sta_network.ssid, ssid);
sta_network.ip.ipv4.addr_type = ADDR_TYPE_DHCP;
sta_network.ssid_specific = 1;
if (status == WPLRET_SUCCESS)
{
ret = wlan_add_network(&sta_network);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
return status;
}
wpl_ret_t WPL_AddNetwork(char *ssid, char *password, char *label)
{
return WPL_AddNetworkWithSecurity(ssid, password, label, WPL_SECURITY_WILDCARD);
}
wpl_ret_t WPL_RemoveNetwork(char *label)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
if (s_wplState != WPL_STARTED)
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
if ((strlen(label) == 0) || (strlen(label) > (WLAN_NETWORK_NAME_MAX_LENGTH - 1)))
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
ret = wlan_remove_network(label);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
return status;
}
wpl_ret_t WPL_Join(char *label)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
EventBits_t syncBit;
if ((s_wplState != WPL_STARTED) || (s_wplStaConnected != false))
{
status = WPLRET_NOT_READY;
}
if (status == WPLRET_SUCCESS)
{
if ((strlen(label) == 0) || (strlen(label) > (WLAN_NETWORK_NAME_MAX_LENGTH - 1)))
{
status = WPLRET_BAD_PARAM;
}
}
if (status == WPLRET_SUCCESS)
{
xEventGroupClearBits(s_wplSyncEvent, WPL_SYNC_CONNECT_GROUP);
ret = wlan_connect(label);
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
syncBit = xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_CONNECT_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(WLAN_REASON_SUCCESS))
{
status = WPLRET_SUCCESS;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_CONNECT_FAILED))
{
status = WPLRET_FAIL;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_NETWORK_NOT_FOUND))
{
status = WPLRET_NOT_FOUND;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_NETWORK_AUTH_FAILED))
{
status = WPLRET_AUTH_FAILED;
}
else if (syncBit & EVENT_BIT(WLAN_REASON_ADDRESS_FAILED))
{
status = WPLRET_ADDR_FAILED;
}
else
{
status = WPLRET_TIMEOUT;
}
if (status != WPLRET_SUCCESS)
{
/* Abort the next connection attempt */
WPL_Leave();
}
}
if (status == WPLRET_SUCCESS)
{
s_wplStaConnected = true;
}
return status;
}
wpl_ret_t WPL_Leave(void)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
EventBits_t syncBit;
if (s_wplState != WPL_STARTED)
{
status = WPLRET_NOT_READY;
}
enum wlan_connection_state connection_state = WLAN_DISCONNECTED;
wlan_get_connection_state(&connection_state);
if (connection_state == WLAN_DISCONNECTED)
{
s_wplStaConnected = false;
return WPLRET_SUCCESS;
}
if (status == WPLRET_SUCCESS)
{
xEventGroupClearBits(s_wplSyncEvent, WPL_SYNC_DISCONNECT_GROUP);
ret = wlan_disconnect();
if (ret != WM_SUCCESS)
{
status = WPLRET_FAIL;
}
}
if (status == WPLRET_SUCCESS)
{
syncBit = xEventGroupWaitBits(s_wplSyncEvent, WPL_SYNC_DISCONNECT_GROUP, pdTRUE, pdFALSE, WPL_SYNC_TIMEOUT_MS);
if (syncBit & EVENT_BIT(WLAN_REASON_USER_DISCONNECT))
{
status = WPLRET_SUCCESS;
}
else
{
status = WPLRET_TIMEOUT;
}
}
s_wplStaConnected = false;
return status;
}
wpl_ret_t WPL_GetIP(char *ip, int client)
{
wpl_ret_t status = WPLRET_SUCCESS;
int ret;
struct wlan_ip_config addr;
if (ip == NULL)
{
status = WPLRET_FAIL;
}
if (status == WPLRET_SUCCESS)
{
if (client)
{
ret = wlan_get_address(&addr);
}
else
{
ret = wlan_get_uap_address(&addr);
}
if (ret == WM_SUCCESS)
{
net_inet_ntoa(addr.ipv4.address, ip);
}
else
{
status = WPLRET_FAIL;
}
}
return status;
}