blob: e5e24aae4031a6d62ea5c7eb499df385424a1974 [file] [log] [blame]
#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 "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 = -1;
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)
{
fgets(pid_s, STA_BUF_SIZE, cmd);
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)
{
fgets(pid_s, STA_BUF_SIZE, cmd);
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;
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;
}
snprintf(ctrl_path + strlen(ctrl_path),10,
"/%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};
fgets(buf,200,fd_tmp);
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};
fgets(buf,200,fd_tmp);
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.
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_event_thread_id = -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;
}