| /************************************************************* |
| Description: |
| C file for network control. |
| Author: |
| LiuBin |
| Date: |
| 2019/7/24 17:13:06 |
| *************************************************************/ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <sys/un.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <errno.h> |
| #include <linux/netlink.h> |
| #include <linux/rtnetlink.h> |
| #include <linux/route.h> |
| #include <cutils/properties.h> |
| #include <telephony/ril.h> |
| |
| #include "mbtk_type.h" |
| #include "mbtk_net_control.h" |
| #include "mbtk_task.h" |
| #include "mbtk_utils.h" |
| #include "mbtk_str.h" |
| |
| #ifdef LOG_TAG |
| #undef LOG_TAG |
| #endif |
| #define LOG_TAG "mbtk_net_control" |
| #include "mbtk_log.h" |
| |
| /************************************************************* |
| Constants and Macros |
| *************************************************************/ |
| #define NET_CONTROL_BUF_SIZE 1024 |
| #ifndef INFTIM |
| #define INFTIM (-1) /* infinite poll timeout */ |
| #endif |
| #define MBTK_NET_PING_HOST "223.5.5.5" |
| #define MBTK_NET_PING_IP "180.97.33.107" // IP for www.baidu.com |
| |
| // #define MBTK_NET_MONITOR_SUPPORT |
| |
| /************************************************************* |
| Variables:local |
| *************************************************************/ |
| static char net_interface[20]; |
| static char net_ip[20]; |
| static bool net_if_inited = FALSE; |
| static mbtk_net_state_t net_state = MBTK_NET_STATE_OFF; |
| static bool net_control_thread_running = FALSE; |
| |
| #ifdef MBTK_NET_MONITOR_SUPPORT |
| static pthread_t net_control_thread_id = -1; |
| static int net_control_fd = -1; |
| static char net_if_name[100] = {0}; |
| #endif |
| |
| /************************************************************* |
| Variables:public |
| *************************************************************/ |
| |
| |
| /************************************************************* |
| Local Function Declaration |
| *************************************************************/ |
| static mbtk_net_state_callback_func net_state_cb = NULL; |
| |
| /************************************************************* |
| Local Function Definitions |
| *************************************************************/ |
| // Test network connected? |
| // ping www.baidu.com |
| static bool net_connected(const char *inf) |
| { |
| char cmd[100]; |
| char cmd_rsp[100]; |
| |
| // IP get now, ping www.baidu.com |
| memset(cmd,0,100); |
| snprintf(cmd,100, |
| "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"", |
| inf, |
| MBTK_NET_PING_HOST); |
| if(!mbtk_cmd_line(cmd,cmd_rsp,100)) |
| { |
| LOGE("ping www.baidu.com cmd error."); |
| return FALSE; |
| } |
| |
| LOGI("cmd_rsp:%s",cmd_rsp); |
| // ping www.baidu.com success. |
| if(str_startwith(cmd_rsp, "8 bytes from ")) |
| { |
| return TRUE; |
| } |
| #if 0 |
| else if(str_contains(cmd_rsp, "unknown host")) |
| { |
| // DNS error,ping IP angin. |
| memset(cmd,0,100); |
| snprintf(cmd,100, |
| "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"", |
| inf, |
| MBTK_NET_PING_IP); |
| if(!mbtk_cmd_line(cmd,cmd_rsp,100)) |
| { |
| LOGW("ping www.baidu.com IP cmd error."); |
| return FALSE; |
| } |
| |
| if(str_startwith(cmd_rsp, "8 bytes from ")) |
| { |
| return TRUE; |
| } |
| else |
| { |
| LOGW("Network unconnected.(ping baidu IP fail)"); |
| return FALSE; |
| } |
| } |
| #endif |
| else |
| { |
| LOGW("Network unconnected.(ping baidu host fail)"); |
| return FALSE; |
| } |
| |
| LOGW("ifconfig cmd fail."); |
| return FALSE; |
| } |
| |
| #ifdef MBTK_NET_MONITOR_SUPPORT |
| static int net_control_netlink_init() |
| { |
| struct sockaddr_nl sa; |
| int len = 2048; |
| |
| net_control_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| if(net_control_fd < 0) |
| { |
| LOGE("socket() fail.[%d]",errno); |
| return -1; |
| } |
| |
| if(setsockopt(net_control_fd, |
| SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) < 0) |
| { |
| LOGE("setsockopt() fail.[%d]",errno); |
| return -1; |
| } |
| |
| bzero(&sa, sizeof(sa)); |
| sa.nl_family = AF_NETLINK; |
| sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE /*| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE*/; |
| if(bind(net_control_fd, |
| (struct sockaddr *) &sa, sizeof(sa)) < 0) |
| { |
| LOGE("bind() fail.[%d]",errno); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len) |
| { |
| for ( ; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { |
| if (attr->rta_type <= max) { |
| tb[attr->rta_type] = attr; |
| } |
| } |
| } |
| |
| static void net_control_if_change(struct nlmsghdr *nh) |
| { |
| int msg_len; |
| struct rtattr *tb[IFLA_MAX + 1]; |
| struct ifinfomsg *ifinfo; |
| bzero(tb, sizeof(tb)); |
| if(nh == NULL) |
| { |
| LOGE("mbtk_net_if_change() nh == NULL"); |
| return; |
| } |
| |
| ifinfo = NLMSG_DATA(nh); |
| if(ifinfo == NULL) |
| { |
| LOGE("mbtk_net_if_change() ifinfo == NULL"); |
| return; |
| } |
| |
| msg_len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo)); |
| parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifinfo), msg_len); /* 8 */ |
| |
| LOGD("Interface changed:if_index=%d,if_name=%s,type=%s,state=%s", |
| ifinfo->ifi_index, (tb[IFLA_IFNAME] ? RTA_DATA(tb[IFLA_IFNAME]) : " "), |
| (nh->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK", |
| (ifinfo->ifi_flags & IFF_UP) ? "up" : "down"); |
| |
| if(net_state_cb) { |
| mbtk_net_if_change_info_t if_info; |
| memset(&if_info, 0x0, sizeof(mbtk_net_if_change_info_t)); |
| if_info.if_index = ifinfo->ifi_index; |
| if(tb[IFLA_IFNAME]) { |
| memcpy(if_info.if_name, RTA_DATA(tb[IFLA_IFNAME]), strlen(RTA_DATA(tb[IFLA_IFNAME]))); |
| } |
| if_info.type = (nh->nlmsg_type == RTM_NEWLINK) ? MBTK_NET_IF_CHANGE_TYPE_ADD : MBTK_NET_IF_CHANGE_TYPE_DEL; |
| if_info.state = (ifinfo->ifi_flags & IFF_UP) ? MBTK_NET_IF_CHANGE_STATE_UP : MBTK_NET_IF_CHANGE_STATE_DOWN; |
| if(str_empty(net_if_name)) { // No set if name, process all interface change. |
| net_state_cb(MBTK_NET_CHANGE_IF, &if_info); |
| } else { |
| // Only monitor specific interface. |
| if(strcmp(net_if_name, if_info.if_name) == 0) { |
| net_state_cb(MBTK_NET_CHANGE_IF, &if_info); |
| } |
| } |
| } |
| } |
| |
| static void net_control_addr_change(struct nlmsghdr *nlh) |
| { |
| int len; |
| struct rtattr *tb[IFA_MAX + 1]; |
| struct ifaddrmsg *ifaddr; |
| |
| bzero(tb, sizeof(tb)); |
| ifaddr = NLMSG_DATA(nlh); |
| len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr)); |
| parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len); |
| |
| if (tb[IFA_ADDRESS] != NULL) { |
| char tmp[256] = {0}; |
| inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp)); |
| LOGD("Address changed:index=%d,type=%s,if_name=%s,addr=%s", ifaddr->ifa_index, |
| (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR", |
| tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", tmp); |
| |
| if(net_state_cb) { |
| mbtk_net_addr_change_info_t addr_info; |
| memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t)); |
| addr_info.if_index = ifaddr->ifa_index; |
| addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL; |
| if(tb[IFA_LABEL] != NULL) { |
| memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL]))); |
| } |
| if (strlen(tmp) > 0) { |
| memcpy(addr_info.addr, tmp, strlen(tmp)); |
| } |
| if(str_empty(net_if_name)) { // No set if name, process all address change. |
| net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info); |
| } else { |
| // Only monitor specific address. |
| if(strcmp(net_if_name, addr_info.if_name) == 0) { |
| net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info); |
| } |
| } |
| } |
| } else { |
| LOGD("Address changed:type=%s,if_name=%s,addr=%s", |
| (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR", |
| tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", "Unknown"); |
| |
| if(net_state_cb) { |
| mbtk_net_addr_change_info_t addr_info; |
| memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t)); |
| addr_info.if_index = ifaddr->ifa_index; |
| addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL; |
| if(tb[IFA_LABEL] != NULL) { |
| memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL]))); |
| } |
| if(str_empty(net_if_name)) { // No set if name, process all address change. |
| net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info); |
| } else { |
| // Only monitor specific address. |
| if(strcmp(net_if_name, addr_info.if_name) == 0) { |
| net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info); |
| } |
| } |
| } |
| } |
| } |
| |
| static void* net_control_monitor_run(void *arg) |
| { |
| LOGI("net_control_monitor_run start."); |
| if(net_control_netlink_init() < 0) |
| { |
| LOGE("mbtk_net_monitor_run() fail."); |
| return ((void*)0); |
| } |
| |
| fd_set rd_set; |
| struct timeval timeout; |
| int select_r; |
| int read_r; |
| struct sockaddr_nl sa; |
| struct nlmsghdr *nh; |
| char buff[NET_CONTROL_BUF_SIZE]; |
| |
| while (net_control_thread_running) |
| { |
| FD_ZERO(&rd_set); |
| FD_SET(net_control_fd, &rd_set); |
| timeout.tv_sec = 5; |
| timeout.tv_usec = 0; |
| select_r = select(net_control_fd + 1, &rd_set, NULL, NULL, &timeout); |
| if (select_r < 0) |
| { |
| perror("select"); |
| } |
| else if (select_r > 0) |
| { |
| if (FD_ISSET(net_control_fd, &rd_set)) |
| { |
| read_r = read(net_control_fd, buff, NET_CONTROL_BUF_SIZE); |
| LOGI("Net change:read len:%d",read_r); |
| #if 0 |
| int i; |
| for(i = 0; i < 32 && i < read_r; i++) |
| LOGI("data:%x",buff[i]); |
| #endif |
| for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r)) |
| { |
| LOGI("msg_type:%d",nh->nlmsg_type); |
| switch (nh->nlmsg_type) |
| { |
| default: |
| LOGI("nh->nlmsg_type = %d\n", nh->nlmsg_type); |
| break; |
| case NLMSG_DONE: |
| case NLMSG_ERROR: |
| break; |
| case RTM_NEWLINK: |
| case RTM_DELLINK: |
| net_control_if_change(nh); |
| break; |
| case RTM_NEWADDR: |
| case RTM_DELADDR: |
| net_control_addr_change(nh); |
| break; |
| case RTM_NEWROUTE: |
| case RTM_DELROUTE: |
| //print_rtmsg(nh); |
| break; |
| } |
| |
| } |
| } |
| } |
| } |
| |
| LOGD("mbtk_net_monitor_run exist ..."); |
| |
| return ((void*)0); |
| } |
| |
| static mbtk_task_info net_control_thread = |
| { |
| .task_id = &net_control_thread_id, |
| .thread_run = net_control_monitor_run, |
| .args = NULL |
| }; |
| #endif |
| |
| static int net_control_interface_init() |
| { |
| // seth_ltex |
| int i = 0; |
| int size = 0; |
| char result[NET_CONTROL_BUF_SIZE]; |
| char cmd[100]; |
| int index = 0; |
| while(i <= 7) |
| { |
| size = snprintf(cmd, 100,"ifconfig ccinet%d", i); |
| cmd[size] = '\0'; |
| memset(result,0x0,NET_CONTROL_BUF_SIZE); |
| if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE)) |
| { |
| index = str_indexof(result,"inet addr:"); |
| if(index > 0) |
| { |
| size = snprintf(net_interface, 20,"ccinet%d", i); |
| net_interface[size] = '\0'; |
| |
| memcpy(net_ip,result + index + 10,20); |
| |
| char *ptr = net_ip; |
| while(*ptr && *ptr != ' ') |
| { |
| ptr++; |
| } |
| *ptr = '\0'; |
| break; |
| } |
| } |
| i++; |
| } |
| |
| LOGI("Interface : %s, IP : %s",net_interface,net_ip); |
| if(index ) |
| { |
| return 0; |
| } |
| else{ |
| return -1; |
| } |
| } |
| |
| static int net_control_init() |
| { |
| if(net_if_inited) |
| { |
| LOGD("Network control has inited."); |
| return 0; |
| } |
| |
| memset(net_ip,0x0,20); |
| memset(net_interface,0x0,20); |
| if(net_control_interface_init()) |
| return -1; |
| |
| net_if_inited = TRUE; |
| LOGI("net_control_init() success."); |
| return 0; |
| } |
| |
| static int net_control_state_change(bool enable) |
| { |
| int size; |
| char result[NET_CONTROL_BUF_SIZE]; |
| char cmd[100]; |
| if(enable) |
| { |
| // ifconfig seth_lte1 up |
| // ip route add default via 10.94.251.205 dev seth_lte1 |
| size = snprintf(cmd,100,"ifconfig %s up",net_interface); |
| cmd[size] = '\0'; |
| |
| if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE)) |
| { |
| size = snprintf(cmd,100,"ip route add default via %s dev %s",net_ip,net_interface); |
| cmd[size] = '\0'; |
| |
| if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE)) |
| { |
| net_state = MBTK_NET_STATE_CONN; |
| return 0; |
| } |
| } |
| } |
| else |
| { |
| // ifconfig seth_lte1 down |
| size = snprintf(cmd,100,"ifconfig %s down",net_interface); |
| cmd[size] = '\0'; |
| |
| if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE)) |
| { |
| net_state = MBTK_NET_STATE_OFF; |
| return 0; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /************************************************************* |
| Public Function Definitions |
| *************************************************************/ |
| /*============================================= |
| FUNCTION |
| mbtk_net_state_get() |
| |
| DESCRIPTION |
| Get network state. |
| |
| DEPENDENCIES |
| None |
| |
| PARAMETERS |
| None |
| |
| RETURN VALUE |
| Current network state. |
| |
| SIDE EFFECTS |
| None |
| =============================================*/ |
| mbtk_net_state_t mbtk_net_state_get() |
| { |
| net_control_init(); |
| |
| net_state = MBTK_NET_STATE_OFF; |
| if(strlen(net_ip) > 0) |
| { |
| if(net_connected(net_interface)) |
| net_state = MBTK_NET_STATE_CONN; |
| } |
| |
| LOGI("[GET]Net state:%d",net_state); |
| |
| if(net_state == MBTK_NET_STATE_CONN) |
| { |
| char value[PROPERTY_VALUE_MAX] = {0}; |
| if (property_get("persist.mbtk.netstate", value, "0,0") > 0 && strcmp(value,"0,0")) { |
| int regStatus = 0, gprsState = 0; |
| char *ptr = value; |
| regStatus = atoi(ptr); |
| if((ptr = strstr(ptr, ","))) |
| { |
| gprsState = atoi(ptr + 1); |
| } |
| |
| LOGI("regStatus : %d, gprsState : %d", regStatus, gprsState); |
| if(regStatus != 1 && regStatus != 5) // Not Home/Roaming Network. |
| { |
| net_state = MBTK_NET_STATE_CONN_UNKNOWN; |
| } |
| else |
| { |
| if (gprsState == RADIO_TECH_LTE || gprsState == RADIO_TECH_LTEP) |
| { |
| net_state = MBTK_NET_STATE_CONN_4G; |
| } |
| else if ((gprsState == RADIO_TECH_GPRS) || (gprsState == RADIO_TECH_EDGE) || (gprsState == RADIO_TECH_GSM)) |
| { |
| net_state = MBTK_NET_STATE_CONN_2G; |
| } else if((gprsState == RADIO_TECH_UMTS) || (gprsState == RADIO_TECH_HSDPA) |
| || (gprsState == RADIO_TECH_HSUPA) || (gprsState == RADIO_TECH_HSPA)) { |
| net_state = MBTK_NET_STATE_CONN_3G; |
| } else { |
| net_state = MBTK_NET_STATE_CONN_UNKNOWN; |
| } |
| } |
| } |
| else |
| { |
| LOGE("property_get persist.mbtk.netstate fail."); |
| net_state = MBTK_NET_STATE_CONN_UNKNOWN; |
| goto end; |
| } |
| } |
| |
| end: |
| return net_state; |
| } |
| |
| /*============================================= |
| FUNCTION |
| mbtk_net_enable() |
| |
| DESCRIPTION |
| Set network state. |
| |
| DEPENDENCIES |
| None |
| |
| PARAMETERS |
| enable |
| TRUE : Enable network. |
| FALSE: Diable network. |
| |
| RETURN VALUE |
| 0 : Success |
| -1: Fail |
| |
| SIDE EFFECTS |
| None |
| =============================================*/ |
| int mbtk_net_enable(bool enable) |
| { |
| if( net_control_init()) |
| return -1; |
| |
| int result = net_control_state_change(enable); |
| |
| LOGI("[SET]Net state:%d",net_state); |
| |
| return result; |
| } |
| |
| int mbtk_net_monitor_reg(const char* if_name, mbtk_net_state_callback_func state_cb) |
| { |
| if( net_control_init()) |
| return -1; |
| |
| #ifdef MBTK_NET_MONITOR_SUPPORT |
| net_control_thread_running = TRUE; |
| if(mbtk_task_start(&net_control_thread)) |
| { |
| LOGE("Create thread fail."); |
| net_control_thread_id = -1; |
| net_control_thread_running = FALSE; |
| return -1; |
| } |
| #endif |
| |
| net_state_cb = state_cb; |
| if(str_empty(if_name)) { |
| memset(net_if_name, 0x0, sizeof(net_if_name)); |
| } else { |
| memset(net_if_name, 0x0, sizeof(net_if_name)); |
| memcpy(net_if_name, if_name, strlen(if_name)); |
| } |
| |
| return 0; |
| } |
| |
| |