#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <sys/epoll.h> | |
#include <errno.h> | |
#include <sys/wait.h> | |
#include <sys/types.h> | |
#include "wpa_ctrl.h" | |
#include "sta_ctrl.h" | |
#include "mbtk_log.h" | |
#include "mbtk_utils.h" | |
//#include "sta_log.h" | |
#define WPA_SUPPLICANT_LOG_FILE "/data/wpa_supplicant.log" | |
static void | |
sta_ctrl_wpa_req_cb(char *msg, size_t len); | |
static void* | |
sta_ctrl_event_thread_run( void *arg ); | |
static sta_err_enum | |
sta_ctrl_close_connection(void); | |
static sta_err_enum | |
sta_ctrl_open_connection(void); | |
static sta_err_enum | |
sta_ctrl_reconnect(void); | |
static void | |
sta_ctrl_recv_event(void); | |
static sta_err_enum | |
sta_ctrl_conf_file_parse | |
( | |
const char *key, | |
char *value | |
); | |
// extern struct wpa_ctrl; | |
static struct wpa_ctrl *sta_ctrl_conn; | |
static struct wpa_ctrl *sta_mon_conn; | |
static int sta_ctrl_attached = 0; | |
static pthread_t sta_event_thread_id; | |
static int sta_event_thread_is_running = 0; | |
static char sta_ctrl_conf_file_path[50]; | |
static char sta_ctrl_ifname[10]; | |
static sta_ctrl_msg_cb sta_ctrl_msg = NULL; | |
static int sta_ctrl_pipe_fd[2]; | |
static void | |
sta_ctrl_wpa_req_cb(char *msg, size_t len) | |
{ | |
LOGE("%s\n", msg); | |
} | |
bool | |
sta_ctrl_system | |
( | |
const char *command | |
) | |
{ | |
int result = TRUE; | |
FILE *stream = NULL; | |
LOGE("system call: %s\n", command); | |
stream = popen( command, "w" ); | |
if( stream == NULL ) | |
{ | |
LOGE("system command failed\n"); | |
result = FALSE; | |
} | |
else if( 0 > pclose( stream ) ) | |
{ | |
LOGE("pclose command failed\n"); | |
} | |
return result; | |
} | |
/* | |
* Return TRUE if process <name> is not running after 2 second. | |
*/ | |
bool | |
sta_ctrl_kill_check(const char *name) | |
{ | |
#define PROCESS_KILL_RETRY 40 | |
bool result; | |
int tmp = 0; | |
FILE *cmd; | |
char pid_s[STA_BUF_SIZE]; | |
int pid; | |
tmp = snprintf(pid_s,STA_BUF_SIZE, | |
"pidof %s",name); | |
pid_s[tmp] = '\0'; | |
tmp = 0; | |
while (tmp++ < PROCESS_KILL_RETRY) | |
{ | |
usleep(50000);/*50 mili second*/ | |
cmd = popen(pid_s, "r"); | |
pid = 0; | |
bzero(pid_s, STA_BUF_SIZE); | |
if(cmd) | |
{ | |
if(fgets(pid_s, STA_BUF_SIZE, cmd) == NULL) { | |
} | |
pclose(cmd); | |
} | |
pid = atoi(pid_s); | |
LOGE("%s pid =%d\n", name,pid); | |
/* If pid is zero we break from while*/ | |
if(pid == 0) | |
{ | |
result = TRUE; | |
goto exit_end; | |
} | |
} | |
LOGE("PID still running after waiting 2 second.\n"); | |
result = FALSE; | |
exit_end: | |
#undef PROCESS_KILL_RETRY | |
return result; | |
} | |
/* | |
* Return TRUE if process <name> is running. | |
*/ | |
bool | |
sta_ctrl_process_running(const char *name) | |
{ | |
char pid_s[STA_BUF_SIZE]; | |
int tmp = snprintf(pid_s,STA_BUF_SIZE, | |
"pidof %s",name); | |
pid_s[tmp] = '\0'; | |
FILE *cmd = popen(pid_s, "r"); | |
bzero(pid_s, STA_BUF_SIZE); | |
if(cmd) | |
{ | |
if(fgets(pid_s, STA_BUF_SIZE, cmd) == NULL) { | |
} | |
pclose(cmd); | |
} | |
int pid = atoi(pid_s); | |
LOGE("%s pid =%d\n", name,pid); | |
/* If pid is zero we break from while*/ | |
if(pid == 0) | |
{ | |
LOGE("%s not runnig.\n",name); | |
return FALSE; | |
}else{ | |
LOGE("%s is runnig.\n",name); | |
return TRUE; | |
} | |
} | |
static void* | |
sta_ctrl_event_thread_run( void *arg ) | |
{ | |
LOGE("Thread[%ld] run().\n",pthread_self()); | |
int nready = 0; | |
struct epoll_event ev_sock,ev_pipe,events[20]; | |
int epfd = epoll_create(256); | |
ev_sock.data.fd = wpa_ctrl_get_fd(sta_mon_conn); | |
ev_sock.events = EPOLLIN | EPOLLET; | |
epoll_ctl(epfd,EPOLL_CTL_ADD,wpa_ctrl_get_fd(sta_mon_conn),&ev_sock); | |
ev_pipe.data.fd = sta_ctrl_pipe_fd[0]; | |
ev_pipe.events = EPOLLIN | EPOLLET; | |
epoll_ctl(epfd,EPOLL_CTL_ADD,sta_ctrl_pipe_fd[0],&ev_pipe); | |
for ( ; ; ) { | |
if(!sta_event_thread_is_running){ | |
break; | |
} | |
LOGE("epoll_wait waitting...\n",nready); | |
nready = epoll_wait(epfd,events,20,-1); | |
LOGE("epoll_wait return.(count = %d)\n",nready); | |
int i; | |
for(i=0;i<nready;++i) { | |
if (events[i].events & EPOLLIN) {// Read | |
if (events[i].data.fd < 0) | |
continue; | |
if(sta_mon_conn // sta_mon_conn can not be NULL | |
&& events[i].data.fd == wpa_ctrl_get_fd(sta_mon_conn)){ | |
sta_ctrl_recv_event(); | |
}else if(events[i].data.fd == sta_ctrl_pipe_fd[0]){ | |
LOGE("Thread end.[fd = %d]\n",events[i].data.fd); | |
// End thread | |
char buf_end[10] = {0}; | |
if(read(sta_ctrl_pipe_fd[0],buf_end,10) > 0 | |
&& strcmp(buf_end,"0") == 0){ | |
sta_event_thread_is_running = 0; | |
break; | |
} | |
}else{ | |
LOGE("No such fd[%d].\n",events[i].data.fd); | |
} | |
} else { | |
LOGE("event error.\n"); | |
} | |
} | |
} | |
close(epfd); | |
LOGE("Thread exit.\n"); | |
return ((void*)0); | |
} | |
static sta_err_enum | |
sta_ctrl_close_connection(void) | |
{ | |
LOGE("start.\n"); | |
if (sta_ctrl_conn == NULL) | |
return STA_ERR_UNKNOWN; | |
if (sta_ctrl_attached) { | |
wpa_ctrl_detach(sta_mon_conn); | |
sta_ctrl_attached = 0; | |
} | |
wpa_ctrl_close(sta_ctrl_conn); | |
sta_ctrl_conn = NULL; | |
if (sta_mon_conn) { | |
wpa_ctrl_close(sta_mon_conn); | |
sta_mon_conn = NULL; | |
} | |
LOGE("end.\n"); | |
return STA_ERR_SUCCESS; | |
} | |
static sta_err_enum | |
sta_ctrl_open_connection(void) | |
{ | |
sta_err_enum result = STA_ERR_SUCCESS; | |
if(sta_ctrl_conn){ | |
return STA_ERR_UNKNOWN; | |
} | |
char ctrl_path[100] = {0}; | |
result = sta_ctrl_conf_file_parse("ctrl_interface", ctrl_path); | |
if(STA_ERR_SUCCESS != result){ | |
LOGE("sta_ctrl_conf_file_parse() fail(%d).\n",result); | |
return result; | |
} | |
sprintf(ctrl_path + strlen(ctrl_path), | |
"/%s", | |
sta_ctrl_ifname); | |
LOGE("ctrl_path = \"%s\"\n",ctrl_path); | |
sta_ctrl_conn = wpa_ctrl_open(ctrl_path); | |
if (sta_ctrl_conn == NULL) { | |
sleep(1); | |
return sta_ctrl_open_connection(); | |
} | |
sta_mon_conn = wpa_ctrl_open(ctrl_path); | |
if (sta_mon_conn == NULL) { | |
return STA_ERR_UNKNOWN; | |
} | |
if (wpa_ctrl_attach(sta_mon_conn) == 0) { | |
sta_ctrl_attached = 1; | |
} else { | |
LOGE("Warning: Failed to attach to " | |
"wpa_supplicant.\n"); | |
sta_ctrl_close_connection(); | |
return STA_ERR_UNKNOWN; | |
} | |
if(!sta_event_thread_is_running) { | |
sta_event_thread_is_running = 1; | |
int ret = pthread_create(&sta_event_thread_id, | |
NULL, | |
sta_ctrl_event_thread_run, | |
NULL); | |
if( ret != 0 ) { | |
LOGE( "Create thread error!\n"); | |
} | |
}else{ | |
LOGE("sta_event_thread is running.\n"); | |
return STA_ERR_UNKNOWN; | |
} | |
return result; | |
} | |
static sta_err_enum | |
sta_ctrl_reconnect(void) | |
{ | |
if(STA_ERR_SUCCESS == sta_ctrl_close_connection()){ | |
return sta_ctrl_open_connection(); | |
}else{ | |
return STA_ERR_UNKNOWN; | |
} | |
} | |
static void | |
sta_ctrl_recv_event(void) | |
{ | |
LOGE("start.\n"); | |
if (sta_ctrl_conn == NULL) { | |
sta_ctrl_reconnect(); | |
LOGE("sta_ctrl_conn == NULL:end.\n"); | |
return; | |
} | |
while (wpa_ctrl_pending(sta_mon_conn) > 0) { | |
char buf[4096]; | |
size_t len = sizeof(buf) - 1; | |
if (wpa_ctrl_recv(sta_mon_conn, buf, &len) == 0) { | |
buf[len] = '\0'; | |
LOGE("<<%s>>\n",buf); | |
if(sta_ctrl_msg) | |
sta_ctrl_msg(buf); | |
} else { | |
LOGE("Could not read pending message.\n"); | |
break; | |
} | |
} | |
if (wpa_ctrl_pending(sta_mon_conn) < 0) { | |
LOGE("Connection to wpa_supplicant lost - trying to " | |
"reconnect\n"); | |
sta_ctrl_reconnect(); | |
} | |
LOGE("end.\n"); | |
} | |
static sta_err_enum | |
sta_ctrl_conf_file_parse | |
( | |
const char *key, | |
char *value | |
) | |
{ | |
sta_err_enum result = STA_ERR_UNKNOWN; | |
FILE *fd = fopen(sta_ctrl_conf_file_path,"r"); | |
if(!fd){ | |
LOGE("Open file(%s) fail(%d).\n",sta_ctrl_conf_file_path,errno); | |
return STA_ERR_UNKNOWN; | |
} | |
char buf[1024]; | |
while(fgets(buf,1024,fd)){ | |
char *start = strstr(buf,key); | |
if(start){ // Find key | |
char *tmp = start + strlen(start) -1; | |
while(*tmp){ | |
if(*tmp == '\r' | |
|| *tmp == '\n'){ | |
*tmp = '\0'; | |
}else{ | |
break; | |
} | |
tmp--; | |
} | |
int size = snprintf(value,100, | |
"%s", | |
start + strlen(key) + 1); | |
value[size] = '\0'; | |
result = STA_ERR_SUCCESS; | |
break; | |
} | |
} | |
fclose(fd); | |
return result; | |
} | |
/***************************************************************/ | |
/************************ Public Fuction ***********************/ | |
/***************************************************************/ | |
sta_err_enum | |
sta_ctrl_cmd_process | |
( | |
const char *cmd, | |
char *reply, | |
size_t reply_len | |
) | |
{ | |
sta_err_enum result = STA_ERR_SUCCESS; | |
bzero(reply,reply_len); | |
reply_len = reply_len - 1; | |
int ret = wpa_ctrl_request(sta_ctrl_conn, | |
cmd, | |
strlen(cmd), | |
reply, | |
&reply_len, | |
sta_ctrl_wpa_req_cb); | |
if (ret == -2) { | |
LOGE("command timed out.\n"); | |
result = STA_ERR_TIMEOUT; | |
goto end_fail; | |
} else if (ret < 0) { | |
LOGE("command failed.\n"); | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} else { | |
reply[reply_len] = '\0'; | |
LOGE("1:%s\n", reply); | |
if(reply_len > 0 && reply[reply_len - 1] != '\n') | |
LOGE("\n"); | |
} | |
//end_success: | |
return result; | |
end_fail: | |
return result; | |
} | |
/** | |
* Open or close wlan driver. | |
*/ | |
sta_err_enum | |
sta_ctrl_driver_init(bool open) | |
{ | |
sta_err_enum result = STA_ERR_SUCCESS; | |
FILE *fd_tmp = NULL; | |
if(open){ | |
fd_tmp = popen("/etc/wifi/mbtk_wifi_driver.sh sta start","r"); | |
}else{ | |
fd_tmp = popen("/etc/wifi/mbtk_wifi_driver.sh sta stop","r"); | |
} | |
if(fd_tmp){ | |
char buf[200] = {0}; | |
if(fgets(buf,200,fd_tmp) == NULL) { | |
} | |
pclose(fd_tmp); | |
if(strlen(buf) > 0){ | |
LOGE("Driver %s fail.(%s)\n",(open?"open":"close"),buf); | |
result = STA_ERR_DRIVER; | |
}else{// Open wpa_supplicant | |
LOGE("Driver %s success.\n",(open?"open":"close")); | |
} | |
}else{ | |
LOGE("Driver %s fail.(%s)\n",(open?"open":"close")); | |
result = STA_ERR_DRIVER; | |
} | |
return result; | |
} | |
sta_err_enum | |
sta_ctrl_wpa_init | |
( | |
const char *conf_file, | |
const char *interface, | |
sta_ctrl_msg_cb cb | |
) | |
{ | |
sta_err_enum result = STA_ERR_SUCCESS; | |
if(!conf_file | |
|| strlen(conf_file) == 0){ | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} | |
if(!interface | |
|| strlen(interface) == 0){ | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} | |
sta_ctrl_msg = cb; | |
int size = snprintf(sta_ctrl_conf_file_path, | |
50, | |
"%s", | |
conf_file); | |
sta_ctrl_conf_file_path[size] = '\0'; | |
size = snprintf(sta_ctrl_ifname, | |
10, | |
"%s", | |
interface); | |
sta_ctrl_ifname[size] = '\0'; | |
if(pipe(sta_ctrl_pipe_fd)){ | |
LOGE("pipe() fail(%d).\n",errno); | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} | |
FILE *fd_tmp = popen("pidof wpa_supplicant","r"); | |
if(fd_tmp){ | |
char buf[200] = {0}; | |
if(fgets(buf,200,fd_tmp) == NULL) { | |
} | |
pclose(fd_tmp); | |
if(strlen(buf) > 0){ | |
LOGE("wpa_supplicant is running.(%s)\n",buf); | |
}else{// Open wpa_supplicant | |
bzero(buf,200); | |
snprintf(buf,200, | |
"wpa_supplicant -Dnl80211 -c%s -i%s -f%s -ddd &", | |
conf_file, | |
interface, | |
WPA_SUPPLICANT_LOG_FILE); | |
/* | |
snprintf(buf,200, | |
"wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wifi/wpa_supplicant.conf -B"); | |
*/ | |
if (sta_ctrl_system(buf)){ | |
LOGE("\"%s\" success.\n",buf); | |
sleep(1); | |
}else{ | |
LOGE("\"%s\" fail.\n",buf); | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} | |
} | |
}else{ | |
LOGE("\"pidof wpa_supplicant\" fail\n"); | |
result = STA_ERR_UNKNOWN; | |
goto end_fail; | |
} | |
result = sta_ctrl_open_connection(); | |
if(STA_ERR_SUCCESS != result) { | |
LOGE("sta_ctrl_open_connection() fail(%d).\n",result); | |
goto end_fail; | |
} | |
//end_success: | |
return result; | |
end_fail: | |
return result; | |
} | |
sta_err_enum | |
sta_ctrl_wpa_deinit | |
( | |
void | |
) | |
{ | |
sta_err_enum result = STA_ERR_SUCCESS; | |
result = sta_ctrl_close_connection(); | |
if(STA_ERR_SUCCESS != result){ | |
goto end_fail; | |
} | |
bzero(sta_ctrl_conf_file_path,50); | |
bzero(sta_ctrl_ifname,10); | |
sta_event_thread_is_running = 0; | |
// End thread. | |
mbtk_write(sta_ctrl_pipe_fd[1],"0",1); | |
LOGE("Waitting for thread(%ld) exit.\n",sta_event_thread_id); | |
pthread_join(sta_event_thread_id,NULL); | |
LOGE("pthread_join() return.\n"); | |
close(sta_ctrl_pipe_fd[0]); | |
close(sta_ctrl_pipe_fd[1]); | |
sta_ctrl_msg = NULL; | |
// Stop process wpa_supplicant | |
if(sta_ctrl_system("killall -15 wpa_supplicant") | |
&& sta_ctrl_kill_check("wpa_supplicant")){ | |
LOGE("\"killall -15 wpa_supplicant\" success.\n"); | |
}else{ | |
if(sta_ctrl_system("killall -9 wpa_supplicant")){ | |
LOGE("\"killall -9 wpa_supplicant\" success.\n"); | |
}else{ | |
LOGE("\"killall -9 wpa_supplicant\" fail.\n"); | |
} | |
} | |
//end_success: | |
LOGE("sta_ctrl_wpa_deinit() end(success).\n"); | |
return result; | |
end_fail: | |
LOGE("sta_ctrl_wpa_deinit() end(fail)[%s].\n",result); | |
return result; | |
} | |