Files
SDK_GD32W51x/NSPE/WIFI_IOT/wifi/wifi_management.c
2023-05-18 18:53:00 +08:00

862 lines
30 KiB
C

/*!
\file wifi_management.c
\brief WiFi management for GD32W51x WiFi SDK
\version 2021-10-30, V1.0.0, firmware for GD32W51x
*/
/*
Copyright (c) 2021, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
/*============================ INCLUDES ======================================*/
#include "app_cfg.h"
#include "state_machine.h"
#include "bsp_inc.h"
#include "wlan_intf.h"
#include "wifi_netlink.h"
#include "lwip/netifapi.h"
#include "debug_print.h"
#include "dhcpd.h"
#define EXTERN
#include "wifi_management.h"
#ifdef CONFIG_WIFI_MANAGEMENT_TASK
/*============================ MACROS ========================================*/
#define STATE_MACHINE_DATA struct wifi_management_sm_data
#define STATE_MACHINE_DEBUG_PREFIX "WIFI_MGMT"
/*============================ MACRO FUNCTIONS ===============================*/
#define GET_SM_STATE(machine) \
sm->machine ## _state
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
os_mutex_t hw_pka_lock;
os_mutex_t hw_cryp_lock;
os_mutex_t hw_hash_lock;
os_sema_t mgmt_task_exit_sema = NULL;
/*============================ LOCAL VARIABLES ===============================*/
static int8_t candidate_rssi_avg;
static int8_t candidate_rssi;
static uint8_t fast_scan;
static uint8_t throttle_scan;
static uint8_t ap_dhcpd_started = 0;
/*============================ PROTOTYPES ====================================*/
static void wifi_mgmt_dhcp_polling(void *eloop_data, void *user_ctx);
static void wifi_mgmt_link_status_polling(void *eloop_data, void *user_ctx);
static void wifi_mgmt_connect_retry(void *eloop_data, void *user_ctx);
#ifdef CONFIG_RF_TEST_SUPPORT
#include "cmd_rf_test.h"
#endif
/*============================ IMPLEMENTATION ================================*/
/***************************** WiFi Management State Machine ******************/
SM_STATE(MAINTAIN_CONNECTION, IDLE)
{
SM_ENTRY(MAINTAIN_CONNECTION, IDLE);
wifi_netif_stop_dhcp();
eloop_timeout_cancel(wifi_mgmt_dhcp_polling, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
eloop_timeout_cancel(wifi_mgmt_link_status_polling, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
if (p_wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX ": disconnect with ap %s\r\n",
p_wifi_netlink->connected_ap_info.ssid.ssid);
wifi_netlink_disconnect_req();
}
sys_memset(&p_wifi_netlink->connected_ap_info, 0, sizeof(struct wifi_connect_result));
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
}
SM_STATE(MAINTAIN_CONNECTION, SCAN)
{
struct wifi_ssid_config *connect_info = &(p_wifi_netlink->connect_info);
struct wifi_scan_req scan_req;
SM_ENTRY(MAINTAIN_CONNECTION, SCAN);
wifi_netif_stop_dhcp();
eloop_timeout_cancel(wifi_mgmt_dhcp_polling, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
eloop_timeout_cancel(wifi_mgmt_link_status_polling, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
sys_memcpy(&scan_req.ssid.ssid, connect_info->ssid.ssid, connect_info->ssid.ssid_len);
scan_req.ssid.ssid_len = connect_info->ssid.ssid_len;
if (wifi_ops_entry.wifi_scan_proc_func(&scan_req) == _FALSE) {
wifi_sm_printf(WIFI_SM_ERROR, STATE_MACHINE_DEBUG_PREFIX": start scan failed\r\n");
eloop_event_send(WIFI_MGMT_EVENT_SCAN_FAIL);
}
}
SM_STATE(MAINTAIN_CONNECTION, CONNECT)
{
struct wifi_ssid_config *connect_info = &(p_wifi_netlink->connect_info);
SM_ENTRY(MAINTAIN_CONNECTION, CONNECT);
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKING;
if (wifi_ops_entry.wifi_connect_req_func(connect_info) == _FALSE) {
wifi_sm_printf(WIFI_SM_ERROR, STATE_MACHINE_DEBUG_PREFIX": start connecting failed\r\n");
}
}
SM_STATE(MAINTAIN_CONNECTION, DHCP)
{
SM_ENTRY(MAINTAIN_CONNECTION, DHCP);
sm->dhcp_polling_count = WIFI_MGMT_DHCP_POLLING_LIMIT;
wifi_netif_start_dhcp();
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX ": start polling DHCP status\r\n");
eloop_timeout_register(WIFI_MGMT_DHCP_POLLING_INTERVAL, wifi_mgmt_dhcp_polling, sm, NULL);
}
SM_STATE(MAINTAIN_CONNECTION, CONNECTED)
{
SM_ENTRY(MAINTAIN_CONNECTION, CONNECTED);
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX ": start polling link status\r\n");
candidate_rssi_avg = 0;
fast_scan = WIFI_MGMT_START_SCAN_FAST_INTERVAL;
throttle_scan = WIFI_MGMT_START_SCAN_THROTTLE_INTERVAL;
if (wifi_netlink_auto_conn_get()) {
wifi_netlink_joined_ap_store();
}
eloop_timeout_register(WIFI_MGMT_LINK_POLLING_INTERVAL, wifi_mgmt_link_status_polling, sm, NULL);
}
SM_STEP(MAINTAIN_CONNECTION)
{
if (!sm->init || sm->event == WIFI_MGMT_EVENT_INIT) {
sys_memset(sm, 0, sizeof(*sm));
sm->init = TRUE;
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
sm->retry_interval = WIFI_MGMT_ROAMING_RETRY_INTERVAL;
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
} else if (GET_SM_STATE(MAINTAIN_CONNECTION) == MAINTAIN_CONNECTION_IDLE) {
switch (sm->event) {
case WIFI_MGMT_EVENT_CONNECT_CMD:
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
eloop_timeout_cancel(wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_AUTO_CONNECT:
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_DISCONNECT_CMD:
case WIFI_MGMT_EVENT_SCAN_DONE:
case WIFI_MGMT_EVENT_SCAN_FAIL:
case WIFI_MGMT_EVENT_CONNECT_FAIL:
break;
// case WIFI_MGMT_EVENT_CONNECT_SUCCESS:
// case WIFI_MGMT_EVENT_DISCONN:
// case WIFI_MGMT_EVENT_DHCP_SUCCESS:
// case WIFI_MGMT_EVENT_DHCP_FAIL:
default:
goto unexpected_events;
}
} else if (GET_SM_STATE(MAINTAIN_CONNECTION) == MAINTAIN_CONNECTION_SCAN) {
switch (sm->event) {
case WIFI_MGMT_EVENT_CONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
eloop_timeout_cancel(wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_DISCONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
break;
case WIFI_MGMT_EVENT_SCAN_DONE:
SM_ENTER(MAINTAIN_CONNECTION, CONNECT);
break;
case WIFI_MGMT_EVENT_SCAN_FAIL:
if (sm->retry_count--) {
eloop_timeout_register(sm->retry_interval, wifi_mgmt_connect_retry, sm, NULL);
} else {
wifi_sm_printf(WIFI_SM_WARNING, STATE_MACHINE_DEBUG_PREFIX ": all connecting retries failed\r\n");
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
}
break;
// case WIFI_MGMT_EVENT_CONNECT_SUCCESS:
// case WIFI_MGMT_EVENT_CONNECT_FAIL:
// case WIFI_MGMT_EVENT_DISCONNECT:
// case WIFI_MGMT_EVENT_DHCP_SUCCESS:
// case WIFI_MGMT_EVENT_DHCP_FAIL:
default:
goto unexpected_events;
}
} else if (GET_SM_STATE(MAINTAIN_CONNECTION) == MAINTAIN_CONNECTION_CONNECT) {
switch (sm->event) {
case WIFI_MGMT_EVENT_CONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
eloop_timeout_cancel(wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_SCAN_DONE:
case WIFI_MGMT_EVENT_SCAN_FAIL:
break;
case WIFI_MGMT_EVENT_DISCONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
break;
case WIFI_MGMT_EVENT_CONNECT_SUCCESS:
SM_ENTER(MAINTAIN_CONNECTION, DHCP);
break;
case WIFI_MGMT_EVENT_CONNECT_FAIL:
case WIFI_MGMT_EVENT_DISCONNECT:
if (sm->retry_count--) {
eloop_timeout_register(sm->retry_interval, wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
} else {
wifi_sm_printf(WIFI_SM_WARNING, STATE_MACHINE_DEBUG_PREFIX ": all connecting retries failed\r\n");
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
}
break;
// case WIFI_MGMT_EVENT_DHCP_SUCCESS:
// case WIFI_MGMT_EVENT_DHCP_FAIL:
default:
goto unexpected_events;
}
} else if (GET_SM_STATE(MAINTAIN_CONNECTION) == MAINTAIN_CONNECTION_DHCP) {
switch (sm->event) {
case WIFI_MGMT_EVENT_CONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
eloop_timeout_cancel(wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_SCAN_DONE:
case WIFI_MGMT_EVENT_SCAN_FAIL:
break;
case WIFI_MGMT_EVENT_DISCONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
break;
case WIFI_MGMT_EVENT_DHCP_SUCCESS:
SM_ENTER(MAINTAIN_CONNECTION, CONNECTED);
eloop_timeout_cancel(wifi_mgmt_connect_retry, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
break;
case WIFI_MGMT_EVENT_DHCP_FAIL:
wifi_netlink_disconnect_req();
case WIFI_MGMT_EVENT_CONNECT_FAIL:
case WIFI_MGMT_EVENT_DISCONNECT:
if (sm->retry_count--) {
eloop_timeout_register(sm->retry_interval, wifi_mgmt_connect_retry, sm, NULL);
} else {
wifi_sm_printf(WIFI_SM_WARNING, STATE_MACHINE_DEBUG_PREFIX ": all connecting retries failed\r\n");
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
}
break;
// case WIFI_MGMT_EVENT_CONNECT_SUCCESS:
default:
goto unexpected_events;
}
} else if (GET_SM_STATE(MAINTAIN_CONNECTION) == MAINTAIN_CONNECTION_CONNECTED) {
switch (sm->event) {
case WIFI_MGMT_EVENT_CONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
eloop_timeout_cancel(wifi_mgmt_connect_retry, sm, NULL);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
break;
case WIFI_MGMT_EVENT_DISCONNECT_CMD:
SM_ENTER(MAINTAIN_CONNECTION, IDLE);
break;
case WIFI_MGMT_EVENT_SCAN_DONE:
case WIFI_MGMT_EVENT_SCAN_FAIL:
break;
case WIFI_MGMT_EVENT_DISCONNECT:
if (WIFI_MGMT_UNLIMITED_RETRY())
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_UNLIMITED;
else
sm->retry_count = WIFI_MGMT_ROAMING_RETRY_LIMIT - 1;
if (sm->reason == WIFI_MESSAGE_INDICATE_DISCON_AP_CHANGED ||
sm->reason == WIFI_MESSAGE_INDICATE_DISCON_NO_BEACON ||
sm->reason == WIFI_MESSAGE_INDICATE_DISCON_RECV_DEAUTH)
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
else
SM_ENTER(MAINTAIN_CONNECTION, CONNECT);
break;
// case WIFI_MGMT_EVENT_CONNECT_SUCCESS:
// case WIFI_MGMT_EVENT_CONNECT_FAIL:
// case WIFI_MGMT_EVENT_DHCP_SUCCESS:
// case WIFI_MGMT_EVENT_DHCP_FAIL:
default:
goto unexpected_events;
}
}
if (!sm->changed) {
wifi_sm_printf(WIFI_SM_DEBUG, STATE_MACHINE_DEBUG_PREFIX
": stay in the state %u upon the event (%u:%u)\r\n",
GET_SM_STATE(MAINTAIN_CONNECTION), sm->event, sm->reason);
}
sm->changed = FALSE;
return;
unexpected_events:
wifi_sm_printf(WIFI_SM_WARNING, STATE_MACHINE_DEBUG_PREFIX
": unexpected event (%u:%u) in the state %u\r\n",
sm->event, sm->reason, GET_SM_STATE(MAINTAIN_CONNECTION));
}
/*!
\brief wifi management run state machine
\param[in] eloop_data: pointer to the eloop data
\param[in] user_ctx: pointer to the user parameters
\param[out] none
\retval none
*/
void wifi_mgmt_cb_run_state_machine(void *eloop_data, void *user_ctx)
{
wifi_management_sm_data_t *sm = eloop_data;
eloop_message_t *message = (eloop_message_t *)user_ctx;
if (message->event < WIFI_MGMT_EVENT_INIT)
return;
sm->event = (wifi_management_event_t)message->event;
sm->reason = message->reason;
wifi_sm_printf(WIFI_SM_DEBUG, STATE_MACHINE_DEBUG_PREFIX
": received message: (%u:%u:%u)\r\n",
sm->MAINTAIN_CONNECTION_state, message->event, message->reason);
SM_STEP_RUN(MAINTAIN_CONNECTION);
}
/************************ WiFi Management Callbacks ***************************/
/************************ WiFi Management Timeouts ****************************/
/*!
\brief wifi management dhcp polling
\param[in] eloop_data: pointer to the eloop data
\param[in] user_ctx: pointer to the user parameters
\param[out] none
\retval none
*/
static void wifi_mgmt_dhcp_polling(void *eloop_data, void *user_ctx)
{
wifi_management_sm_data_t *sm = eloop_data;
if (wifi_netif_is_ip_got()) {
wifi_netlink_ipaddr_set((uint8_t *)wifi_netif_get_ip());
//DEBUGPRINT("DHCP: IP configured: "IP_FMT"\r\n", IP_ARG(wifi_netif_get_ip()->addr));
eloop_event_send(WIFI_MGMT_EVENT_DHCP_SUCCESS);
if (p_wifi_netlink->conn_blocked) {
sys_sema_up(&p_wifi_netlink->block_sema);
p_wifi_netlink->conn_blocked = FALSE;
}
return;
}
if (--sm->dhcp_polling_count) {
if ((sm->dhcp_polling_count & 0xF) == 0) {
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX ": waiting for DHCP(%d)...\r\n", sm->dhcp_polling_count);
}
eloop_timeout_register(WIFI_MGMT_DHCP_POLLING_INTERVAL, wifi_mgmt_dhcp_polling, sm, NULL);
} else {
DEBUGPRINT("DHCP: IP request timeouted!\r\n");
wifi_netif_stop_dhcp();
eloop_event_send(WIFI_MGMT_EVENT_DHCP_FAIL);
}
}
/*!
\brief find candidate ap
\param[in] eloscan_itemop_data: pointer to the wifi_scan_info struction
\param[out] none
\retval none
*/
static void find_candidate_ap(struct wifi_scan_info *scan_item)
{
if (!sys_memcmp(scan_item->ssid.ssid,
p_wifi_netlink->connected_ap_info.ssid.ssid,
p_wifi_netlink->connected_ap_info.ssid.ssid_len) &&
sys_memcmp(scan_item->bssid_info.bssid,
p_wifi_netlink->connected_ap_info.bssid_info.bssid,
sizeof(scan_item->bssid_info.bssid))) {
candidate_rssi_avg = (candidate_rssi_avg * 3 + scan_item->rssi) >> 2;
candidate_rssi = scan_item->rssi;
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX
": found a candidate AP "MAC_FMT", rssi %d, avg rssi %d\r\n",
MAC_ARG(scan_item->bssid_info.bssid), scan_item->rssi, candidate_rssi_avg);
}
}
/*!
\brief wifi management scan done
\param[in] eloop_data: pointer to the eloop data
\param[in] user_ctx: pointer to the user parameters
\param[out] none
\retval none
*/
void wifi_mgmt_cb_scan_done(void *eloop_data, void *user_ctx)
{
int rssi;
candidate_rssi = 0; /* rssi won't be larger than or equal to 0 */
wifi_netlink_scan_list_get(find_candidate_ap);
if (!candidate_rssi)
goto exit;
fast_scan = WIFI_MGMT_START_SCAN_FAST_INTERVAL;
rssi = wifi_netlink_bss_rssi_get();
if (rssi < WIFI_MGMT_TRIGGER_ROAMING_RSSI_THRESHOLD &&
(rssi + WIFI_MGMT_START_ROAMING_RSSI_THRESHOLD_1 < candidate_rssi_avg ||
rssi + WIFI_MGMT_START_ROAMING_RSSI_THRESHOLD_2 < candidate_rssi)) {
wifi_sm_printf(WIFI_SM_NOTICE, STATE_MACHINE_DEBUG_PREFIX ": try roaming to a better AP\r\n");
eloop_event_send(WIFI_MGMT_EVENT_CONNECT_CMD);
}
exit:
eloop_event_unregister(WIFI_MGMT_EVENT_SCAN_DONE);
}
/*!
\brief wifi management link status polling
\param[in] eloop_data: pointer to the eloop data
\param[in] user_ctx: pointer to the user parameters
\param[out] none
\retval none
*/
static void wifi_mgmt_link_status_polling(void *eloop_data, void *user_ctx)
{
wifi_management_sm_data_t *sm = eloop_data;
int rssi;
wifi_sm_printf(WIFI_SM_INFO, STATE_MACHINE_DEBUG_PREFIX ": polling link status\r\n");
rssi = wifi_netlink_bss_rssi_get();
if (rssi < WIFI_MGMT_TRIGGER_ROAMING_RSSI_THRESHOLD && (fast_scan || --throttle_scan == 0)) {
if (candidate_rssi_avg == 0)
candidate_rssi_avg = rssi;
eloop_event_register(WIFI_MGMT_EVENT_SCAN_DONE, wifi_mgmt_cb_scan_done, NULL, NULL);
if (wifi_management_scan(FALSE) != 0) {
eloop_event_unregister(WIFI_MGMT_EVENT_SCAN_DONE);
}
if (fast_scan)
fast_scan--;
if (throttle_scan == 0)
throttle_scan = WIFI_MGMT_START_SCAN_THROTTLE_INTERVAL;
}
eloop_timeout_register(WIFI_MGMT_LINK_POLLING_INTERVAL, wifi_mgmt_link_status_polling, sm, NULL);
}
/*!
\brief wifi management connect retry
\param[in] eloop_data: pointer to the eloop data
\param[in] user_ctx: pointer to the user parameters
\param[out] none
\retval none
*/
static void wifi_mgmt_connect_retry(void *eloop_data, void *user_ctx)
{
wifi_management_sm_data_t *sm = eloop_data;
wifi_sm_printf(WIFI_SM_NOTICE, STATE_MACHINE_DEBUG_PREFIX ": retry to connect, remaining times 0x%x\r\n",
sm->retry_count);
SM_ENTER(MAINTAIN_CONNECTION, SCAN);
}
/************************ WiFi Management Interfaces **************************/
/*!
\brief wifi management connect
\param[in] ssid: pointer to the SSID
\param[in] password: pointer to the password
\param[in] blocked: whether block
\param[out] none
\retval function run status
\arg -1: link is ongoing
\arg -2: SSID empty
\arg -3: SSID's length error
\arg -4: password's length error
\arg OS_OK: run success
*/
int wifi_management_connect(uint8_t *ssid, uint8_t *password, uint8_t blocked)
{
struct wifi_ssid_config *connect_info = &p_wifi_netlink->connect_info;
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_LINKING) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX": Link is ongoing... Please wait for a minute.\r\n");
return -1;
}
if (ssid == NULL) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX": SSID empty!\r\n");
return -2;
}
if (strlen((const char *)ssid) > WIFI_SSID_MAX_LEN) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX": SSID's length should be less than %u\r\n", WIFI_SSID_MAX_LEN);
return -3;
}
if (password &&
((strlen((const char *)password) > WPA_MAX_PSK_LEN) ||
((strlen((const char *)password) < WPA_MIN_PSK_LEN)))) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX": password's length should be between %d and %d inclusively\r\n",
WPA_MIN_PSK_LEN, WPA_MAX_PSK_LEN);
return -4;
}
connect_info->ssid.ssid_len = strlen((const char *)ssid);
sys_memcpy(connect_info->ssid.ssid, ssid, connect_info->ssid.ssid_len + 1);
if (password) {
sys_memcpy(connect_info->passwd, password, strlen((const char *)password) + 1);
} else {
sys_memset(connect_info->passwd, 0, (WPA_MAX_PSK_LEN + 1));
}
if (blocked)
p_wifi_netlink->conn_blocked = TRUE;
return eloop_event_send(WIFI_MGMT_EVENT_CONNECT_CMD);
}
/*!
\brief wifi management disconnect
\param[in] none
\param[out] none
\retval function run status
-1: error happen
OS_OK: run success
*/
int wifi_management_disconnect()
{
return eloop_event_send(WIFI_MGMT_EVENT_DISCONNECT_CMD);
}
/*!
\brief wifi management scan
\param[in] blocked: whether block
\param[out] none
\retval function run status
-1: error happen
0: run success
*/
int wifi_management_scan(uint8_t blocked)
{
wifi_management_sm_data_t *sm = &wifi_sm_data;
if (GET_SM_STATE(MAINTAIN_CONNECTION) != MAINTAIN_CONNECTION_CONNECTED &&
GET_SM_STATE(MAINTAIN_CONNECTION) != MAINTAIN_CONNECTION_IDLE) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX
": ignore scan in the connecting process (%d)\r\n", GET_SM_STATE(MAINTAIN_CONNECTION));
return -1;
}
if (wifi_netlink_scan_set() != 1) {
DEBUGPRINT(STATE_MACHINE_DEBUG_PREFIX ": start scan failed\r\n");
}
if (blocked)
p_wifi_netlink->scan_blocked = TRUE;
return 0;
}
/*!
\brief wifi management block wait
\param[in] none
\param[out] none
\retval 0: run success
*/
int wifi_management_block_wait(void)
{
if ((p_wifi_netlink->scan_blocked == TRUE) || (p_wifi_netlink->conn_blocked == TRUE))
sys_sema_down(&p_wifi_netlink->block_sema, 20000);
return 0;
}
/*!
\brief wifi management forward netlink message
\param[in] message: wifi message type, refer to WIFI_MESSAGE_TYPE_E
\param[out] none
\retval function run status
OS_ERROR: error happen
OS_OK: run success
*/
int wifi_management_forward_netlink_message(WIFI_MESSAGE_TYPE_E message)
{
eloop_message_t wifi_mgmt_message;
wifi_management_event_t event;
switch (message) {
case WIFI_MESSAGE_NOTIFY_SCAN_RESULT_SUCC:
event = WIFI_MGMT_EVENT_SCAN_DONE;
if (p_wifi_netlink->scan_blocked) {
sys_sema_up(&p_wifi_netlink->block_sema);
p_wifi_netlink->scan_blocked = FALSE;
}
break;
case WIFI_MESSAGE_NOTIFY_SCAN_RESULT_FAIL:
event = WIFI_MGMT_EVENT_SCAN_FAIL;
if (p_wifi_netlink->scan_blocked) {
sys_sema_up(&p_wifi_netlink->block_sema);
p_wifi_netlink->scan_blocked = FALSE;
}
break;
case WIFI_MESSAGE_INDICATE_CONN_SUCCESS:
event = WIFI_MGMT_EVENT_CONNECT_SUCCESS;
break;
case WIFI_MESSAGE_INDICATE_CONN_NO_AP:
case WIFI_MESSAGE_INDICATE_CONN_ASSOC_FAIL:
case WIFI_MESSAGE_INDICATE_CONN_HANDSHAKE_FAIL:
case WIFI_MESSAGE_INDICATE_CONN_FAIL:
event = WIFI_MGMT_EVENT_CONNECT_FAIL;
if (p_wifi_netlink->conn_blocked) {
sys_sema_up(&p_wifi_netlink->block_sema);
p_wifi_netlink->conn_blocked = FALSE;
}
break;
case WIFI_MESSAGE_INDICATE_DISCON_REKEY_FAIL:
case WIFI_MESSAGE_INDICATE_DISCON_MIC_FAIL:
case WIFI_MESSAGE_INDICATE_DISCON_RECV_DEAUTH:
case WIFI_MESSAGE_INDICATE_DISCON_NO_BEACON:
case WIFI_MESSAGE_INDICATE_DISCON_AP_CHANGED:
case WIFI_MESSAGE_INDICATE_DISCON_FROM_UI:
case WIFI_MESSAGE_INDICATE_DISCON_UNSPECIFIED:
event = WIFI_MGMT_EVENT_DISCONNECT;
if (p_wifi_netlink->conn_blocked) {
sys_sema_up(&p_wifi_netlink->block_sema);
p_wifi_netlink->conn_blocked = FALSE;
}
break;
default:
return OS_ERROR;
}
wifi_mgmt_message.event = event;
wifi_mgmt_message.reason = message;
return eloop_message_send(wifi_mgmt_message);
}
/*!
\brief wifi management task
\param[in] arg: pointer to the argureargument
\param[out] none
\retval none
*/
void wifi_management_task(void *arg)
{
eloop_init();
eloop_run();
eloop_destroy();
sys_sema_up(&mgmt_task_exit_sema);
sys_task_delete(NULL);
}
/*!
\brief wifi management start
\param[in] none
\param[out] none
\retval none
*/
void wifi_management_start(void)
{
void *handle;
COMPILE_TIME_ASSERT(WIFI_MGMT_EVENT_MAX <= UINT16_MAX);
sys_sema_init(&mgmt_task_exit_sema, 0);
handle = sys_task_create(&wifi_mgmt_task_tcb, (const uint8_t *)"wifi_mgmt", &wifi_mgmt_task_stk[0],
WIFI_MGMT_TASK_STK_SIZE, WIFI_MGMT_TASK_QUEUE_SIZE, WIFI_MGMT_TASK_PRIO,
(task_func_t)wifi_management_task, NULL);
if (handle == NULL) {
DEBUGPRINT("creating wifi management task failed\r\n");
sys_sema_free(&mgmt_task_exit_sema);
mgmt_task_exit_sema = NULL;
return;
}
eloop_event_send(WIFI_MGMT_EVENT_INIT);
}
/*!
\brief wifi management stop
\param[in] none
\param[out] none
\retval none
*/
void wifi_management_stop(void)
{
eloop_event_send(ELOOP_EVENT_TERMINATE);
if (mgmt_task_exit_sema != NULL) {
// wait until wifi_management_task run finish
sys_sema_down(&mgmt_task_exit_sema, 0);
sys_sema_free(&mgmt_task_exit_sema);
mgmt_task_exit_sema = NULL;
}
}
/*!
\brief wifi management ap start
\param[in] ssid: pointer to the SSID
\param[in] password: pointer to the password
\param[in] channel: channel
\param[in] hidden: whether hidden
\param[out] none
\retval none
*/
void wifi_management_ap_start(char *ssid, char *passwd, uint32_t channel, uint32_t hidden)
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
eloop_event_send(ELOOP_EVENT_TERMINATE);
wifi_netif_stop_dhcp();
/* Stop DHCPD */
if (ap_dhcpd_started) {
stop_dhcpd_daemon();
ap_dhcpd_started = 0;
}
wifi_netlink_ap_start(ssid, passwd, channel, hidden);
#ifdef CONFIG_IPV6_SUPPORT
CONFIG_IP4_ADDR(&ipaddr.u_addr.ip4);
CONFIG_IP4_ADDR_NM(&netmask.u_addr.ip4);
CONFIG_IP4_ADDR_GW(&gw.u_addr.ip4);
#else
CONFIG_IP4_ADDR(&ipaddr);
CONFIG_IP4_ADDR_NM(&netmask);
CONFIG_IP4_ADDR_GW(&gw);
#endif
wifi_netif_set_addr(&ipaddr, &netmask, &gw);
if (!ap_dhcpd_started) {
dhcpd_daemon();
ap_dhcpd_started = 1;
}
wifi_netif_set_up();
}
/*!
\brief wifi management station start
\param[in] none
\param[out] none
\retval none
*/
void wifi_management_sta_start(void)
{
if (p_wifi_netlink->ap_started){
/* Stop DHCPD */
if (ap_dhcpd_started) {
stop_dhcpd_daemon();
ap_dhcpd_started = 0;
}
wifi_netlink_dev_close();
wifi_netlink_dev_open();
}
if (eloop_event_send(ELOOP_EVENT_WAKEUP) != OS_OK) {
wifi_management_start();
}
}
/*!
\brief wifi management ap assoc infromation
\param[in] assoc_info: pointer to the assoc infromation
\param[out] none
\retval run status(0x0000000-0xffffffff)
*/
uint32_t wifi_management_ap_assoc_info(uint8_t *assoc_info)
{
return wifi_ops_entry.wifi_softap_get_assoc_info(assoc_info);
}
#endif /* CONFIG_WIFI_MANAGEMENT_TASK */
void wifi_management_init(void)
{
void *handle;
#ifndef CONFIG_RF_TEST_SUPPORT
printf("System clock is %d\r\n", SystemCoreClock);
#endif
hw_crypt_lock_init();
tcpip_init(NULL, NULL);
wifi_netlink_init();
/* prevent os from going to tickless sleep */
wifi_wakelock_acquire();
wifi_netlink_dev_open();
#ifdef CONFIG_RF_TEST_SUPPORT
mp_mode_config(LOG_UART);
#endif
#ifdef CONFIG_WIFI_MANAGEMENT_TASK
wifi_management_start();
if (wifi_netlink_auto_conn_get()) {
if (wifi_netlink_joined_ap_load() >= 0) {
eloop_event_send(WIFI_MGMT_EVENT_AUTO_CONNECT);
}
}
#endif
}