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

1742 lines
62 KiB
C

/*!
\file wifi_netlink.c
\brief WiFi netlink layer 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.
*/
#include <string.h>
#include <stdlib.h>
#undef MOUDLE
#define MOUDLE WIFI_NETLINK
#include "debug_print.h"
#include "app_cfg.h"
#include "uart.h"
#include "malloc.h"
#include "lwipopts.h"
#include "wifi_netif.h"
#define EXTERN
#include "wifi_netlink.h"
#include "wlan_intf_def.h"
#include "wlan_intf.h"
#include "wifi_management.h"
#if defined(CONFIG_TZ_ENABLED)
#include "rom_export.h"
#include "mbl_nsc_api.h"
#else
#include "mbl_api.h"
#endif
#ifdef PLATFORM_OS_RTTHREAD
#include <drivers/pm.h>
#endif
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
static void *wifi_roaming_task_tcb = NULL;
static int32_t is_roaming = _FALSE;
static void terminate_roaming_task(void);
static int roaming_scan(struct wifi_scan_req *scan_req);
static void wifi_roaming_task_func(void *p_arg);
#endif
extern uint32_t softap_find_ipaddr_by_macaddr(uint8_t *mac_addr);
/*!
\brief initialize wifi netlink
\param[in] none
\param[out] none
\retval wifi netlink information
*/
WIFI_NETLINK_INFO_T *wifi_netlink_init(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink;
if (p_wifi_netlink)
return p_wifi_netlink;
wifi_netlink = (WIFI_NETLINK_INFO_T *)sys_malloc(sizeof(WIFI_NETLINK_INFO_T));
if (NULL == wifi_netlink) {
DEBUG_ERROR("wifi netlink: alloc wifi netlink failed\r\n");
}
sys_memset(wifi_netlink, 0, sizeof(WIFI_NETLINK_INFO_T));
p_wifi_netlink = wifi_netlink;
wifi_ops_entry.wifi_set_task_priority(WIFI_RX_TASK_PRORITY,
WIFI_TX_TASK_PRORITY,
WIFI_WLAN_TASK_PRORITY,
WIFI_PS_TASK_PRORITY);
sys_sema_init(&wifi_netlink->block_sema, 0);
return wifi_netlink;
}
/*!
\brief get wifi netlink status
\param[in] none
\param[out] none
\retval 0: run success
*/
int wifi_netlink_status_get(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
if (!wifi_netlink->device_opened) {
DEBUGPRINT("WIFI Status: Closed\r\n");
DEBUGPRINT("==============================\r\n");
DEBUGPRINT("\r\n");
return 0;
}
if (wifi_netlink->ap_started) {
uint8_t assoc_info[MAX_STATION_NUM * ETH_ALEN];
uint32_t sta_ipaddr[MAX_STATION_NUM];
uint32_t client_num, i;
DEBUGPRINT("WIFI Status: AP Started\r\n");
DEBUGPRINT("==============================\r\n");
DEBUGPRINT("\rMODE: AP\r\n");
DEBUGPRINT("\rSSID: %s\r\n", wifi_netlink->ap_conf.ssid);
DEBUGPRINT("\rCHANNEL: %d\r\n", wifi_netlink->ap_conf.channel);
if (wifi_netlink->ap_conf.security == 3) {
DEBUGPRINT("\rSECURITY: WPA2\r\n");
DEBUGPRINT("\rPASSWORD: %s\r\n", wifi_netlink->ap_conf.password);
} else if (wifi_netlink->ap_conf.security == 0) {
DEBUGPRINT("\rSECURITY: Open\r\n");
}
client_num = wifi_ops_entry.wifi_softap_get_assoc_info(assoc_info);
for (i = 0; i < client_num; i++) {
sta_ipaddr[i] = softap_find_ipaddr_by_macaddr(assoc_info + i * ETH_ALEN);
DEBUGPRINT("CLIENT[%d]: "MAC_FMT" "IP_FMT"\r\n", i, MAC_ARG(assoc_info + i * ETH_ALEN), IP_ARG(sta_ipaddr[i]));
}
} else {
if (wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
DEBUGPRINT("WIFI Status: Connected\r\n");
DEBUGPRINT("==============================\r\n");
DEBUGPRINT("\rMODE: STATION\r\n");
DEBUGPRINT("\rSSID: %s\r\n", wifi_netlink->connected_ap_info.ssid.ssid);
DEBUGPRINT("\rCHANNEL: %d\r\n", wifi_netlink->connected_ap_info.channel);
switch (wifi_netlink->connected_ap_info.bw) {
case CHANNEL_WIDTH_20:
DEBUGPRINT("\rBW: 20M\r\n");
break;
case CHANNEL_WIDTH_40:
DEBUGPRINT("\rBW: 40M\r\n");
break;
case CHANNEL_WIDTH_80:
DEBUGPRINT("\rBW: 80M\r\n");
break;
case CHANNEL_WIDTH_160:
DEBUGPRINT("\rBW: 160M\r\n");
break;
case CHANNEL_WIDTH_80_80:
DEBUGPRINT("\rBW: 80+80M\r\n");
break;
default:
DEBUGPRINT("\rBW: UnKnown\r\n");
break;
}
switch (wifi_netlink->connected_ap_info.wireless_mode) {
case WIRELESS_11B:
DEBUGPRINT("\rMODE: B\r\n");
break;
case WIRELESS_11G:
case WIRELESS_11BG:
case WIRELESS_11ABG:
DEBUGPRINT("\rMODE: G\r\n");
break;
case WIRELESS_11_24N:
case WIRELESS_11_5N:
case WIRELESS_11GN:
case WIRELESS_11AN:
case WIRELESS_11BGN:
case WIRELESS_11ABGN:
DEBUGPRINT("\rMODE: N\r\n");
break;
case WIRELESS_11BGN_AC:
#ifndef CONFIG_80211AC_SUPPORT
DEBUGPRINT("\rMODE: N\r\n");
#else
DEBUGPRINT("\rMODE: AC\r\n");
#endif
break;
case WIRELESS_11AC:
case WIRELESS_11_AC_5G:
DEBUGPRINT("\rMODE: AC\r\n");
break;
default:
DEBUGPRINT("\rMODE: Unknown\r\n");
break;
}
switch (wifi_netlink->connect_info.encryp_protocol) {
case WIFI_ENCRYPT_PROTOCOL_OPENSYS:
DEBUGPRINT("\rSECURITY: Open \r\n");
break;
case WIFI_ENCRYPT_PROTOCOL_WEP:
DEBUGPRINT("\rSECURITY: WEP \r\n");
break;
case WIFI_ENCRYPT_PROTOCOL_WPA:
DEBUGPRINT("\rSECURITY: WPA \r\n");
break;
case WIFI_ENCRYPT_PROTOCOL_WPA2:
DEBUGPRINT("\rSECURITY: WPA2 \r\n");
break;
case WIFI_ENCRYPT_PROTOCOL_WPA3_TRANSITION:
DEBUGPRINT("\rSECURITY: WPA2/WPA3\r\n");
break;
case WIFI_ENCRYPT_PROTOCOL_WPA3_ONLY:
DEBUGPRINT("\rSECURITY: WPA3\r\n");
break;
default:
DEBUGPRINT("\rSECURITY: Unknown \r\n");
break;
}
DEBUGPRINT("\rBSSID: "MAC_FMT"\r\n", MAC_ARG(wifi_netlink->connected_ap_info.bssid_info.bssid));
DEBUGPRINT("\rRSSI: %d dbm\r\n", wifi_ops_entry.wifi_get_bss_rssi());
} else {
DEBUGPRINT("WIFI Status: Opened\r\n");
DEBUGPRINT("\r\n==============================\r\n");
}
}
DEBUGPRINT("\r\n");
return 0;
}
/* same ssid ap info process */
/*!
\brief add ap list
\param[in] insert_node: pointer to the insert node
\param[in] scan_list_head: pointer to the scan list head
\param[out] none
\retval 0: replac node, 1: insert new node
*/
uint8_t ap_list_add(struct wifi_scan_info *insert_node, struct wifi_scan_info *scan_list_head)
{
struct wifi_scan_info *p_scan_list = scan_list_head;
while (p_scan_list != NULL) {
if ((insert_node->ssid.ssid_len == p_scan_list->ssid.ssid_len) &&
(!sys_memcmp(&insert_node->ssid.ssid, &p_scan_list->ssid.ssid, insert_node->ssid.ssid_len))) {
if (insert_node->encryp_protocol != p_scan_list->encryp_protocol) {
return 1;
} else {
if (insert_node->rssi > p_scan_list->rssi) {
// use insert_node ap info replacing the previous one except next_ptr
sys_memcpy(&p_scan_list->ssid, &insert_node->ssid, sizeof(struct wifi_scan_info) - FIELD_OFFSET(struct wifi_scan_info, ssid));
}
return 0;
}
}
p_scan_list = p_scan_list->next_ptr;
}
return 1;
}
/*!
\brief compare AP RSSI
\param[in] insert_node: pointer to the insert node
\param[in] original_node: pointer to the original node
\param[out] none
\retval 0: insert node RSSI is lower, 1: insert node RSSI is higher
*/
uint8_t be_prior_to(struct wifi_scan_info *insert_node, struct wifi_scan_info *original_node)
{
/*
if ((insert_node->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_OPENSYS) &&
(original_node->encryp_protocol != WIFI_ENCRYPT_PROTOCOL_OPENSYS)) {
return TRUE;
}
if ((insert_node->encryp_protocol != WIFI_ENCRYPT_PROTOCOL_OPENSYS) &&
(original_node->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_OPENSYS)) {
return FALSE;
}
*/
if (insert_node->rssi > original_node->rssi) {
return 1;
} else {
return 0;
}
}
/*!
\brief sorting scan list
\param[in] none
\param[out] none
\retval none
*/
void scan_list_sorting(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_scan_info *p_scan_list, *p_next;
struct wifi_scan_info *scan_list_head = NULL;
struct wifi_scan_info *scan_list_node = wifi_netlink->scan_list;
unsigned char i;
wifi_netlink->valid_ap_num = 0;
for (i = 0; i < wifi_netlink->scan_ap_num; i++) {
if (scan_list_head == NULL) {
scan_list_head = scan_list_node;
wifi_netlink->valid_ap_num = 1;
} else {
if (ap_list_add(scan_list_node, scan_list_head)) {
p_scan_list = scan_list_head;
if (be_prior_to(scan_list_node, p_scan_list)) {
scan_list_node->next_ptr = p_scan_list;
scan_list_head = scan_list_node;
} else {
while (p_scan_list->next_ptr != NULL) {
p_next = p_scan_list->next_ptr;
if (be_prior_to(scan_list_node, p_next)) {
scan_list_node->next_ptr = p_next;
p_scan_list->next_ptr = scan_list_node;
break;
}
p_scan_list = p_scan_list->next_ptr;
}
if (p_scan_list->next_ptr == NULL) {
p_scan_list->next_ptr = scan_list_node;
scan_list_node->next_ptr = NULL;
}
}
wifi_netlink->valid_ap_num++;
}
}
scan_list_node++;
}
wifi_netlink->scan_list_head = scan_list_head;
}
/*!
\brief print bitrate
\param[in] bitrate: bitrate
\param[out] none
\retval none
*/
void bitrate_print(unsigned long bitrate)
{
double rate = bitrate;
char scale;
int divisor;
if (rate >= GIGA) {
scale = 'G';
divisor = GIGA;
} else {
if (rate >= MEGA) {
scale = 'M';
divisor = MEGA;
} else {
scale = 'k';
divisor = KILO;
}
}
DEBUGPRINT("Rate: %g %cb/s\r\n", rate/divisor, scale);
}
/*!
\brief post netlink message
\param[in] receiver_tcb: pointer to the receiver task
\param[in] msg_type: message type refer to WIFI_MESSAGE_TYPE_E
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
static int netlink_message_post(void *receiver_tcb, WIFI_MESSAGE_TYPE_E msg_type)
{
return sys_task_post(receiver_tcb, &msg_type, 0);
}
/*!
\brief set wifi netlink scan
\param[in] none
\param[out] none
\retval 0 if succeeded, non-zero otherwise
*/
int wifi_netlink_scan_set(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_scan_req scan_req;
uint8_t ret_val = 0;
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
if (wifi_netlink->link_status == WIFI_NETLINK_STATUS_ROAMING) {
DEBUGPRINT("wifi netlink: Roaming is ongoing, stop scan.\r\n");
return ret_val;
}
#endif
sys_memset(&scan_req.ssid.ssid, 0, WIFI_SSID_MAX_LEN);
scan_req.ssid.ssid_len = 0;
// wifi_netlink->saved_link_status = wifi_netlink->link_status;
if (wifi_netlink->link_status == WIFI_NETLINK_STATUS_NO_LINK) {
wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK_SCAN;
} else if (wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED_SCAN;
}
wifi_netlink->scan_list_ready = 0;
ret_val = wifi_ops_entry.wifi_scan_proc_func(&scan_req);
return ret_val;
}
/*!
\brief get wifi netlink scan ist
\param[in] iterator: pointer to the iter scan item function
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_scan_list_get(iter_scan_item iterator)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_scan_info *p_scan_list;
wifi_netlink->scan_ap_num = 0;
wifi_netlink->scan_list_head = NULL;
sys_memset(wifi_netlink->scan_list, 0, sizeof(wifi_netlink->scan_list));
wifi_ops_entry.wifi_get_scan_list_func(wifi_netlink->scan_list, &wifi_netlink->scan_ap_num);
scan_list_sorting();
if (iterator) {
p_scan_list = wifi_netlink->scan_list_head;
while (p_scan_list != NULL) {
iterator(p_scan_list);
p_scan_list = p_scan_list->next_ptr;
}
}
//wifi_netlink->link_status = wifi_netlink->saved_link_status;
DEBUG_INFO("wifi netlink: scan finished, scanned ap number: %d\r\n", wifi_netlink->valid_ap_num);
return 0;
}
/*!
\brief wifi netlink connect request
\param[in] ssid: pointer to the SSID
\param[in] password: pointer to the password
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_connect_req(uint8_t *ssid, uint8_t *password)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_ssid_config *connect_info = &wifi_netlink->connect_info;
#if 0
struct wifi_scan_info *p_scan_list = wifi_netlink->scan_list_head;
unsigned char wep_key[13] = {0};
uint8_t temp_buf[3] = {0};
char *endptr = NULL;
uint8_t i;
uint8_t found_ap = 0;
#endif
if (ssid == NULL) {
DEBUG_WARNING("wifi netlink: ssid empty!\r\n");
return -1;
}
if (strlen((const char *)ssid) > WIFI_SSID_MAX_LEN) {
DEBUG_WARNING("wifi netlink: ssid's length should not be greater than %d!\r\n", WIFI_SSID_MAX_LEN);
return -1;
}
if (password &&
((strlen((const char *)password) > WPA_MAX_PSK_LEN) ||
((strlen((const char *)password) < WPA_MIN_PSK_LEN)))) {
DEBUG_WARNING("wifi netlink: password's length should not be greater than %d or less than %d!\r\n",
WPA_MAX_PSK_LEN, WPA_MIN_PSK_LEN);
return -1;
}
if (wifi_netlink->ap_started) {
wifi_netlink_dev_close();
wifi_netlink_dev_open();
}
#if 0 /* Move to wifi interface layer. */
for (i = 0; i < wifi_netlink->scan_ap_num; i++) {
if ((p_scan_list->ssid.ssid_len == strlen((const char *)ssid)) &&
(!sys_memcmp(p_scan_list->ssid.ssid, ssid, p_scan_list->ssid.ssid_len))) {
found_ap = 1;
break;
} else {
p_scan_list = p_scan_list->next_ptr;
}
}
sys_memset(connect_info, 0, sizeof(*connect_info));
if (found_ap) {
sys_memcpy(&connect_info->ssid, &p_scan_list->ssid, sizeof(struct wifi_ssid));
sys_memcpy(&connect_info->bssid_info, &p_scan_list->bssid_info, sizeof(struct wifi_bssid));
connect_info->network_mode = p_scan_list->network_mode;
connect_info->encryp_protocol = p_scan_list->encryp_protocol;
connect_info->channel = p_scan_list->channel;
connect_info->pairwise_cipher = p_scan_list->pairwise_cipher;
connect_info->group_cipher = p_scan_list->group_cipher;
if (password)
sys_memcpy(connect_info->passwd, password, strlen((const char *)password) + 1);
if (connect_info->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_OPENSYS) {
} else if (connect_info->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_WPA ||
connect_info->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_WPA2) {
connect_info->credential.wpa_credential.credential_type = WIFI_WPA_CREDENTIAL_TYPE_PSK;
if (password == NULL) {
DEBUGPRINT("wifi netlink: please input the password when connect!\r\n");
return -1;
} else {
sys_memcpy(connect_info->credential.wpa_credential.wpa_psk_info.psk, password, strlen((const char *)password) + 1);
}
} else if (connect_info->encryp_protocol == WIFI_ENCRYPT_PROTOCOL_WEP) {
if (password == NULL) {
DEBUGPRINT("wifi netlink: please input the password when connect!\r\n");
return -1;
}
connect_info->credential.wep_credential.is_open_mode = 0;
connect_info->credential.wep_credential.key_in_use = 0; // [idx0 - idx3]
if (strlen((const char *)password) == (WEP_64BITS_KEY_HEX_LEN << 1)) {
connect_info->credential.wep_credential.key_type = WIFI_WEP_KEY_TYPE_64BITS;
for (i=0; i < WEP_64BITS_KEY_HEX_LEN; i++) {
if ((password + i*2) != NULL) {
sys_memcpy(temp_buf, (password + i*2), 2);
wep_key[i] = (uint8_t)strtoul((const char *)temp_buf, &endptr, 16);
}
}
sys_memcpy(connect_info->credential.wep_credential.key.key_64bits_arr[0], wep_key, WEP_64BITS_KEY_HEX_LEN);
} else if (strlen((const char *)password) == (WEP_128BITS_KEY_HEX_LEN << 1)) {
connect_info->credential.wep_credential.key_type = WIFI_WEP_KEY_TYPE_128BITS;
for (i=0; i < WEP_128BITS_KEY_HEX_LEN; i++) {
if ((password + i*2) != NULL) {
sys_memcpy(temp_buf, (password + i*2), 2);
wep_key[i] = (uint8_t)strtoul((const char *)temp_buf, &endptr, 16);
}
}
sys_memcpy(connect_info->credential.wep_credential.key.key_128bits_arr[0], wep_key, WEP_128BITS_KEY_HEX_LEN);
} else {
DEBUGPRINT("wifi netlink: WEP share key length should be %d or %d HEX!\r\n",
WEP_64BITS_KEY_HEX_LEN << 1, WEP_128BITS_KEY_HEX_LEN << 1);
return -1;
}
} else {
DEBUGPRINT("wifi netlink: not supported security mode!\r\n");
return -1;
}
} else {
sys_memcpy(connect_info->ssid.ssid, ssid, strlen((const char *)ssid) + 1);
connect_info->ssid.ssid_len = strlen((const char *)ssid);
if (password) {
sys_memcpy(connect_info->passwd, password, strlen((const char *)password) + 1);
}
}
#else
sys_memcpy(connect_info->ssid.ssid, ssid, strlen((const char *)ssid) + 1);
connect_info->ssid.ssid_len = strlen((const char *)ssid);
if (password) {
sys_memcpy(connect_info->passwd, password, strlen((const char *)password) + 1);
} else {
sys_memset(connect_info->passwd, 0, 64);
}
#endif
wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKING;
if (wifi_ops_entry.wifi_connect_req_func(connect_info) == _FALSE)
return -1;
return 0;
}
/*!
\brief wifi netlink disconnect request
\param[in] none
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_disconnect_req(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_disconnect_req disconnect_info;
if (wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
sys_memcpy(&disconnect_info.ssid, &wifi_netlink->connected_ap_info.ssid, sizeof(struct wifi_ssid));
wifi_ops_entry.wifi_disconnect_req_func(&disconnect_info);
#ifdef CONFIG_IPV6_SUPPORT
wifi_netif_set_ip6addr_invalid();
#endif
DEBUG_INFO("wifi netlink: disconnect with ap %s\r\n", &wifi_netlink->connected_ap_info.ssid.ssid);
sys_memset(&wifi_netlink->connected_ap_info, 0, sizeof(struct wifi_connect_result));
wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
} else {
DEBUG_INFO("wifi netlink: not connected!\r\n");
}
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
terminate_roaming_task();
#endif
return 0;
}
/*!
\brief open wifi netlink device
\param[in] none
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_dev_open(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
if (!wifi_netlink->device_opened) {
wifi_netif_open();
wifi_netlink->device_opened = 1;
sys_sema_init(&wifi_netlink->block_sema, 0);
DEBUG_INFO("wifi netlink: device opened!\r\n");
}
return 0;
}
/*!
\brief close wifi netlink device
\param[in] none
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_dev_close(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
if (wifi_netlink->device_opened) {
wifi_netlink_disconnect_req();
wifi_netif_close();
wifi_netlink->device_opened = 0;
if (wifi_netlink->block_sema)
sys_sema_free(&wifi_netlink->block_sema);
sys_memset(wifi_netlink, 0, sizeof(WIFI_NETLINK_INFO_T));
DEBUG_INFO("wifi netlink: device closed!\r\n");
}
return 0;
}
/*!
\brief set wifi netlink ip addrress
\param[in] ipaddr: pointer to the ip addrress
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_ipaddr_set(uint8_t *ipaddr)
{
wifi_ops_entry.wifi_set_ipaddr_func(ipaddr);
DEBUG_INFO("wifi netlink: Got IP "IP_FMT"\r\n", IP_ARG(*(uint32_t *)ipaddr));
#ifdef CONFIG_IPV6_SUPPORT
ip6_addr_t *ip6_uniqe = (ip6_addr_t *)wifi_netif_get_ip6(1);
DEBUG_INFO("wifi netlink: Got IP6 [%s]\r\n", ip6addr_ntoa(ip6_uniqe));
#endif
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED_CONFIGED;
return 0;
}
/*!
\brief start wifi netlink ap
\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 0 if succeeded, -1 otherwise
*/
int wifi_netlink_ap_start(char *ssid, char *password, uint8_t channel, uint8_t hidden)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
uint8_t result = 0;
struct wifi_ap_config ap_conf;
if (wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
wifi_netlink_disconnect_req();
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
} else if (wifi_netlink->link_status == WIFI_NETLINK_STATUS_ROAMING) {
terminate_roaming_task();
#endif
}
if (wifi_netlink->ap_started) {
wifi_netlink_dev_close();
wifi_netlink_dev_open();
}
if (wifi_netlink->device_opened == 0) {
wifi_netlink_dev_open();
}
if ((NULL == ssid) || (strlen(ssid) > WIFI_SSID_MAX_LEN))
return -1;
sys_memcpy(ap_conf.ssid, ssid, (strlen(ssid) + 1));
if (password)
sys_memcpy(ap_conf.password, password, (strlen(password) + 1));
else
sys_memset(ap_conf.password, 0, sizeof(ap_conf.password));
ap_conf.channel = channel;
ap_conf.hidden = hidden;
if (NULL != password) {
ap_conf.security = WIFI_ENCRYPT_PROTOCOL_WPA2;
} else {
ap_conf.security = WIFI_ENCRYPT_PROTOCOL_OPENSYS;
}
// softap security mode: WPA2-AES only
DEBUG_INFO("wifi netlink: starting softap ...\r\n");
if (wifi_ops_entry.wifi_softap_func) {
result = wifi_ops_entry.wifi_softap_func(&ap_conf);
} else {
DEBUG_WARNING("wifi netlink: Not support softap mode now.\r\n");
DEBUG_WARNING("wifi netlink: Please define CONFIG_SOFTAP_SUPPORT in wlan_cfg.h and rebuild wlan library.\r\n");
return 0;
}
if (result == 1) {
// update wifi netlink structure for getting status
wifi_netlink->ap_started = 1;
sys_memcpy((uint8_t *)&wifi_netlink->ap_conf, &ap_conf, sizeof(struct wifi_ap_config));
DEBUG_INFO("wifi netlink: softap %s started!\r\n", ssid);
} else {
DEBUG_INFO("wifi netlink: softap not started!\r\n");
}
return 0;
}
/*!
\brief set wifi netlink channel
\param[in] channel: channel
\param[in] bandwidth: band width
\param[in] ch_offset: chchannel offset
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_channel_set(uint32_t channel, uint32_t bandwidth, uint32_t ch_offset)
{
if (!(channel > 0 && channel <= 14) &&
!((channel == 36) || (channel == 40) || (channel == 44) || (channel == 48)) &&
!((channel == 149) || (channel == 153) || (channel == 157) || (channel == 161))) {
DEBUG_ERROR("wifi netlink: set channel, invalid channel!\r\n");
return -1;
}
if (bandwidth != CHANNEL_WIDTH_20 && bandwidth != CHANNEL_WIDTH_40) {
DEBUG_ERROR("wifi netlink: set channel, invalid bandwidth!\r\n");
return -1;
}
if (ch_offset > HT_SEC_CHNL_OFFSET_BELOW) {
DEBUG_ERROR("wifi netlink: set channel, invalid channel offset!\r\n");
return -1;
}
if (bandwidth == CHANNEL_WIDTH_40 && ch_offset == HT_SEC_CHNL_OFFSET_NONE) {
if ((channel > 9 && channel <= 13) || (channel == 48) || (channel == 161)) {
ch_offset = HT_SEC_CHNL_OFFSET_BELOW;
} else {
ch_offset = HT_SEC_CHNL_OFFSET_ABOVE;
}
}
wifi_ops_entry.wifi_set_channel(channel, bandwidth, ch_offset);
DEBUG_INFO("set primary channel to %d, bandwidth is %d, channel offset is %d\r\n",
channel, bandwidth, ch_offset);
return 0;
}
/*!
\brief set wifi power mode
\param[in] ps_enable: 0 is disable, 1 is normal power saveing mode, 2 is deep sleep mode
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_ps_set(int ps_mode)
{
wifi_ops_entry.wifi_set_ps(ps_mode);
#ifdef RT_USING_PM
if (ps_mode == WIFI_PS_MODE_LPS_AND_CPU_DEEPSLEEP) {
for (int i = PM_SLEEP_MODE_NONE; i < PM_SLEEP_MODE_DEEP; i++) {
rt_pm_release_all(i);
}
rt_pm_request(PM_SLEEP_MODE_DEEP);
} else {
rt_pm_request(PM_SLEEP_MODE_NONE);
}
#endif
return 0;
}
/*!
\brief get wifi power save mode
\param[in] none
\param[out] none
\retval the value of power save mode
*/
int wifi_netlink_ps_get(void)
{
int ps_mode;
wifi_ops_entry.wifi_get_ps((uint32_t*)&ps_mode);
return ps_mode;
}
/*!
\brief get wifi netlink BSS RSSI
\param[in] none
\param[out] none
\retval the RSSI value of BSS, 0 if get value failed
*/
int wifi_netlink_bss_rssi_get(void)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
if (wifi_netlink->link_status >= WIFI_NETLINK_STATUS_LINKED) {
wifi_netlink->connected_ap_info.rssi = wifi_ops_entry.wifi_get_bss_rssi();
return wifi_netlink->connected_ap_info.rssi;
}
return 0;
}
/*!
\brief get wifi netlink ap channel
\param[in] bssid: pointer to the BSSID
\param[out] none
\retval the channel of ap, 0 if get failed
*/
int wifi_netlink_ap_channel_get(uint8_t *bssid)
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
struct wifi_scan_info *p_scan_list = wifi_netlink->scan_list_head;
while (p_scan_list != NULL) {
if (sys_memcmp(p_scan_list->bssid_info.bssid, bssid, 6) == 0) {
return p_scan_list->channel;
}
p_scan_list = p_scan_list->next_ptr;
}
return 0;
}
/*!
\brief get wifi netlink task stack
\param[in] none
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_task_stack_get(void)
{
wifi_ops_entry.wifi_dump_driver_threads();
return 0;
}
/*!
\brief get wifi netlink link state
\param[in] none
\param[out] none
\retval wifi netlink link state
*/
int wifi_netlink_link_state_get(void)
{
return p_wifi_netlink->link_status;
}
/*!
\brief get wifi netlink linked ap information
\param[in] none
\param[out] ssid: pointer to the SSID
\param[out] passwd: pointer to the password
\param[out] bssid: pointer to the BSSID
\retval 0 if succeeded
*/
int wifi_netlink_linked_ap_info_get(uint8_t *ssid, uint8_t *passwd, uint8_t *bssid)
{
if (ssid) {
sys_memcpy(ssid, p_wifi_netlink->connected_ap_info.ssid.ssid, p_wifi_netlink->connected_ap_info.ssid.ssid_len);
}
if (passwd) {
sys_memcpy(passwd, p_wifi_netlink->connect_info.passwd, sizeof(p_wifi_netlink->connect_info.passwd));
}
if (bssid) {
sys_memcpy(bssid, p_wifi_netlink->connected_ap_info.bssid_info.bssid, ETH_ALEN);
}
return 0;
}
/*!
\brief send wifi netlink raw
\param[in] buf: pointer to the data
\param[in] len: send data length
\param[out] none
\retval 1 if succeed, 0 otherwise
*/
int wifi_netlink_raw_send(uint8_t *buf, uint32_t len)
{
struct wifi_priv_req_info priv_req_info;
priv_req_info.priv_req = WIFI_PRIV_TEST_TX;
priv_req_info.priv_param1 = (uint32_t)buf;
priv_req_info.priv_param2 = len;
priv_req_info.priv_param3 = 1;
priv_req_info.priv_param4 = 0;
priv_req_info.result_data = NULL;
return wifi_ops_entry.wifi_priv_req_func(&priv_req_info);
}
/*!
\brief wifi netlink promisc callback
\param[in] buf: pointer to the data
\param[in] len: data length
\param[in] rssi: RSSI
\param[out] none
\retval none
*/
static void wifi_netlink_promisc_callback(unsigned char *buf, unsigned short len, signed char rssi)
{
if (p_wifi_netlink->promisc_callback) {
p_wifi_netlink->promisc_callback(buf, len, rssi);
}
if (p_wifi_netlink->promisc_mgmt_callback) {
if ((GetFrameType(buf) == WIFI_MGT_TYPE) &&
((GetFrameSubType(buf) >> 5) & p_wifi_netlink->promisc_mgmt_filter)) {
p_wifi_netlink->promisc_mgmt_callback(buf, (int)len, rssi, 0);
}
}
}
/*!
\brief set wifi netlink promisc mode
\param[in] enable: 1 is enable, 0 is disable
\param[in] callback: pointer to the callback function
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_promisc_mode_set(uint32_t enable,
void (*callback)(unsigned char*, unsigned short, signed char))
{
WIFI_NETLINK_INFO_T *wifi_netlink = p_wifi_netlink;
if (enable) {
wifi_netlink->promisc_callback = callback;
wifi_ops_entry.wifi_set_promisc_mode(enable, wifi_netlink_promisc_callback);
} else {
wifi_ops_entry.wifi_set_promisc_mode(0, NULL);
wifi_netlink->promisc_callback = NULL;
wifi_netlink->promisc_mgmt_callback = NULL;
}
return 0;
}
/*!
\brief set wifi netlink promisc management callback
\param[in] filter_mask: filter mask
\param[in] callback: pointer to the callback function
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_promisc_mgmt_cb_set(uint32_t filter_mask,
void (*callback)(unsigned char*, int, signed char, int))
{
p_wifi_netlink->promisc_mgmt_callback = callback;
p_wifi_netlink->promisc_mgmt_filter = filter_mask;
return 0;
}
/*!
\brief set wifi netlink promisc filter
\param[in] filter_type: filter type
\param[in] filter_value: pointer to the filter value
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_promisc_filter_set(uint8_t filter_type, uint8_t *filter_value)
{
wifi_ops_entry.wifi_set_promisc_filter(filter_type, filter_value);
return 0;
}
/*!
\brief set wifi netlink auto connect
\param[in] auto_conn_enable: 1 is enable, 0 is disable
\param[out] none
\retval function run state
*/
int wifi_netlink_auto_conn_set(uint8_t auto_conn_enable)
{
#ifdef USE_MBL_API
return mbl_sys_status_set(SYS_AUTO_CONN, LEN_SYS_AUTO_CONN, &auto_conn_enable);
#else
return 0;
#endif
}
/*!
\brief get wifi netlink auto connect
\param[in] none
\param[out] none
\retval the state value of auto connect enable
*/
uint8_t wifi_netlink_auto_conn_get(void)
{
#ifdef USE_MBL_API
uint8_t auto_conn_enable;
int ret = mbl_sys_status_get(SYS_AUTO_CONN, LEN_SYS_AUTO_CONN, &auto_conn_enable);
if (ret != SYS_STATUS_FOUND_OK)
auto_conn_enable = 0;
//DEBUG_INFO("Get auto connect = %d\r\n", auto_conn_enable);
return auto_conn_enable;
#else
return 0;
#endif
}
/*!
\brief store wifi netlink joined ap
\param[in] none
\param[out] none
\retval 0 if succeeded, -1 is SSID length error, -2 is password length error
*/
int wifi_netlink_joined_ap_store(void)
{
#ifdef USE_MBL_API
uint8_t *ssid = p_wifi_netlink->connected_ap_info.ssid.ssid;
uint8_t *pwd = p_wifi_netlink->connect_info.passwd;
ip_addr_t *ip = wifi_netif_get_ip();
uint8_t buf[LEN_SYS_SSID_X];
uint8_t ssid_len = strlen((char *)ssid);
uint8_t pwd_len = strlen((char *)pwd);
if (ssid_len <= LEN_SYS_SSID_X) {
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, ssid, ssid_len);
mbl_sys_status_set(SYS_SSID_1, LEN_SYS_SSID_X, buf);
} else if ((ssid_len > LEN_SYS_SSID_X) && (ssid_len < 2 * LEN_SYS_SSID_X)) {
mbl_sys_status_set(SYS_SSID_1, LEN_SYS_SSID_X, (uint8_t *)ssid);
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, (ssid + LEN_SYS_SSID_X), (ssid_len - LEN_SYS_SSID_X));
mbl_sys_status_set(SYS_SSID_2, LEN_SYS_SSID_X, buf);
} else {
return -1;
}
if (pwd_len <= LEN_SYS_PASSWD_X) {
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, pwd, pwd_len);
mbl_sys_status_set(SYS_PASSWD_1, LEN_SYS_PASSWD_X, buf);
} else if ((pwd_len > LEN_SYS_PASSWD_X) && (pwd_len <= 2 * LEN_SYS_PASSWD_X)) {
mbl_sys_status_set(SYS_PASSWD_1, LEN_SYS_PASSWD_X, (uint8_t *)pwd);
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, (pwd + LEN_SYS_PASSWD_X), (pwd_len - LEN_SYS_PASSWD_X));
mbl_sys_status_set(SYS_PASSWD_2, LEN_SYS_PASSWD_X, buf);
} else if ((pwd_len > 2 * LEN_SYS_PASSWD_X) && (pwd_len <= 3 * LEN_SYS_PASSWD_X)) {
mbl_sys_status_set(SYS_PASSWD_1, LEN_SYS_PASSWD_X, (uint8_t *)pwd);
mbl_sys_status_set(SYS_PASSWD_2, LEN_SYS_PASSWD_X, (uint8_t *)(pwd + LEN_SYS_PASSWD_X));
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, (pwd + 2 * LEN_SYS_PASSWD_X), (pwd_len - 2 * LEN_SYS_PASSWD_X));
mbl_sys_status_set(SYS_PASSWD_3, LEN_SYS_PASSWD_X, buf);
} else if ((pwd_len > 3 * LEN_SYS_PASSWD_X) && (pwd_len <= 4 * LEN_SYS_PASSWD_X)){
mbl_sys_status_set(SYS_PASSWD_1, LEN_SYS_PASSWD_X, (uint8_t *)pwd);
mbl_sys_status_set(SYS_PASSWD_2, LEN_SYS_PASSWD_X, (uint8_t *)(pwd + LEN_SYS_PASSWD_X));
mbl_sys_status_set(SYS_PASSWD_3, LEN_SYS_PASSWD_X, (uint8_t *)(pwd + 2 * LEN_SYS_PASSWD_X));
sys_memset(buf, 0, sizeof(buf));
sys_memcpy(buf, (pwd + 3 * LEN_SYS_PASSWD_X), (pwd_len - 3 * LEN_SYS_PASSWD_X));
mbl_sys_status_set(SYS_PASSWD_4, LEN_SYS_PASSWD_X, buf);
} else {
return -2;
}
#ifdef CONFIG_IPV6_SUPPORT
if (ip->type == IPADDR_TYPE_V6)
mbl_sys_status_set(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&(ip->u_addr.ip6.addr));
else
mbl_sys_status_set(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&(ip->u_addr.ip4.addr));
#else
mbl_sys_status_set(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&(ip->addr));
#endif
return 0;
#else
return 0;
#endif
}
/*!
\brief load wifi netlink joined ap
\param[in] none
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_joined_ap_load(void)
{
#ifdef USE_MBL_API
uint8_t buf[LEN_SYS_SSID_X];
uint8_t *ssid_get = p_wifi_netlink->connect_info.ssid.ssid;
uint8_t *pwd_get = p_wifi_netlink->connect_info.passwd;
ip_addr_t ip_get;
int ret;
/* Get SSID */
sys_memset(ssid_get, 0, sizeof(p_wifi_netlink->connect_info.ssid.ssid));
ret = mbl_sys_status_get(SYS_SSID_1, LEN_SYS_SSID_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy(ssid_get, buf, LEN_SYS_SSID_X);
} else {
return -1;
}
ret = mbl_sys_status_get(SYS_SSID_2, LEN_SYS_SSID_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy((ssid_get + LEN_SYS_SSID_X), buf, LEN_SYS_SSID_X);
}
p_wifi_netlink->connect_info.ssid.ssid_len = strlen((char *)ssid_get);
DEBUG_INFO("Get ssid = %s len= %d\r\n", ssid_get, p_wifi_netlink->connect_info.ssid.ssid_len);
/* Get Password */
sys_memset(pwd_get, 0, sizeof(p_wifi_netlink->connect_info.passwd));
ret = mbl_sys_status_get(SYS_PASSWD_1, LEN_SYS_PASSWD_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy(pwd_get, buf, LEN_SYS_PASSWD_X);
}
ret = mbl_sys_status_get(SYS_PASSWD_2, LEN_SYS_PASSWD_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy((pwd_get + LEN_SYS_PASSWD_X), buf, LEN_SYS_PASSWD_X);
}
ret = mbl_sys_status_get(SYS_PASSWD_3, LEN_SYS_PASSWD_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy((pwd_get + 2 * LEN_SYS_PASSWD_X), buf, LEN_SYS_PASSWD_X);
}
ret = mbl_sys_status_get(SYS_PASSWD_4, LEN_SYS_PASSWD_X, buf);
if (ret == SYS_STATUS_FOUND_OK) {
sys_memcpy((pwd_get + 3 * LEN_SYS_PASSWD_X), buf, LEN_SYS_PASSWD_X);
}
DEBUG_INFO("Get pwd = %s\r\n", (char *)pwd_get);
/* TODO: shorten dhcp time */
#ifdef CONFIG_IPV6_SUPPORT
if (ip_get.type == IPADDR_TYPE_V6) {
IP6_ADDR(&ip_get.u_addr.ip6, 0, 0, 0, 0);
mbl_sys_status_get(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&ip_get.u_addr.ip6.addr);
DEBUG_INFO("Get ipaddr = %s\r\n", ip6addr_ntoa(&ip_get.u_addr.ip6));
} else {
ip_get.u_addr.ip4.addr = 0;
mbl_sys_status_get(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&ip_get.u_addr.ip4.addr);
DEBUG_INFO("Get ipaddr = "IP_FMT"\r\n", IP_ARG(ip_get.u_addr.ip4.addr));
}
#else
ip_get.addr = 0;
mbl_sys_status_get(SYS_IP_ADDR, LEN_SYS_IP_ADDR, (uint8_t *)&ip_get.addr);
DEBUG_INFO("Get ipaddr = "IP_FMT"\r\n", IP_ARG(ip_get.addr));
#endif
return 0;
#else
return 0;
#endif
}
/*!
\brief notify wifi netlink scan result
\param[in] result: pointer to the WIFI_SCAN_RESULT_E struction
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_scan_result_notify(WIFI_SCAN_RESULT_E *result)
{
#ifdef CONFIG_WIFI_MANAGEMENT_TASK
WIFI_MESSAGE_TYPE_E message;
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_NO_LINK_SCAN) {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
}
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_LINKED_SCAN) {
if (wifi_netif_is_ip_got()) {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED_CONFIGED;
} else {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED;
}
}
if (*result == WIFI_SCAN_RESULT_SUCC) {
p_wifi_netlink->scan_list_ready = 1;
message = WIFI_MESSAGE_NOTIFY_SCAN_RESULT_SUCC;
} else if (*result == WIFI_SCAN_RESULT_FAIL) {
message = WIFI_MESSAGE_NOTIFY_SCAN_RESULT_FAIL;
} else {
DEBUGPRINT("wifi netlink: unknown scan result\r\n");
return -1;
}
return wifi_management_forward_netlink_message(message);
#if 0
int ret = 0;
WIFI_SCAN_RESULT_E scan_result = *result;
wifi_management_event_t event;
if (scan_result == WIFI_SCAN_RESULT_SUCC) {
p_wifi_netlink->scan_list_ready = 1;
event = WIFI_MGMT_EVENT_SCAN_DONE;
} else if (scan_result == WIFI_SCAN_RESULT_FAIL) {
event = WIFI_MGMT_EVENT_SCAN_FAIL;
} else {
DEBUGPRINT("wifi netlink: unknown scan result\r\n");
return -1;
}
ret = eloop_event_send(event);
if (ret != 0) {
DEBUGPRINT("wifi netlink: notify scan result, os msg pool is empty, or task msg queue is full\r\n");
}
return ret;
#endif
#else
WIFI_SCAN_RESULT_E scan_result = *result;
WIFI_MESSAGE_TYPE_E msg_type;
int ret = 0;
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_NO_LINK_SCAN) {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
}
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_LINKED_SCAN) {
if (wifi_netif_is_ip_got()) {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED_CONFIGED;
} else {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED;
}
}
if (scan_result == WIFI_SCAN_RESULT_SUCC) {
p_wifi_netlink->scan_list_ready = 1;
msg_type = WIFI_MESSAGE_NOTIFY_SCAN_RESULT_SUCC;
} else if (scan_result == WIFI_SCAN_RESULT_FAIL) {
msg_type = WIFI_MESSAGE_NOTIFY_SCAN_RESULT_FAIL;
} else {
msg_type = WIFI_MESSAGE_NUM;
}
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
if ((p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_ROAMING) && wifi_roaming_task_tcb) {
ret = netlink_message_post(wifi_roaming_task_tcb, msg_type);
if (ret != 0) {
DEBUG_ERROR("wifi netlink: notify scan result, os msg pool is empty, or task msg queue is full\r\n");
}
} else {
ret = netlink_message_post(&console_task_tcb, msg_type);
if (ret != 0) {
DEBUG_ERROR("wifi netlink: notify scan result, os msg pool is empty, or task msg queue is full\r\n");
}
}
#else
ret = netlink_message_post(&console_task_tcb, msg_type);
if (ret != 0) {
DEBUG_ERROR("wifi netlink: notify scan result, os msg pool is empty, or task msg queue is full\r\n");
}
#endif /* CONFIG_WIFI_ROAMING_SUPPORT */
return ret;
#endif /* CONFIG_WIFI_MANAGEMENT_TASK */
}
/*!
\brief connect wifi netlink indicate
\param[in] connect_result: pointer to the wifi_connect_result struction
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_indicate_connect(struct wifi_connect_result *connect_result)
{
WIFI_MESSAGE_TYPE_E msg_type = WIFI_MESSAGE_NUM;
if (!p_wifi_netlink) {
DEBUG_ERROR("wifi netlink: indicate connect error, wifi_netlink not initialized!\r\n");
return -1;
}
DEBUG_INFO("wifi netlink: indicate connect, link_status is %d.\r\n", p_wifi_netlink->link_status);
if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_LINKING) {
switch (connect_result->result) {
case WIFI_CONN_RESULT_SUCC:
sys_memcpy(&p_wifi_netlink->connected_ap_info, connect_result, sizeof(struct wifi_connect_result));
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED;
msg_type = WIFI_MESSAGE_INDICATE_CONN_SUCCESS;
DEBUG_INFO("wifi netlink: connected to ap: %s\r\n", &connect_result->ssid.ssid);
break;
case WIFI_CONN_RESULT_AP_NOT_FOUND:
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
msg_type = WIFI_MESSAGE_INDICATE_CONN_NO_AP;
DEBUG_INFO("wifi netlink: indicate connect failed, couldn't find AP!\r\n");
break;
case WIFI_CONN_RESULT_AUTH_FAIL:
case WIFI_CONN_RESULT_ASSOC_FAIL:
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
msg_type = WIFI_MESSAGE_INDICATE_CONN_ASSOC_FAIL;
DEBUG_INFO("wifi netlink: indicate connect failed, assoctiate failed!\r\n");
break;
case WIFI_CONN_RESULT_HANDSHAKE_FAIL:
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
msg_type = WIFI_MESSAGE_INDICATE_CONN_HANDSHAKE_FAIL;
DEBUG_INFO("wifi netlink: indicate connect failed, wpa/wpa2 handshake failed !\r\n");
break;
default :
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
msg_type = WIFI_MESSAGE_INDICATE_CONN_FAIL;
DEBUG_INFO("wifi netlink: indicate connect failed, connect failed!\r\n");
break;
}
#ifndef CONFIG_WIFI_MANAGEMENT_TASK
if (netlink_message_post(&console_task_tcb, msg_type) != 0) {
DEBUG_ERROR("wifi netlink: indicate connect, os msg pool is empty, or task msg queue is full\r\n");
return -1;
}
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
} else if (p_wifi_netlink->link_status == WIFI_NETLINK_STATUS_ROAMING) {
switch (connect_result->result) {
case WIFI_CONN_RESULT_SUCC:
sys_memcpy(&p_wifi_netlink->connected_ap_info, connect_result, sizeof(struct wifi_connect_result));
msg_type = WIFI_MESSAGE_INDICATE_CONN_SUCCESS;
DEBUG_INFO("wifi netlink: roaming connected to ap: %s\r\n", &connect_result->ssid.ssid);
break;
case WIFI_CONN_RESULT_AP_NOT_FOUND:
msg_type = WIFI_MESSAGE_INDICATE_CONN_NO_AP;
DEBUG_INFO("wifi netlink: roaming indicate connect failed, couldn't find AP!\r\n");
break;
case WIFI_CONN_RESULT_AUTH_FAIL:
case WIFI_CONN_RESULT_ASSOC_FAIL:
msg_type = WIFI_MESSAGE_INDICATE_CONN_ASSOC_FAIL;
DEBUG_INFO("wifi netlink: roaming indicate connect failed, assoctiate failed!\r\n");
break;
case WIFI_CONN_RESULT_HANDSHAKE_FAIL:
msg_type = WIFI_MESSAGE_INDICATE_CONN_HANDSHAKE_FAIL;
DEBUG_INFO("wifi netlink: roaming indicate connect failed, wpa/wpa2 handshake failed !\r\n");
break;
case WIFI_CONN_RESULT_UNSPECIFIED:
default :
msg_type = WIFI_MESSAGE_INDICATE_CONN_FAIL;
DEBUG_INFO("wifi netlink: roaming indicate connect failed, connect failed!\r\n");
break;
}
if (wifi_roaming_task_tcb) {
if (netlink_message_post(wifi_roaming_task_tcb, msg_type) != 0) {
DEBUG_INFO("wifi netlink: indicate connect, os msg pool is empty, or task msg queue is full\r\n");
return -1;
}
}
#endif
#endif
}
#ifdef CONFIG_WIFI_MANAGEMENT_TASK
return wifi_management_forward_netlink_message(msg_type);
#else
return 0;
#endif
}
/*!
\brief disconnect wifi netlink indicate
\param[in] disc_info: pointer to the wifi_disconnect_info struction
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_indicate_disconnect(struct wifi_disconnect_info *disc_info)
{
WIFI_MESSAGE_TYPE_E msg_type;
struct wifi_connect_result *ap_info = &(p_wifi_netlink->connected_ap_info);
if (!p_wifi_netlink) {
DEBUG_ERROR("wifi netlink: indicate disconnect error, wifi_netlink not initialized!\r\n");
return -1;
}
p_wifi_netlink->discon_reason = disc_info->reason;
switch (disc_info->reason) {
case WIFI_DISCON_RECV_DEAUTH:
case WIFI_DISCON_RECV_DISASSOC:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_RECV_DEAUTH;
break;
case WIFI_DISCON_NO_BEACON:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_NO_BEACON;
break;
case WIFI_DISCON_AP_CHANGED:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_AP_CHANGED;
break;
case WIFI_DISCON_REKEY_FAIL:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_REKEY_FAIL;
break;
case WIFI_DISCON_MIC_FAIL:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_MIC_FAIL;
break;
case WIFI_DISCON_FROM_UI:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_FROM_UI;
break;
default:
msg_type = WIFI_MESSAGE_INDICATE_DISCON_UNSPECIFIED;
break;
}
DEBUG_INFO("wifi netlink: disconnect reason %d, msg type %d\r\n", disc_info->reason, msg_type);
switch (p_wifi_netlink->link_status) {
case WIFI_NETLINK_STATUS_NO_LINK:
case WIFI_NETLINK_STATUS_NO_LINK_SCAN:
break;
case WIFI_NETLINK_STATUS_LINKING:
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
#ifndef CONFIG_WIFI_MANAGEMENT_TASK
if (netlink_message_post(&console_task_tcb, msg_type) != 0) {
DEBUG_ERROR("wifi netlink: indicate disconnect, os msg pool is empty, or task msg queue is full\r\n");
return -1;
}
#endif
break;
#if defined(CONFIG_WIFI_ROAMING_SUPPORT) && !defined(CONFIG_WIFI_MANAGEMENT_TASK)
case WIFI_NETLINK_STATUS_LINKED:
case WIFI_NETLINK_STATUS_LINKED_SCAN:
case WIFI_NETLINK_STATUS_LINKED_CONFIGED:
if (disc_info->reason != WIFI_DISCON_FROM_UI) {
if ((disc_info->ssid.ssid_len == ap_info->ssid.ssid_len) &&
(!sys_memcmp(&disc_info->ssid.ssid, ap_info->ssid.ssid, disc_info->ssid.ssid_len))) {
DEBUG_INFO("wifi netlink: start roaming...\r\n");
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_ROAMING;
wifi_netif_stop_dhcp();
wifi_roaming_task_tcb = sys_task_create(NULL, (const uint8_t *)"wifi_roaming_task", NULL, WIFI_ROAMING_TASK_STK_SIZE,
WIFI_ROAMING_QUEUE_SIZE, WIFI_ROAMING_TASK_PRIO, (task_func_t)wifi_roaming_task_func, NULL);
} else {
DEBUG_INFO("wifi netlink: indicate disconnect, ssid not match, ignored!\r\n");
DEBUG_INFO("disconnect ssid %s len %d connected ssid %s len %d\r\n", &disc_info->ssid.ssid, disc_info->ssid.ssid_len,
ap_info->ssid.ssid, ap_info->ssid.ssid_len);
}
} else {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
}
break;
case WIFI_NETLINK_STATUS_ROAMING:
DEBUG_INFO("wifi netlink: roaming state, receive message %d\r\n", msg_type);
if (wifi_roaming_task_tcb) {
if (netlink_message_post(wifi_roaming_task_tcb, msg_type) != 0) {
DEBUG_ERROR("wifi netlink: indicate disconnect, post netlink message failed.\r\n");
return -1;
}
}
break;
#else
case WIFI_NETLINK_STATUS_LINKED:
case WIFI_NETLINK_STATUS_LINKED_SCAN:
case WIFI_NETLINK_STATUS_LINKED_CONFIGED:
if ((disc_info->ssid.ssid_len == ap_info->ssid.ssid_len) &&
(!sys_memcmp(&disc_info->ssid.ssid, ap_info->ssid.ssid, disc_info->ssid.ssid_len))) {
sys_memset(&p_wifi_netlink->connected_ap_info, 0, sizeof(struct wifi_connect_result));
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
wifi_netif_stop_dhcp();
DEBUG_INFO("wifi netlink: indicate disconnect, disconnected with ap: %s\r\n", &disc_info->ssid.ssid);
} else {
DEBUG_INFO("wifi netlink: indicate disconnect, ssid not match, ignored!\r\n");
DEBUG_INFO("disconnect ssid %s len %d connected ssid %s len %d\r\n", &disc_info->ssid.ssid, disc_info->ssid.ssid_len,
ap_info->ssid.ssid, ap_info->ssid.ssid_len);
}
#ifndef CONFIG_WIFI_MANAGEMENT_TASK
if (netlink_message_post(&console_task_tcb, msg_type) != 0) {
DEBUG_INFO("wifi netlink: indicate disconnect, os msg pool is empty, or task msg queue is full\r\n");
return -1;
}
#endif
break;
#endif
default:
break;
}
#ifdef CONFIG_WIFI_MANAGEMENT_TASK
return wifi_management_forward_netlink_message(msg_type);
#else
return 0;
#endif
}
/*!
\brief get wifi bandwith
\param[in] none
\param[out] bw : get supported bandwidth
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_bw_get(uint32_t *bw)
{
return wifi_ops_entry.wifi_get_bw(bw);
}
/*!
\brief set wifi bandwith
\param[in] bw : set supported bandwidth
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
int wifi_netlink_bw_set(uint32_t bw)
{
return wifi_ops_entry.wifi_set_bw(bw);
}
#ifdef CONFIG_WIFI_ROAMING_SUPPORT
/*!
\brief terminate roaming task
\param[in] none
\param[out] none
\retval none
*/
static void terminate_roaming_task(void)
{
while (is_roaming == _TRUE) {
if (wifi_roaming_task_tcb) {
netlink_message_post(wifi_roaming_task_tcb, WIFI_MESSAGE_TASK_TERMINATE);
DEBUG_INFO("wifi netlink: roaming task terminating...\r\n");
}
sys_ms_sleep(100);
}
}
/*!
\brief roaming scan
\param[in] scan_req: pointer to the wifi_scan_req struction
\param[out] none
\retval 0 if succeeded, -1 otherwise
*/
static int roaming_scan(struct wifi_scan_req *scan_req)
{
int waiting_terminated = 0;
WIFI_MESSAGE_TYPE_E msg_type;
if (wifi_ops_entry.wifi_scan_proc_func(scan_req) == 1) {
do {
if (sys_task_wait(WIFI_SCAN_WAITING_TIME, &msg_type) == OS_OK) {
if (msg_type == WIFI_MESSAGE_NOTIFY_SCAN_RESULT_SUCC
|| msg_type == WIFI_MESSAGE_NOTIFY_SCAN_RESULT_FAIL) {
if (waiting_terminated)
return -1;
else
break;
} else if (msg_type == WIFI_MESSAGE_TASK_TERMINATE) {
waiting_terminated = 1;
}
} else { /* Waiting timeout */
return -1;
}
} while (1);
}
return 0;
}
/*!
\brief wifi roaming task function
\param[in] p_arg: pointer to the argument
\param[out] none
\retval none
*/
static void wifi_roaming_task_func(void *p_arg)
{
struct wifi_ssid_config *connect_info = &(p_wifi_netlink->connect_info);
WIFI_MESSAGE_TYPE_E msg_type;
int retry_count = 0;
int dhcp_retry = 0;
int status = -1;
struct wifi_disconnect_req disconnect_info;
struct wifi_scan_req scan_req;
is_roaming = _TRUE;
DEBUG_INFO("wifi netlink: roaming ssid %s\r\n", connect_info->ssid.ssid);
// DEBUGPRINT("wifi netlink: roaming password %s\r\n", (char *)connect_info->passwd);
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;
/* Force scanning since AP may change channel or other options. */
if (p_wifi_netlink->discon_reason == WIFI_DISCON_AP_CHANGED
|| p_wifi_netlink->discon_reason == WIFI_DISCON_NO_BEACON
|| p_wifi_netlink->discon_reason == WIFI_DISCON_RECV_DEAUTH) {
if (roaming_scan(&scan_req) == -1)
goto Exit;
}
while ((retry_count < ROAMING_RETRY_LIMIT) && (status != 0)) {
DEBUG_INFO("Connect Retry[%d]: last status is %d.\r\n", retry_count, status);
status = -1;
sys_task_msg_flush(NULL);
/* Force scanning if the first linking retry failed. */
if (retry_count > 1) {
if (roaming_scan(&scan_req) == -1)
goto Exit;
}
wifi_ops_entry.wifi_connect_req_func(connect_info);
do {
if (sys_task_wait(WIFI_CONNECT_WAITING_TIME, &msg_type) == OS_OK) {
switch (msg_type) {
case WIFI_MESSAGE_INDICATE_CONN_SUCCESS:
DEBUG_INFO("wifi netlink: roaming connect successfully! Start DHCP.\r\n");
while (dhcp_retry++ < DHCP_RETRY_LIMIT) {
wifi_netif_start_dhcp();
if (TRUE == wifi_netif_polling_dhcp()) {
wifi_netlink_ipaddr_set((uint8_t *)wifi_netif_get_ip());
DEBUG_INFO("wifi netlink: ip configured, IP: %s\r\n", ip_ntoa(wifi_netif_get_ip()));
status = 0;
break;
} else {
DEBUG_INFO("wifi netlink: get ip timeout!\r\n");
wifi_netif_stop_dhcp();
}
}
if (status != 0) {
sys_memcpy(&disconnect_info.ssid, connect_info->ssid.ssid, sizeof(disconnect_info.ssid));
wifi_ops_entry.wifi_disconnect_req_func(&disconnect_info);
status = 7;
}
dhcp_retry = 0;
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:
DEBUG_INFO("wifi netlink: roaming connect failed, event is %d!\r\n", msg_type);
status = 2;
break;
case WIFI_MESSAGE_INDICATE_DISCON_RECV_DEAUTH:
DEBUG_INFO("wifi netlink: roaming connect failed, receive Deauth or Disassoc.\r\n");
status = 3;
break;
case WIFI_MESSAGE_TASK_TERMINATE:
case WIFI_MESSAGE_INDICATE_DISCON_FROM_UI:
DEBUG_INFO("wifi netlink: roaming task terminated.\r\n");
sys_memcpy(&disconnect_info.ssid, connect_info->ssid.ssid, sizeof(disconnect_info.ssid));
wifi_ops_entry.wifi_disconnect_req_func(&disconnect_info);
retry_count = ROAMING_RETRY_LIMIT;
status = 4;
break;
case WIFI_MESSAGE_NOTIFY_SCAN_RESULT_SUCC:
case WIFI_MESSAGE_NOTIFY_SCAN_RESULT_FAIL:
default:
break;
}
} else {
DEBUG_INFO("wifi netlink: romaing connect timeout or error\r\n");
status = 6;
break;
}
} while (status < 0);
retry_count++;
}
Exit:
if (status != 0) {
sys_memset(&p_wifi_netlink->connected_ap_info, 0, sizeof(struct wifi_connect_result));
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_NO_LINK;
wifi_netif_stop_dhcp();
DEBUG_INFO("wifi netlink: roaming failed, status is %d.\r\n", status);
} else {
p_wifi_netlink->link_status = WIFI_NETLINK_STATUS_LINKED;
DEBUG_INFO("wifi netlink: roaming succeeded.\r\n");
}
is_roaming = _FALSE;
wifi_roaming_task_tcb = NULL;
sys_task_delete(NULL);
}
#endif
/*!
\brief callbak function for softap sta delete
\param[in] mac_addr: the mac addr of delete sta
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_indicate_softap_sta_del(uint8_t *mac_addr)
{
#ifdef CONFIG_SOFTAP_CALLBACK_ENABLED
uint32_t ip_addr;
ip_addr = softap_find_ipaddr_by_macaddr(mac_addr);
/* TODO */
printf("this is callback for softap sta delete\r\n");
printf("the mac addr of delete sta is "MAC_FMT"\r\n", MAC_ARG(mac_addr));
printf("the ip addr of delete sta is "IP_FMT"\r\n", IP_ARG(ip_addr));
#endif
return 0;
}
/*!
\brief callbak function for softap sta add
\param[in] mac_addr: the mac addr of add sta
\param[in] ip_addr: the ip addr(ipv4) of add sta
\param[out] none
\retval 0 if succeeded
*/
int wifi_netlink_indicate_softap_sta_add(uint8_t *mac_addr, uint32_t ip_addr)
{
#ifdef CONFIG_SOFTAP_CALLBACK_ENABLED
/* TODO */
printf("this is callback for softap sta add\r\n");
printf("the mac addr of add sta is "MAC_FMT"\r\n", MAC_ARG(mac_addr));
printf("the ip addr of add sta is "IP_FMT"\r\n", IP_ARG(ip_addr));
#endif
return 0;
}