| /* |
| * MBTK Network Interface control. |
| * |
| * Author : lb |
| * Date : 2021/8/20 11:44:05 |
| * |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| //#include <net/if.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <linux/if_ether.h> |
| #include <linux/sockios.h> |
| //#include <cutils/properties.h> |
| #include <arpa/inet.h> |
| #include <pthread.h> |
| #include <linux/route.h> |
| #include <sys/ioctl.h> |
| #include <unistd.h> |
| |
| #include "mbtk_type.h" |
| #include "mbtk_log.h" |
| #include "mbtk_utils.h" |
| #include "mbtk_ifc.h" |
| |
| #define IFNAMSIZ 16 |
| |
| static int ifc_ctl_sock = -1; |
| static pthread_mutex_t ifc_sock_mutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| static void ifc_init_ifr(const char *name, struct ifreq *ifr) |
| { |
| memset(ifr, 0, sizeof(struct ifreq)); |
| strncpy(ifr->ifr_name, name, IFNAMSIZ); |
| ifr->ifr_name[IFNAMSIZ - 1] = 0; |
| } |
| |
| static int ifc_set_flags(int sock, const char *name, unsigned set, unsigned clr) |
| { |
| struct ifreq ifr; |
| ifc_init_ifr(name, &ifr); |
| |
| if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) |
| return -1; |
| ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set; |
| return ioctl(sock, SIOCSIFFLAGS, &ifr); |
| } |
| |
| static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr) |
| { |
| struct sockaddr_in *sin = (struct sockaddr_in *) sa; |
| sin->sin_family = AF_INET; |
| sin->sin_port = 0; |
| sin->sin_addr.s_addr = addr; |
| } |
| |
| #if 1 |
| static const char *ipaddr_to_string(in_addr_t addr) |
| { |
| struct in_addr in_addr; |
| |
| in_addr.s_addr = addr; |
| return inet_ntoa(in_addr); |
| } |
| #endif |
| |
| static in_addr_t prefixLengthToIpv4Netmask(int prefix_length) |
| { |
| in_addr_t mask = 0; |
| |
| // C99 (6.5.7): shifts of 32 bits have undefined results |
| if (prefix_length <= 0 || prefix_length > 32) |
| { |
| return 0; |
| } |
| |
| mask = ~mask << (32 - prefix_length); |
| mask = htonl(mask); |
| |
| return mask; |
| } |
| |
| #if 1 |
| static int ifc_set_prefixLength(const char *name, int prefixLength) |
| { |
| struct ifreq ifr; |
| // TODO - support ipv6 |
| // if (prefixLength > 32 || prefixLength < 0) return -1; |
| |
| in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength); |
| ifc_init_ifr(name, &ifr); |
| init_sockaddr_in(&ifr.ifr_addr, mask); |
| |
| return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr); |
| } |
| #endif |
| |
| int ifc_act_on_ipv4_route(int action, const char *ifname, struct in_addr dst, int prefix_length, |
| struct in_addr gw) |
| { |
| struct rtentry rt; |
| int result; |
| in_addr_t netmask; |
| |
| memset(&rt, 0, sizeof(rt)); |
| |
| rt.rt_dst.sa_family = AF_INET; |
| rt.rt_dev = (void*) ifname; |
| |
| netmask = prefixLengthToIpv4Netmask(prefix_length); |
| init_sockaddr_in(&rt.rt_genmask, netmask); |
| init_sockaddr_in(&rt.rt_dst, dst.s_addr); |
| rt.rt_flags = RTF_UP; |
| |
| if (prefix_length == 32) |
| { |
| rt.rt_flags |= RTF_HOST; |
| } |
| |
| if (gw.s_addr != 0) |
| { |
| rt.rt_flags |= RTF_GATEWAY; |
| init_sockaddr_in(&rt.rt_gateway, gw.s_addr); |
| } |
| |
| result = ioctl(ifc_ctl_sock, action, &rt); |
| if (result < 0) |
| { |
| if (errno == EEXIST) |
| { |
| result = 0; |
| } |
| else |
| { |
| result = -errno; |
| } |
| } |
| return result; |
| } |
| |
| static int ifc_create_default_route1(const char *name, in_addr_t gw) |
| { |
| struct in_addr in_dst, in_gw; |
| |
| in_dst.s_addr = 0; |
| in_gw.s_addr = gw; |
| |
| int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw); |
| LOGD("ifc_create_default_route(%s, %d) = %d", name, gw, ret); |
| return ret; |
| } |
| |
| /* deprecated - v4 only */ |
| static int ifc_create_default_route2(const char *name, const char *gw) |
| { |
| struct in_addr in_dst, in_gw; |
| |
| in_dst.s_addr = 0; |
| if(gw == NULL) |
| { |
| in_gw.s_addr = 0; |
| } |
| else |
| { |
| if(inet_aton(gw,(struct in_addr *)&(in_gw.s_addr)) < 0) |
| { |
| LOGE("inet_aton error."); |
| return -1; |
| } |
| } |
| |
| int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw); |
| LOGD("ifc_create_default_route(%s) = %d", name, ret); |
| return ret; |
| } |
| |
| int mbtk_ifc_open(void) |
| { |
| pthread_mutex_lock(&ifc_sock_mutex); |
| if (ifc_ctl_sock == -1) |
| { |
| ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); |
| if (ifc_ctl_sock < 0) |
| { |
| LOGE("socket() failed: %s\n", strerror(errno)); |
| } |
| } |
| |
| return ifc_ctl_sock < 0 ? -1 : 0; |
| } |
| |
| int mbtk_ifc_close(void) |
| { |
| if (ifc_ctl_sock != -1) |
| { |
| (void)close(ifc_ctl_sock); |
| ifc_ctl_sock = -1; |
| } |
| pthread_mutex_unlock(&ifc_sock_mutex); |
| |
| return 0; |
| } |
| |
| int mbtk_ifc_set_addr(const char *name, in_addr_t addr, in_addr_t netmask) |
| { |
| struct ifreq ifr, irf_mask; |
| int ret; |
| |
| ifc_init_ifr(name, &ifr); |
| init_sockaddr_in(&ifr.ifr_addr, addr); |
| |
| ret = ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr); |
| if(ret) |
| { |
| LOGD("set_addr(%s, %x) = %d fail.", name, addr, ret); |
| } |
| |
| if(netmask) |
| { |
| ifc_init_ifr(name, &irf_mask); |
| init_sockaddr_in(&irf_mask.ifr_netmask, netmask); |
| ret = ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &irf_mask); |
| if(ret) |
| { |
| LOGD("set_netmask(%s, %x) = %d fail.", name, netmask, ret); |
| } |
| } |
| |
| return ret; |
| } |
| |
| int mbtk_ifc_ip_config(const char *ifname, const char *ipv4, const char *mask, const char *gateway) |
| { |
| UNUSED(gateway); |
| struct ifreq ifr; |
| |
| // struct rtentry rt; |
| // Set IPv4 |
| struct sockaddr_in *sin; |
| memset(&ifr,0,sizeof(ifr)); |
| strcpy(ifr.ifr_name,ifname); |
| sin = (struct sockaddr_in*)&ifr.ifr_addr; |
| sin->sin_family = AF_INET; |
| if(ipv4) { |
| if(inet_aton(ipv4,&(sin->sin_addr)) < 0) |
| { |
| LOGE("inet_aton error."); |
| return -2; |
| } |
| } else { |
| memset(&(sin->sin_addr), 0, sizeof(struct in_addr)); |
| } |
| |
| if(ioctl(ifc_ctl_sock,SIOCSIFADDR,&ifr) < 0) |
| { |
| LOGE("ioctl SIOCSIFADDR error."); |
| return -3; |
| } |
| |
| #if 1 |
| #if 1 |
| //netmask |
| if(mask) { |
| if(inet_aton(mask,&(sin->sin_addr)) < 0) |
| { |
| LOGE("inet_pton error."); |
| return -4; |
| } |
| |
| if(ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0) |
| { |
| LOGE("ioctl error."); |
| return -5; |
| } |
| } |
| #else |
| |
| //struct ifreq ifr; |
| //strcpy(ifr.ifr_name, interface_name); |
| struct sockaddr_in netmask_addr; |
| bzero(&netmask_addr, sizeof(struct sockaddr_in)); |
| netmask_addr.sin_family = PF_INET; |
| inet_aton(mask, &netmask_addr.sin_addr); |
| memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr, |
| sizeof(struct sockaddr_in)); |
| if (ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0) |
| { |
| LOGE("ioctl() fail."); |
| return -1; |
| } |
| #endif |
| #endif |
| |
| #if 0 |
| //gateway |
| memset(&rt, 0, sizeof(struct rtentry)); |
| memset(sin, 0, sizeof(struct sockaddr_in)); |
| sin->sin_family = AF_INET; |
| sin->sin_port = 0; |
| if(inet_aton(gateway, &sin->sin_addr)<0) |
| { |
| LOGE( "inet_aton error." ); |
| } |
| memcpy ( &rt.rt_gateway, sin, sizeof(struct sockaddr_in)); |
| ((struct sockaddr_in *)&rt.rt_dst)->sin_family=AF_INET; |
| ((struct sockaddr_in *)&rt.rt_genmask)->sin_family=AF_INET; |
| rt.rt_flags = RTF_GATEWAY; |
| if (ioctl(ifc_ctl_sock, SIOCADDRT, &rt)<0) |
| { |
| LOGE("ioctl(SIOCADDRT) error in set_default_route\n"); |
| return -1; |
| } |
| #endif |
| return 0; |
| } |
| |
| int mbtk_ifc_set_netmask(const char *ifname, const char *netmask) |
| { |
| int s; |
| if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) |
| { |
| LOGE("Socket"); |
| return -1; |
| } |
| struct ifreq ifr; |
| strcpy(ifr.ifr_name, ifname); |
| struct sockaddr_in netmask_addr; |
| bzero(&netmask_addr, sizeof(struct sockaddr_in)); |
| netmask_addr.sin_family = PF_INET; |
| inet_aton(netmask, &netmask_addr.sin_addr); |
| memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr, |
| sizeof(struct sockaddr_in)); |
| if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0) |
| { |
| LOGE("ioctl"); |
| close(s); |
| return -1; |
| } |
| close(s); |
| return 0; |
| } |
| |
| |
| int mbtk_ifc_get_addr(const char *name, void *addr) |
| { |
| int ret; |
| struct ifreq ifr; |
| ifc_init_ifr(name, &ifr); |
| |
| ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr); |
| LOGD("ifc_get_addr(%s, %x) = %d", name, ifr.ifr_addr, ret); |
| if(ret < 0) return -1; |
| |
| memcpy(addr, &ifr.ifr_addr, sizeof(struct sockaddr)); |
| return 0; |
| } |
| |
| |
| int mbtk_ifc_up(const char *name) |
| { |
| int ret = ifc_set_flags(ifc_ctl_sock, name, IFF_UP, 0); |
| // LOGI("mbtk_ifc_up(%s) = %d", name, ret); |
| return ret; |
| } |
| |
| int mbtk_ifc_down(const char *name) |
| { |
| int ret = ifc_set_flags(ifc_ctl_sock, name, 0, IFF_UP); |
| // LOGI("mbtk_ifc_down(%s) = %d", name, ret); |
| return ret; |
| } |
| |
| int mbtk_ifc_get_hwaddr(const char *name, void *ptr) |
| { |
| int r; |
| struct ifreq ifr; |
| ifc_init_ifr(name, &ifr); |
| |
| r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr); |
| if(r < 0) return -1; |
| |
| memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); |
| return 0; |
| } |
| |
| int mbtk_ifc_get_ifindex(const char *name, int *if_indexp) |
| { |
| int r; |
| struct ifreq ifr; |
| ifc_init_ifr(name, &ifr); |
| |
| r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr); |
| if(r < 0) return -1; |
| |
| *if_indexp = ifr.ifr_ifindex; |
| return 0; |
| } |
| |
| int mbtk_ifc_configure1(const char *ifname, |
| in_addr_t address, |
| uint32_t prefixLength, |
| in_addr_t gateway, |
| in_addr_t netmask) |
| { |
| if(mbtk_ifc_open()) |
| { |
| LOGE("mbtk_ifc_open() fail.", strerror(errno)); |
| return -1; |
| } |
| |
| if (mbtk_ifc_up(ifname)) |
| { |
| LOGE("failed to turn on interface %s: %s", ifname, strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| if (mbtk_ifc_set_addr(ifname, address, netmask)) |
| { |
| LOGE("failed to set ipaddr %s: %s", ipaddr_to_string(address), strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| if (ifc_set_prefixLength(ifname, prefixLength)) |
| { |
| LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| if (ifc_create_default_route1(ifname, gateway)) |
| { |
| LOGE("failed to set default route %s: %s", ipaddr_to_string(gateway), strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| |
| mbtk_ifc_close(); |
| return 0; |
| } |
| |
| int mbtk_ifc_configure2(const char *ifname, |
| const char *ipv4, |
| uint32_t prefixLength, |
| const char *gateway, |
| const char *netmask) |
| { |
| if(mbtk_ifc_open()) |
| { |
| LOGE("mbtk_ifc_open() fail.", strerror(errno)); |
| return -1; |
| } |
| |
| if(ipv4 == NULL) { |
| if (mbtk_ifc_down(ifname)) |
| { |
| LOGE("failed to turn off interface %s: %s", ifname, strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| } else { |
| if (mbtk_ifc_up(ifname)) |
| { |
| LOGE("failed to turn on interface %s: %s", ifname, strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| } |
| |
| if (mbtk_ifc_ip_config(ifname, ipv4, netmask, gateway)) |
| { |
| LOGE("failed to set ipaddr: %s", strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| |
| // mbtk_ifc_set_netmask(ifname, netmask); |
| |
| #if 0 |
| if (ifc_set_prefixLength(ifname, prefixLength)) |
| { |
| LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| #endif |
| |
| #if 0 |
| if (ifc_create_default_route2(ifname, gateway)) |
| { |
| LOGE("failed to set default route: %s", strerror(errno)); |
| mbtk_ifc_close(); |
| return -1; |
| } |
| #endif |
| |
| mbtk_ifc_close(); |
| |
| return 0; |
| } |
| |
| struct in6_ifreq { |
| struct in6_addr addr; |
| uint32_t prefixlen; |
| unsigned int ifindex; |
| }; |
| |
| int mbtk_ipv6_config(const char *ifname, const char *ipv6, uint32_t prefixLength) |
| { |
| struct ifreq ifr; |
| struct in6_ifreq ifr6; |
| int sockfd; |
| int err = 0; |
| |
| // Create IPv6 socket to perform the ioctl operations on |
| sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP); |
| if(sockfd < 0) { |
| LOGE("socket() fail.[%d]", errno); |
| return -1; |
| } |
| |
| if(ipv6) { |
| if(ifc_set_flags(sockfd, ifname, IFF_UP, 0) < 0) { |
| LOGE("if up fail[%d].", errno); |
| err = -1; |
| goto exit; |
| } |
| |
| // Copy the interface name to the ifreq struct |
| strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
| // Get the ifrindex of the interface |
| if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0) |
| { |
| LOGE("ioctl SIOGIFINDEX error."); |
| err = -1; |
| goto exit; |
| } |
| |
| // Prepare the in6_ifreq struct and set the address to the interface |
| if(inet_pton(AF_INET6, ipv6, &ifr6.addr) < 0) { |
| LOGE("inet_pton() fail[%d].", errno); |
| err = -1; |
| goto exit; |
| } |
| } else { |
| if(ifc_set_flags(sockfd, ifname, 0, IFF_UP) < 0) { |
| LOGE("if down fail[%d].", errno); |
| err = -1; |
| goto exit; |
| } |
| |
| // Copy the interface name to the ifreq struct |
| strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
| // Get the ifrindex of the interface |
| if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0) |
| { |
| LOGE("ioctl SIOGIFINDEX error."); |
| err = -1; |
| goto exit; |
| } |
| |
| // Set IPv6 to 0. |
| memset(&(ifr6.addr), 0, sizeof(struct in6_addr)); |
| } |
| ifr6.ifindex = ifr.ifr_ifindex; |
| ifr6.prefixlen = prefixLength; |
| if(ioctl(sockfd, SIOCSIFADDR, &ifr6) < 0) { |
| LOGE("ioctl SIOCSIFADDR error."); |
| err = -1; |
| goto exit; |
| } |
| |
| LOGD("Set IPv6 : %s success.", ipv6); |
| exit: |
| close(socket); |
| return err; |
| } |