因为要解决Android4.4.2系统Ethernet 设置断电重启后,IP地址子网掩码等设置无效的问题,故对底层用到的 libnetutils 代码做了简单的分析
/system/core/libnetutils/ifc_utils.c ----- libnetutils的核心接口文件
主要用到了如下几个函数
1》 open close
int ifc_init(void)
{
int ret;
if (ifc_ctl_sock == -1) {
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (ifc_ctl_sock < 0) {
printerr("socket() failed: %s\n", strerror(errno));
}
}
ret = ifc_ctl_sock < 0 ? -1 : 0;
if (DBG) printerr("ifc_init_returning %d", ret);
return ret;
}
int ifc_init6(void)
{
if (ifc_ctl_sock6 == -1) {
ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
if (ifc_ctl_sock6 < 0) {
printerr("socket() failed: %s\n", strerror(errno));
}
}
return ifc_ctl_sock6 < 0 ? -1 : 0;
}
void ifc_close(void)
{
if (DBG) printerr("ifc_close");
if (ifc_ctl_sock != -1) {
(void)close(ifc_ctl_sock);
ifc_ctl_sock = -1;
}
}
void ifc_close6(void)
{
if (ifc_ctl_sock6 != -1) {
(void)close(ifc_ctl_sock6);
ifc_ctl_sock6 = -1;
}
}
分为IPV4和IPV6两种接口,通过 socket 方法实现
2》 通过 ioctl 实现对 Out-of-band(带外)数据的读写,实现IP地址 子网掩码等参数的管理
int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
if (addr != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
*addr = 0;
} else {
*addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
}
}
if (prefixLength != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
*prefixLength = 0;
} else {
*prefixLength = ipv4NetmaskToPrefixLength(
((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr);
}
}
if (flags != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
*flags = 0;
} else {
*flags = ifr.ifr_flags;
}
}
return 0;
}
3》下面三个函数实现了网卡的开关复位操作
int ifc_enable(const char *ifname)
{
int result;
ifc_init();
result = ifc_up(ifname);
ifc_close();
return result;
}
int ifc_disable(const char *ifname)
{
unsigned addr, count;
int result;
ifc_init();
result = ifc_down(ifname);
ifc_set_addr(ifname, 0);
for (count=0, addr=1;((addr != 0) && (count < 255)); count++) {
if (ifc_get_addr(ifname, &addr) < 0)
break;
if (addr)
ifc_set_addr(ifname, 0);
}
ifc_close();
return result;
}
int ifc_reset_connections(const char *ifname, const int reset_mask)
{
#ifdef HAVE_ANDROID_OS
int result, success;
in_addr_t myaddr;
struct ifreq ifr;
struct in6_ifreq ifr6;
if (reset_mask & RESET_IPV4_ADDRESSES) {
/* IPv4. Clear connections on the IP address. */
ifc_init();
ifc_get_info(ifname, &myaddr, NULL, NULL);
ifc_init_ifr(ifname, &ifr);
init_sockaddr_in(&ifr.ifr_addr, myaddr);
result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
ifc_close();
} else {
result = 0;
}
if (reset_mask & RESET_IPV6_ADDRESSES) {
/*
* IPv6. On Linux, when an interface goes down it loses all its IPv6
* addresses, so we don't know which connections belonged to that interface
* So we clear all unused IPv6 connections on the device by specifying an
* empty IPv6 address.
*/
ifc_init6();
// This implicitly specifies an address of ::, i.e., kill all IPv6 sockets.
memset(&ifr6, 0, sizeof(ifr6));
success = ioctl(ifc_ctl_sock6, SIOCKILLADDR, &ifr6);
if (result == 0) {
result = success;
}
ifc_close6();
}
return result;
#else
return 0;
#endif
}
注:关于 ioctl
控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。用于向设备发控制和配置命令 ,有些命令需要控制参数,这些数据是不能用read / write 读写的,称为Out-of-band数据。也就是说,read / write 读写的数据是in-band数据,是I/O操作的主体,而ioctl 命令传送的是控制信息,其中的数据是辅助的数据。