SmartAudio/package/allwinner/wifimanager/src/network_manager.c

690 lines
17 KiB
C
Executable File

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/time.h>
#include <uvdbus/log.h>
#include "wifi_event.h"
#include "network_manager.h"
#include "wifi_intf.h"
#include "wifi.h"
#include "tool.h"
#define WAITING_CLK_COUNTS 50
#define SSID_LEN 512
#define UTF8_BYTES_MAX 4096
#define UTF8_MULTI_BYTES_MASK 0x80
#define ESCAP_CHAR_ASCII '\\'
#define DQUOT_CHAR_ASCII '\"'
#define QUOT_CHAR_ASCII '\''
/* scan thread */
static pthread_t scan_thread_id;
static int scan_running = 0;
static int scan_terminating = 0;
static pthread_mutex_t scan_mutex;
static pthread_cond_t scan_cond;
static int scan_pause = 0;
static int scan_error = 0;
static int do_scan_flag = 1;
/* run scan immediately */
static pthread_mutex_t thread_run_mutex;
static pthread_cond_t thread_run_cond;
/*stop restart scan*/
static pthread_mutex_t scan_stop_restart_mutex;
static pthread_cond_t scan_stop_restart_cond;
/* store scan results */
static char scan_results[SCAN_BUF_LEN];
static int scan_results_len = 0;
static int scan_completed = 0;
enum wpa_states wpa_supplicant_state_convert(char *str)
{
if(!strncmp(str,"DISCONNECTED",16)){
return WPA_DISCONNECTED;
}
if(!strncmp(str,"INTERFACE_DISABLED",22)){
return WPA_INTERFACE_DISABLED;
}
if(!strncmp(str,"INACTIVE",12)){
return WPA_INACTIVE;
}
if(!strncmp(str,"SCANNING",12)){
return WPA_SCANNING;
}
if(!strncmp(str,"AUTHENTICATING",18)){
return WPA_AUTHENTICATING;
}
if(!strncmp(str,"ASSOCIATED",14)){
return WPA_ASSOCIATED;
}
if(!strncmp(str,"4WAY_HANDSHAKE",19)){
return WPA_4WAY_HANDSHAKE;
}
if(!strncmp(str,"GROUP_HANDSHAKE",19)){
return WPA_GROUP_HANDSHAKE;
}
if(!strncmp(str,"COMPLETED",13)){
return WPA_COMPLETED;
}
if(!strncmp(str,"DISCONNECTED",16)){
return WPA_DISCONNECTED;
}
return WPA_UNKNOWN;
}
static const char * wpa_supplicant_state_txt(enum wpa_states state)
{
switch (state) {
case WPA_DISCONNECTED:
return "DISCONNECTED";
case WPA_INACTIVE:
return "INACTIVE";
case WPA_INTERFACE_DISABLED:
return "INTERFACE_DISABLED";
case WPA_SCANNING:
return "SCANNING";
case WPA_AUTHENTICATING:
return "AUTHENTICATING";
case WPA_ASSOCIATING:
return "ASSOCIATING";
case WPA_ASSOCIATED:
return "ASSOCIATED";
case WPA_4WAY_HANDSHAKE:
return "4WAY_HANDSHAKE";
case WPA_GROUP_HANDSHAKE:
return "GROUP_HANDSHAKE";
case WPA_COMPLETED:
return "COMPLETED";
default:
return "UNKNOWN";
}
}
void print_wpa_status(struct wpa_status *wpa_sta)
{
LOG_EX(LOG_Debug, "obtained wpa_supplicant status,as follow:\n");
LOG_EX(LOG_Debug, "==============================\n");
if(wpa_sta->id >= 0)
LOG_EX(LOG_Debug, "id:%d\n",wpa_sta->id);
if(wpa_sta->bssid)
LOG_EX(LOG_Debug, "bssid:%s\n",wpa_sta->bssid);
if(wpa_sta->freq >=0)
LOG_EX(LOG_Debug, "freq:%d\n",wpa_sta->freq);
if(wpa_sta->ssid)
LOG_EX(LOG_Debug, "ssid:%s\n",wpa_sta->ssid);
if(wpa_sta->wpa_state)
LOG_EX(LOG_Debug, "wpa_state:%s\n",wpa_supplicant_state_txt(wpa_sta->wpa_state));
if(wpa_sta->ip_address)
LOG_EX(LOG_Debug, "ip_address:%s\n",wpa_sta->ip_address);
if(wpa_sta->key_mgmt)
LOG_EX(LOG_Debug, "key_mgmt:%s\n",wpa_sta->key_mgmt);
if(wpa_sta->mac_address)
LOG_EX(LOG_Debug, "mac_address:%s\n",wpa_sta->mac_address);
LOG_EX(LOG_Debug, "==============================\n");
}
static char *strstr_wpa(const char *src,const char *obj,
const char pre_str[2],int pst_len)
{
const char *p=src;
int length;
int i=0;
if(src == NULL || obj == NULL || pre_str ==NULL){
LOG_EX(LOG_Debug, "src or obj or pre_str is NULL");
return NULL;
}
if(pst_len > strlen(pre_str)){
LOG_EX(LOG_Debug, "pst_len length is illegal");
return NULL;
}
length = strlen(obj);
for(;;p++,i++){
p=strchr(p,*obj);
if(p == NULL){
LOG_EX(LOG_Debug, "%s is not exist",obj);
return NULL;
}
if(strncmp(p,obj,length) == 0){
if(i > 1 && *(p-1) != pre_str[0] && *(p-1) != pre_str[1]){
return (char*)p;
}
}
}
}
static int search_wpa_string(const char *src,const char *obj,int max,char *get_str)
{
int i=0;
const char *sptr = NULL;
const char *pnext = NULL;
if(obj == NULL || src == NULL){
wmg_printf(MSG_DEBUG,"src or obj is NULL");
return 0;
}
if(!strncmp("id=",obj,3)){
sptr = strstr_wpa(src,obj,"su",2);
}else if(!strncmp("ssid=",obj,5)){
sptr = strstr_wpa(src,obj,"bb",2);
}else if(!strncmp("address=",obj,8)){
sptr = strstr_wpa(src,obj,"__",2);
}else{
sptr = strstr(src, obj);
}
if(sptr !=NULL){
pnext=sptr+strlen(obj);
i=0;
while(1){
i++;
if(i >max ){
LOG_EX(LOG_Debug, "Data overflow");
break;
}
pnext++;
if(*pnext == '\n')
break;
}
strncpy(get_str,sptr+strlen(obj),i);
get_str[i]='\0';
return 1;
}
return -1;
}
static struct wpa_status *gstatus;
static struct wpa_status* wpa_status_init()
{
int i;
if(gstatus == NULL)
gstatus = (struct wpa_status *)wgos_zalloc(sizeof(struct wpa_status));
if(gstatus == NULL){
LOG_EX(LOG_Debug, "MALLOC STATUS STRUCT FAILED!\n");
return NULL;
}
gstatus->id = -1;
gstatus->freq = -1;
for(i = 0;i< WPA_STA_MAX_SSID;i++){
gstatus->ssid[i] = '\0';
if(i < WPA_STA_MAX_BSSID)
gstatus->bssid[i] = '\0';
if(i < WPA_STA_MAX_IP_ADDR)
gstatus->ip_address[i] = '\0';
if(i < WPA_STA_MAX_KEY_MGMT)
gstatus->key_mgmt[i]='\0';
if(i < WPA_STA_MAX_MAC_ADDR)
gstatus->mac_address[i]='\0';
}
gstatus->wpa_state = WPA_UNKNOWN;
return gstatus;
}
void wpa_status_free()
{
if(gstatus !=NULL)
free(gstatus);
}
struct wpa_status * get_wpa_status()
{
char reply[4096] = {0};
char wpa_result[32];
struct wpa_status *wpa_sta;
wpa_sta = wpa_status_init();
wifi_command("STATUS", reply, sizeof(reply));
if(reply !=NULL){
if(search_wpa_string(reply,"ssid=",32,wpa_result) >0)
strncpy(wpa_sta->ssid,wpa_result,strlen(wpa_result));
if(search_wpa_string(reply,"id=",4,wpa_result) >0)
wpa_sta->id = atoi(wpa_result);
if(search_wpa_string(reply,"freq=",6,wpa_result) >0)
wpa_sta->freq = atoi(wpa_result);
if(search_wpa_string(reply,"bssid=",18,wpa_result) >0)
strncpy(wpa_sta->bssid,wpa_result,strlen(wpa_result));
if(search_wpa_string(reply,"key_mgmt=",16,wpa_result) >0)
strncpy(wpa_sta->key_mgmt,wpa_result,strlen(wpa_result));
if(search_wpa_string(reply,"wpa_state=",32,wpa_result) >0)
wpa_sta->wpa_state = wpa_supplicant_state_convert(wpa_result);
if(search_wpa_string(reply,"address=",18,wpa_result) >0)
strncpy(wpa_sta->mac_address,wpa_result,strlen(wpa_result));
if(search_wpa_string(reply,"ip_address=",16,wpa_result) >0)
strncpy(wpa_sta->ip_address,wpa_result,strlen(wpa_result));
}
if(wmg_get_debug_level() >= MSG_DEBUG){
print_wpa_status(wpa_sta);
}
return wpa_sta;
}
int update_scan_results()
{
int i=0;
LOG_EX(LOG_Debug, "update scan results enter\n");
pthread_mutex_lock(&thread_run_mutex);
scan_completed = 0;
pthread_cond_signal(&thread_run_cond);
pthread_mutex_unlock(&thread_run_mutex);
while(i <= 15){
usleep(200*1000);
if(scan_completed == 1){
break;
}
i++;
}
return 0;
}
int remove_slash_from_scan_results()
{
char *ptr = NULL;
char *ptr_s = NULL;
char *ftr = NULL;
ptr_s = scan_results;
while(1)
{
ptr = strchr(ptr_s,'\"');
if(ptr == NULL)
break;
ptr_s = ptr;
if((*(ptr-1)) == '\\')
{
ftr = ptr;
ptr -= 1;
while(*ftr != '\0')
*(ptr++) = *(ftr++);
*ptr = '\0';
continue; //restart new search at ptr_s after removing slash
}
else
ptr_s++; //restart new search at ptr_s++
}
ptr_s = scan_results;
while(1)
{
ptr = strchr(ptr_s,'\\');
if(ptr == NULL)
break;
ptr_s = ptr;
if((*(ptr-1)) == '\\')
{
ftr = ptr;
ptr -= 1;
while(*ftr != '\0')
*(ptr++) = *(ftr++);
*ptr = '\0';
continue; //restart new search at ptr_s after removing slash
}
else
ptr_s++; //restart new search at ptr_s++
}
return 0;
}
int get_scan_results_inner(char *result, int *len)
{
int index = 0;
char *ptr = NULL;
int ret = 0;
pthread_mutex_lock(&scan_mutex);
if(0 != scan_error)
{
// prinf("%s: scan or scan_results ERROR in scan_thread!\n", __func__);
ret = -1;
}
remove_slash_from_scan_results();
if(*len <= scan_results_len){
strncpy(result, scan_results, *len-1);
index = *len -1;
result[index] = '\0';
ptr=strrchr(result, '\n');
if(ptr != NULL){
*ptr = '\0';
}
}else{
strncpy(result, scan_results, scan_results_len);
result[scan_results_len] = '\0';
}
pthread_mutex_unlock(&scan_mutex);
return ret;
}
int is_network_exist(const char *ssid, tKEY_MGMT key_mgmt)
{
int ret = 0, i = 0, key[4] = {0};
for(i=0; i<4; i++){
key[i]=0;
}
get_key_mgmt(ssid, key);
if(key_mgmt == WIFIMG_NONE){
if(key[0] == 1){
ret = 1;
}
}else if(key_mgmt == WIFIMG_WPA_PSK || key_mgmt == WIFIMG_WPA2_PSK){
if(key[1] == 1){
ret = 1;
}
}else if(key_mgmt == WIFIMG_WEP){
if(key[2] == 1){
ret = 1;
}
}else{
;
}
return ret;
}
char getHalfByteCharac(char val)
{
char ret =-1;
if(9 >= (val&0x0f)) ret = (val&0x0f)+'0';
else ret = (val&0x0f)-10+'a';
return ret;
}
int utf8BytesExchangeEx(char *pCharIn,char ** pCharOut)
{
int size =0;
char * p_data = NULL;
char buf[UTF8_BYTES_MAX]={0x00};
int index =0;
int cpPos=0;
if(NULL == pCharIn)
{
return -1;
}
size =strlen(pCharIn);
p_data = pCharIn;
while(index<= size)
{
if(0 != ( (*p_data)&UTF8_MULTI_BYTES_MASK))
{
buf[cpPos++]='\\';
buf[cpPos++]='x';
buf[cpPos++]= getHalfByteCharac((*p_data)>>4);
buf[cpPos++]= getHalfByteCharac((*p_data)&0xf);
}else if( (*p_data) == ESCAP_CHAR_ASCII)
{
buf[cpPos++] = ESCAP_CHAR_ASCII;
buf[cpPos++] = ESCAP_CHAR_ASCII;
}else if( (*p_data) == DQUOT_CHAR_ASCII)
{
buf[cpPos++] = ESCAP_CHAR_ASCII;
buf[cpPos++] = DQUOT_CHAR_ASCII;
}else if((*p_data) == QUOT_CHAR_ASCII)
{
buf[cpPos++] = QUOT_CHAR_ASCII;
}
else
{
buf[cpPos++] = *p_data;
}
index++;
p_data++;
}
* pCharOut = malloc(strlen(buf)+1);
if(NULL == * pCharOut) return -1;
memset(* pCharOut,0x00,strlen(buf)+1);
memcpy(* pCharOut,buf,strlen(buf));
return 0;
}
int get_key_mgmt(const char *ssid, int key_mgmt_info[])
{
char *ptr = NULL, *pssid_start = NULL, *pssid_end = NULL;
char *pst = NULL, *pend = NULL;
char *pflag = NULL;
char flag[128], pssid[SSID_LEN + 1];
int len = 0, i = 0;
LOG_EX(LOG_Debug, "enter get_key_mgmt, ssid %s\n", ssid);
key_mgmt_info[KEY_NONE_INDEX] = 0;
key_mgmt_info[KEY_WEP_INDEX] = 0;
key_mgmt_info[KEY_WPA_PSK_INDEX] = 0;
pthread_mutex_lock(&scan_mutex);
/* first line end */
ptr = strchr(scan_results, '\n');
if(!ptr){
pthread_mutex_unlock(&scan_mutex);
LOG_EX(LOG_Debug, "no ap scan, return\n");
return 0;
}
//point second line of scan results
ptr++;
remove_slash_from_scan_results();
while(1){
/* line end */
pend = strchr(ptr, '\n');
if (pend != NULL){
*pend = '\0';
}
/* line start */
pst = ptr;
/* abstract ssid */
pssid_start = strrchr(pst, '\t') + 1;
strncpy(pssid, pssid_start, SSID_LEN);
pssid[SSID_LEN] = '\0';
/* find ssid in scan results */
if(strcmp(pssid, ssid) == 0){
pflag = pst;
for(i=0; i<3; i++){
pflag = strchr(pflag, '\t');
pflag++;
}
len = pssid_start - pflag;
len = len - 1;
strncpy(flag, pflag, len);
flag[len] = '\0';
LOG_EX(LOG_Debug, "ssid %s, flag %s\n", ssid, flag);
if((strstr(flag, "WPA-PSK-") != NULL)
|| (strstr(flag, "WPA2-PSK-") != NULL)){
key_mgmt_info[KEY_WPA_PSK_INDEX] = 1;
}else if(strstr(flag, "WEP") != NULL){
key_mgmt_info[KEY_WEP_INDEX] = 1;
}else if((strcmp(flag, "[ESS]") == 0) || (strcmp(flag, "[WPS][ESS]") == 0)){
key_mgmt_info[KEY_NONE_INDEX] = 1;
}else{
;
}
}
if(pend != NULL){
*pend = '\n';
//point next line
ptr = pend+1;
}else{
break;
}
}
pthread_mutex_unlock(&scan_mutex);
return 0;
}
void *wifi_scan_thread(void *args)
{
int ret = -1, i = 0;
char cmd[16] = {0}, reply[16] = {0};
struct timeval now;
struct timespec outtime;
while(scan_running){
pthread_mutex_lock(&scan_stop_restart_mutex);
while(do_scan_flag == 0){
pthread_cond_wait(&scan_stop_restart_cond, &scan_stop_restart_mutex);
}
if(scan_terminating)
{
pthread_mutex_unlock(&scan_stop_restart_mutex);
continue;
}
pthread_mutex_unlock(&scan_stop_restart_mutex);
pthread_mutex_lock(&scan_mutex);
while(scan_pause == 1){
pthread_cond_wait(&scan_cond, &scan_mutex);
}
/* set scan start flag */
set_scan_start_flag();
/* scan cmd */
strncpy(cmd, "SCAN", 15);
ret = wifi_command(cmd, reply, sizeof(reply));
if(ret){
scan_error = 1;
pthread_mutex_unlock(&scan_mutex);
usleep(5000*1000);
continue;
}
for(i=0;i<WAITING_CLK_COUNTS;i++){
if(get_scan_status() == 1){
break;
}
usleep(100*1000);
}
LOG_EX(LOG_Debug, "scan status %d\n", get_scan_status());
if(get_scan_status() == 1){
strncpy(cmd, "SCAN_RESULTS", 15);
cmd[15] = '\0';
ret = wifi_command(cmd, scan_results, sizeof(scan_results));
if(ret){
scan_error = 1;
LOG_EX(LOG_Debug, "do scan results error!\n");
pthread_mutex_unlock(&scan_mutex);
continue;
}
scan_results_len = strlen(scan_results);
scan_error = 0;
//printf("scan results len2 %d\n", scan_results_len);
//printf("scan results2\n");
//printf("%s\n", scan_results);
}
pthread_mutex_unlock(&scan_mutex);
//wait run singal or timeout 15s
pthread_mutex_lock(&thread_run_mutex);
if(scan_completed == 0){
scan_completed = 1;
}
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + 15;
outtime.tv_nsec = now.tv_usec *1000;
if(!scan_terminating)
{
pthread_cond_timedwait(&thread_run_cond, &thread_run_mutex, &outtime);
scan_completed = 0;
}
pthread_mutex_unlock(&thread_run_mutex);
}//end of while scan running
}
void shutdown_wifi_scan_thread()
{
pthread_mutex_lock(&scan_stop_restart_mutex);
do_scan_flag = 0;
pthread_mutex_unlock(&scan_stop_restart_mutex);
}
void restart_wifi_scan_thread()
{
pthread_mutex_lock(&scan_stop_restart_mutex);
do_scan_flag = 1;
pthread_mutex_unlock(&scan_stop_restart_mutex);
pthread_cond_signal(&scan_stop_restart_cond);
}
void start_wifi_scan_thread(void *args)
{
scan_terminating = 0;
pthread_mutex_init(&scan_stop_restart_mutex, NULL);
pthread_cond_init(&scan_stop_restart_cond, NULL);
pthread_mutex_init(&scan_mutex, NULL);
pthread_cond_init(&scan_cond, NULL);
pthread_mutex_init(&thread_run_mutex, NULL);
pthread_cond_init(&thread_run_cond,NULL);
scan_running = 1;
pthread_create(&scan_thread_id, NULL, &wifi_scan_thread, args);
}
void pause_wifi_scan_thread()
{
pthread_mutex_lock(&scan_mutex);
scan_pause=1;
pthread_mutex_unlock(&scan_mutex);
}
void resume_wifi_scan_thread()
{
pthread_mutex_lock(&scan_mutex);
scan_pause=0;
pthread_mutex_unlock(&scan_mutex);
pthread_cond_signal(&scan_cond);
}
void stop_wifi_scan_thread()
{
scan_running = 0;
usleep(200*1000);
pthread_mutex_lock(&thread_run_mutex);
scan_terminating = 1;
pthread_cond_signal(&thread_run_cond);
pthread_mutex_unlock(&thread_run_mutex);
restart_wifi_scan_thread();//if scan is stopped by the user, wake up the scan_thread
pthread_join(scan_thread_id, NULL);
pthread_cond_destroy(&thread_run_cond);
pthread_mutex_destroy(&thread_run_mutex);
pthread_cond_destroy(&scan_cond);
pthread_mutex_destroy(&scan_mutex);
pthread_cond_destroy(&scan_stop_restart_cond);
pthread_mutex_destroy(&scan_stop_restart_mutex);
}