| #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 = -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) | |
| { | |
| 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_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; | |
| } | |