469 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			469 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2023, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2018-08-06     tyx          the first version | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <rtthread.h>
 | ||
|  | #include <wlan_cfg.h>
 | ||
|  | 
 | ||
|  | #define DBG_TAG "WLAN.cfg"
 | ||
|  | #ifdef RT_WLAN_CFG_DEBUG
 | ||
|  | #define DBG_LVL DBG_LOG
 | ||
|  | #else
 | ||
|  | #define DBG_LVL DBG_INFO
 | ||
|  | #endif /* RT_WLAN_CFG_DEBUG */
 | ||
|  | #include <rtdbg.h>
 | ||
|  | 
 | ||
|  | #ifdef RT_WLAN_CFG_ENABLE
 | ||
|  | 
 | ||
|  | #define WLAN_CFG_LOCK()      (rt_mutex_take(&cfg_mutex, RT_WAITING_FOREVER))
 | ||
|  | #define WLAN_CFG_UNLOCK()    (rt_mutex_release(&cfg_mutex))
 | ||
|  | 
 | ||
|  | #if RT_WLAN_CFG_INFO_MAX < 1
 | ||
|  | #error "The minimum configuration is 1"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | struct cfg_save_info_head | ||
|  | { | ||
|  |     rt_uint32_t magic; | ||
|  |     rt_uint32_t len; | ||
|  |     rt_uint32_t num; | ||
|  |     rt_uint32_t crc; | ||
|  | }; | ||
|  | 
 | ||
|  | struct rt_wlan_cfg_des | ||
|  | { | ||
|  |     rt_uint32_t num; | ||
|  |     struct rt_wlan_cfg_info *cfg_info; | ||
|  | }; | ||
|  | 
 | ||
|  | static struct rt_wlan_cfg_des *cfg_cache; | ||
|  | static const struct rt_wlan_cfg_ops *cfg_ops; | ||
|  | static struct rt_mutex cfg_mutex; | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * CRC16_CCITT | ||
|  |  */ | ||
|  | static rt_uint16_t rt_wlan_cal_crc(rt_uint8_t *buff, int len) | ||
|  | { | ||
|  |     rt_uint16_t wCRCin = 0x0000; | ||
|  |     rt_uint16_t wCPoly = 0x1021; | ||
|  |     rt_uint8_t  wChar = 0; | ||
|  | 
 | ||
|  |     while (len--) | ||
|  |     { | ||
|  |         int i; | ||
|  | 
 | ||
|  |         wChar = *(buff++); | ||
|  |         wCRCin ^= (wChar << 8); | ||
|  | 
 | ||
|  |         for (i = 0; i < 8; i++) | ||
|  |         { | ||
|  |             if (wCRCin & 0x8000) | ||
|  |                 wCRCin = (wCRCin << 1) ^ wCPoly; | ||
|  |             else | ||
|  |                 wCRCin = wCRCin << 1; | ||
|  |         } | ||
|  |     } | ||
|  |     return wCRCin; | ||
|  | } | ||
|  | 
 | ||
|  | void rt_wlan_cfg_init(void) | ||
|  | { | ||
|  |     /* init cache memory */ | ||
|  |     if (cfg_cache == RT_NULL) | ||
|  |     { | ||
|  |         cfg_cache = rt_malloc(sizeof(struct rt_wlan_cfg_des)); | ||
|  |         if (cfg_cache != RT_NULL) | ||
|  |         { | ||
|  |             rt_memset(cfg_cache, 0, sizeof(struct rt_wlan_cfg_des)); | ||
|  |         } | ||
|  |         /* init mutex lock */ | ||
|  |         rt_mutex_init(&cfg_mutex, "wlan_cfg", RT_IPC_FLAG_PRIO); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | void rt_wlan_cfg_set_ops(const struct rt_wlan_cfg_ops *ops) | ||
|  | { | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     /* save ops pointer */ | ||
|  |     cfg_ops = ops; | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  | } | ||
|  | 
 | ||
|  | /* save config data */ | ||
|  | rt_err_t rt_wlan_cfg_cache_save(void) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  |     struct cfg_save_info_head *info_pkg; | ||
|  |     int len = 0; | ||
|  | 
 | ||
|  |     if ((cfg_ops == RT_NULL) || (cfg_ops->write_cfg == RT_NULL)) | ||
|  |         return RT_EOK; | ||
|  | 
 | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     len = sizeof(struct cfg_save_info_head) + sizeof(struct rt_wlan_cfg_info) * cfg_cache->num; | ||
|  |     info_pkg = rt_malloc(len); | ||
|  |     if (info_pkg == RT_NULL) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -RT_ENOMEM; | ||
|  |     } | ||
|  |     info_pkg->magic = RT_WLAN_CFG_MAGIC; | ||
|  |     info_pkg->len = len; | ||
|  |     info_pkg->num = cfg_cache->num; | ||
|  |     /* CRC */ | ||
|  |     info_pkg->crc = rt_wlan_cal_crc((rt_uint8_t *)cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * cfg_cache->num); | ||
|  |     rt_memcpy(((rt_uint8_t *)info_pkg) + sizeof(struct cfg_save_info_head), | ||
|  |               cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * cfg_cache->num); | ||
|  |     if (cfg_ops->write_cfg(info_pkg, len) != len) | ||
|  |         err =  -RT_ERROR; | ||
|  |     rt_free(info_pkg); | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | rt_err_t rt_wlan_cfg_cache_refresh(void) | ||
|  | { | ||
|  |     int len = 0, i, j; | ||
|  |     struct cfg_save_info_head *head; | ||
|  |     void *data; | ||
|  |     struct rt_wlan_cfg_info *t_info, *cfg_info; | ||
|  |     rt_uint32_t crc; | ||
|  |     rt_bool_t equal_flag; | ||
|  | 
 | ||
|  |     /* cache is full! exit */ | ||
|  |     if (cfg_cache == RT_NULL || cfg_cache->num >= RT_WLAN_CFG_INFO_MAX) | ||
|  |         return -RT_ERROR; | ||
|  | 
 | ||
|  |     /* check callback */ | ||
|  |     if ((cfg_ops == RT_NULL) || | ||
|  |             (cfg_ops->get_len == RT_NULL) || | ||
|  |             (cfg_ops->read_cfg == RT_NULL)) | ||
|  |         return -RT_ERROR; | ||
|  | 
 | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     /* get data len */ | ||
|  |     if ((len = cfg_ops->get_len()) <= 0) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -RT_ERROR; | ||
|  |     } | ||
|  | 
 | ||
|  |     head = rt_malloc(len); | ||
|  |     if (head == RT_NULL) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -RT_ERROR; | ||
|  |     } | ||
|  |     /* get data */ | ||
|  |     if (cfg_ops->read_cfg(head, len) != len) | ||
|  |     { | ||
|  |         rt_free(head); | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -RT_ERROR; | ||
|  |     } | ||
|  |     /* get config */ | ||
|  |     data = ((rt_uint8_t *)head) + sizeof(struct cfg_save_info_head); | ||
|  |     crc = rt_wlan_cal_crc((rt_uint8_t *)data, len - sizeof(struct cfg_save_info_head)); | ||
|  |     LOG_D("head->magic:0x%08x  RT_WLAN_CFG_MAGIC:0x%08x", head->magic, RT_WLAN_CFG_MAGIC); | ||
|  |     LOG_D("head->len:%d len:%d", head->len, len); | ||
|  |     LOG_D("head->num:%d num:%d", head->num, (len - sizeof(struct cfg_save_info_head)) / sizeof(struct rt_wlan_cfg_info)); | ||
|  |     LOG_D("hred->crc:0x%04x crc:0x%04x", head->crc, crc); | ||
|  |     /* check */ | ||
|  |     if ((head->magic != RT_WLAN_CFG_MAGIC) || | ||
|  |             (head->len != len) || | ||
|  |             (head->num != (len - sizeof(struct cfg_save_info_head)) / sizeof(struct rt_wlan_cfg_info)) || | ||
|  |             (head->crc != crc)) | ||
|  |     { | ||
|  |         rt_free(head); | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -RT_ERROR; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* remove duplicate config */ | ||
|  |     cfg_info = (struct rt_wlan_cfg_info *)data; | ||
|  |     for (i = 0; i < head->num; i++) | ||
|  |     { | ||
|  |         equal_flag = RT_FALSE; | ||
|  |         for (j = 0; j < cfg_cache->num; j++) | ||
|  |         { | ||
|  |             if ((cfg_cache->cfg_info[j].info.ssid.len == cfg_info[i].info.ssid.len) && | ||
|  |                     (rt_memcmp(&cfg_cache->cfg_info[j].info.ssid.val[0], &cfg_info[i].info.ssid.val[0], | ||
|  |                                cfg_cache->cfg_info[j].info.ssid.len) == 0) && | ||
|  |                     (rt_memcmp(&cfg_cache->cfg_info[j].info.bssid[0], &cfg_info[i].info.bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0)) | ||
|  |             { | ||
|  |                 equal_flag = RT_TRUE; | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (cfg_cache->num >= RT_WLAN_CFG_INFO_MAX) | ||
|  |         { | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (equal_flag == RT_FALSE) | ||
|  |         { | ||
|  |             t_info = rt_realloc(cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num + 1)); | ||
|  |             if (t_info == RT_NULL) | ||
|  |             { | ||
|  |                 rt_free(head); | ||
|  |                 WLAN_CFG_UNLOCK(); | ||
|  |                 return -RT_ERROR; | ||
|  |             } | ||
|  |             cfg_cache->cfg_info = t_info; | ||
|  |             cfg_cache->cfg_info[cfg_cache->num] = cfg_info[i]; | ||
|  |             cfg_cache->num ++; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     rt_free(head); | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_wlan_cfg_get_num(void) | ||
|  | { | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     return cfg_cache->num; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_wlan_cfg_read(struct rt_wlan_cfg_info *cfg_info, int num) | ||
|  | { | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     if ((cfg_info == RT_NULL) || (num <= 0)) | ||
|  |         return 0; | ||
|  |     /* copy data */ | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     num = cfg_cache->num > num ? num : cfg_cache->num; | ||
|  |     rt_memcpy(&cfg_cache->cfg_info[0], cfg_info, sizeof(struct rt_wlan_cfg_info) * num); | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  | 
 | ||
|  |     return num; | ||
|  | } | ||
|  | 
 | ||
|  | rt_err_t rt_wlan_cfg_save(struct rt_wlan_cfg_info *cfg_info) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  |     struct rt_wlan_cfg_info *t_info; | ||
|  |     int idx = -1, i = 0; | ||
|  | 
 | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     /* parameter check */ | ||
|  |     if ((cfg_info == RT_NULL) || (cfg_info->info.ssid.len == 0)) | ||
|  |     { | ||
|  |         return -RT_EINVAL; | ||
|  |     } | ||
|  |     /* if (iteam == cache) exit */ | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     for (i = 0; i < cfg_cache->num; i++) | ||
|  |     { | ||
|  |         if ((cfg_cache->cfg_info[i].info.ssid.len == cfg_info->info.ssid.len) && | ||
|  |                 (rt_memcmp(&cfg_cache->cfg_info[i].info.ssid.val[0], &cfg_info->info.ssid.val[0], | ||
|  |                            cfg_cache->cfg_info[i].info.ssid.len) == 0) && | ||
|  |                 (rt_memcmp(&cfg_cache->cfg_info[i].info.bssid[0], &cfg_info->info.bssid[0], RT_WLAN_BSSID_MAX_LENGTH) == 0)) | ||
|  |         { | ||
|  |             idx = i; | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if ((idx == 0) && (cfg_cache->cfg_info[i].key.len == cfg_info->key.len) && | ||
|  |             (rt_memcmp(&cfg_cache->cfg_info[i].key.val[0], &cfg_info->key.val[0], cfg_info->key.len) == 0)) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return RT_EOK; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* not find iteam with cache, Add iteam to the head   */ | ||
|  |     if ((idx == -1) && (cfg_cache->num < RT_WLAN_CFG_INFO_MAX)) | ||
|  |     { | ||
|  |         t_info = rt_realloc(cfg_cache->cfg_info, sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num + 1)); | ||
|  |         if (t_info == RT_NULL) | ||
|  |         { | ||
|  |             WLAN_CFG_UNLOCK(); | ||
|  |             return -RT_ENOMEM; | ||
|  |         } | ||
|  |         cfg_cache->cfg_info = t_info; | ||
|  |         cfg_cache->num ++; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* move cache info */ | ||
|  |     i = (i >= RT_WLAN_CFG_INFO_MAX ? RT_WLAN_CFG_INFO_MAX - 1 : i); | ||
|  |     for (; i; i--) | ||
|  |     { | ||
|  |         cfg_cache->cfg_info[i] = cfg_cache->cfg_info[i - 1]; | ||
|  |     } | ||
|  |     /* add iteam to head */ | ||
|  |     cfg_cache->cfg_info[i] = *cfg_info; | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  | 
 | ||
|  |     /* save info to flash */ | ||
|  |     err = rt_wlan_cfg_cache_save(); | ||
|  | 
 | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_wlan_cfg_read_index(struct rt_wlan_cfg_info *cfg_info, int index) | ||
|  | { | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     if ((cfg_info == RT_NULL) || (index < 0)) | ||
|  |         return 0; | ||
|  | 
 | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     if (index >= cfg_cache->num) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return 0; | ||
|  |     } | ||
|  |     /* copy data */ | ||
|  |     *cfg_info = cfg_cache->cfg_info[index]; | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  |     return 1; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_wlan_cfg_delete_index(int index) | ||
|  | { | ||
|  |     struct rt_wlan_cfg_info *cfg_info; | ||
|  |     int i; | ||
|  | 
 | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     if (index < 0) | ||
|  |         return -1; | ||
|  | 
 | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     if (index >= cfg_cache->num) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     /* malloc new mem */ | ||
|  |     cfg_info = rt_malloc(sizeof(struct rt_wlan_cfg_info) * (cfg_cache->num - 1)); | ||
|  |     if (cfg_info == RT_NULL) | ||
|  |     { | ||
|  |         WLAN_CFG_UNLOCK(); | ||
|  |         return -1; | ||
|  |     } | ||
|  |     /* copy data to new mem */ | ||
|  |     for (i = 0; i < cfg_cache->num; i++) | ||
|  |     { | ||
|  |         if (i < index) | ||
|  |         { | ||
|  |             cfg_info[i] = cfg_cache->cfg_info[i]; | ||
|  |         } | ||
|  |         else if (i > index) | ||
|  |         { | ||
|  |             cfg_info[i - 1] = cfg_cache->cfg_info[i]; | ||
|  |         } | ||
|  |     } | ||
|  |     rt_free(cfg_cache->cfg_info); | ||
|  |     cfg_cache->cfg_info = cfg_info; | ||
|  |     cfg_cache->num --; | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | void rt_wlan_cfg_delete_all(void) | ||
|  | { | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     /* delete all iteam */ | ||
|  |     WLAN_CFG_LOCK(); | ||
|  |     cfg_cache->num = 0; | ||
|  |     rt_free(cfg_cache->cfg_info); | ||
|  |     cfg_cache->cfg_info = RT_NULL; | ||
|  |     WLAN_CFG_UNLOCK(); | ||
|  | } | ||
|  | 
 | ||
|  | void rt_wlan_cfg_dump(void) | ||
|  | { | ||
|  |     int index = 0; | ||
|  |     struct rt_wlan_info *info; | ||
|  |     struct rt_wlan_key *key; | ||
|  |     char *security; | ||
|  | 
 | ||
|  |     rt_wlan_cfg_init(); | ||
|  | 
 | ||
|  |     rt_kprintf("             SSID                           PASSWORD                   MAC            security     chn\n"); | ||
|  |     rt_kprintf("------------------------------- ------------------------------- -----------------  --------------  ---\n"); | ||
|  |     for (index = 0; index < cfg_cache->num; index ++) | ||
|  |     { | ||
|  |         info = &cfg_cache->cfg_info[index].info; | ||
|  |         key = &cfg_cache->cfg_info[index].key; | ||
|  | 
 | ||
|  |         if (info->ssid.len) | ||
|  |             rt_kprintf("%-32.32s", &info->ssid.val[0]); | ||
|  |         else | ||
|  |             rt_kprintf("%-32.32s", " "); | ||
|  | 
 | ||
|  |         if (key->len) | ||
|  |             rt_kprintf("%-32.32s", &key->val[0]); | ||
|  |         else | ||
|  |             rt_kprintf("%-32.32s", " "); | ||
|  | 
 | ||
|  |         rt_kprintf("%02x:%02x:%02x:%02x:%02x:%02x  ", | ||
|  |                    info->bssid[0], | ||
|  |                    info->bssid[1], | ||
|  |                    info->bssid[2], | ||
|  |                    info->bssid[3], | ||
|  |                    info->bssid[4], | ||
|  |                    info->bssid[5] | ||
|  |                   ); | ||
|  |         switch (info->security) | ||
|  |         { | ||
|  |         case SECURITY_OPEN: | ||
|  |             security = "OPEN"; | ||
|  |             break; | ||
|  |         case SECURITY_WEP_PSK: | ||
|  |             security = "WEP_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WEP_SHARED: | ||
|  |             security = "WEP_SHARED"; | ||
|  |             break; | ||
|  |         case SECURITY_WPA_TKIP_PSK: | ||
|  |             security = "WPA_TKIP_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WPA_AES_PSK: | ||
|  |             security = "WPA_AES_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WPA2_AES_PSK: | ||
|  |             security = "WPA2_AES_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WPA2_TKIP_PSK: | ||
|  |             security = "WPA2_TKIP_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WPA2_MIXED_PSK: | ||
|  |             security = "WPA2_MIXED_PSK"; | ||
|  |             break; | ||
|  |         case SECURITY_WPS_OPEN: | ||
|  |             security = "WPS_OPEN"; | ||
|  |             break; | ||
|  |         case SECURITY_WPS_SECURE: | ||
|  |             security = "WPS_SECURE"; | ||
|  |             break; | ||
|  |         default: | ||
|  |             security = "UNKNOWN"; | ||
|  |             break; | ||
|  |         } | ||
|  |         rt_kprintf("%-14.14s  ", security); | ||
|  |         rt_kprintf("%3d    \n", info->channel); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | #endif
 |