blob: 3a7b24bdd1a703118e6954e1200b66b2a7c3cc97 [file] [log] [blame]
/*
* 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;
}
#if 0
/* 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;
}
#endif
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:
mbtk_close(sockfd);
return err;
}