源代码位于: system/core/libnetutils/*
0605$ ls system/core/libnetutils/
Android.mk dhcpclient.c dhcpmsg.c dhcpmsg.h dhcp_utils.c ifc_utils.c ifc_utils.c~ NOTICE packet.c packet.h
1. ifc_init(), ifc_close() :
int ifc_init(void)
{
int ret;
if (ifc_ctl_sock == -1) {
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); //socket通信
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); // close socket
ifc_ctl_sock = -1;
}
}
void ifc_close6(void)
{
if (ifc_ctl_sock6 != -1) {
(void)close(ifc_ctl_sock6);
ifc_ctl_sock6 = -1;
}
}
2. ifc_up(), ifc_down():
int ifc_up(const char *name)
{
int ret = ifc_set_flags(name, IFF_UP, 0);
if (DBG) printerr("ifc_up(%s) = %d", name, ret);
return ret;
}
int ifc_down(const char *name)
{
int ret = ifc_set_flags(name, 0, IFF_UP);
if (DBG) printerr("ifc_down(%s) = %d", name, ret);
return ret;
}
static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
}
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;
}
3. ifc_enable(), ifc_disable():
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;
}
d. int ifc_set_addr(const char *name, in_addr_t addr)
int ifc_set_addr(const char *name, in_addr_t addr)
{
struct ifreq ifr;
int ret;
ifc_init_ifr(name, &ifr);
init_sockaddr_in(&ifr.ifr_addr, addr);
ret = ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
if (DBG) printerr("ifc_set_addr(%s, xx) = %d", name, ret);
return ret;
}
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;
}
4. int ifc_reset_connections(const char *ifname, const int reset_mask)
#define RESET_IPV4_ADDRESSES 0x01
#define RESET_IPV6_ADDRESSES 0x02
#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
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
}
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((int)
((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;
}
5. int ifc_remove_default_route(const char *ifname):
/*
* Removes the default route for the named interface.
*/
int ifc_remove_default_route(const char *ifname)
{
struct rtentry rt;
int result;
ifc_init();
memset(&rt, 0, sizeof(rt));
rt.rt_dev = (void *)ifname;
rt.rt_flags = RTF_UP|RTF_GATEWAY;
init_sockaddr_in(&rt.rt_dst, 0);
if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
}
if (ifc_set_addr(ifname, 0)) {
printerr("failed to set ipaddr to 0 : %s\n", strerror(errno));
}
ifc_close();
return result;
}
6. ifc_configure()
int
ifc_configure(const char *ifname,
in_addr_t address,
in_addr_t prefixLength,
in_addr_t gateway,
in_addr_t dns1,
in_addr_t dns2) {
char dns_prop_name[PROPERTY_KEY_MAX];
ifc_init();
if (ifc_up(ifname)) {
printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
ifc_close();
return -1;
}
if (ifc_set_addr(ifname, address)) {
printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
ifc_close();
return -1;
}
if (ifc_set_prefixLength(ifname, prefixLength)) {
printerr("failed to set prefixLength %d: %s\n", prefixLength, strerror(errno));
ifc_close();
return -1;
}
if (ifc_create_default_route(ifname, gateway)) {
printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
ifc_close();
return -1;
}
ifc_close();
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
return 0;
}