Home | History | Annotate | Download | only in dhcpcd
      1 /* external/dhcpcd/ifaddrs.c
      2 **
      3 ** Copyright 2011, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");.
      6 ** you may not use this file except in compliance with the License..
      7 ** You may obtain a copy of the License at.
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0.
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software.
     12 ** distributed under the License is distributed on an "AS IS" BASIS,.
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied..
     14 ** See the License for the specific language governing permissions and.
     15 ** limitations under the License.
     16 */
     17 
     18 #include <arpa/inet.h>
     19 #include <sys/socket.h>
     20 #include "ifaddrs.h"
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <sys/types.h>
     26 #include <dirent.h>
     27 #include <netinet/ether.h>
     28 #include <netdb.h>
     29 #include <linux/if_packet.h>
     30 #include <netinet/if_ether.h>
     31 #include <linux/if_arp.h>
     32 #include <netutils/ifc.h>
     33 
     34 struct ifaddrs *get_interface(const char *name, sa_family_t family)
     35 {
     36     unsigned addr, flags;
     37     int masklen;
     38     struct ifaddrs *ifa;
     39     struct sockaddr_in *saddr = NULL;
     40     struct sockaddr_in *smask = NULL;
     41     struct sockaddr_ll *hwaddr = NULL;
     42     unsigned char hwbuf[ETH_ALEN];
     43 
     44     if (ifc_get_info(name, &addr, &masklen, &flags))
     45         return NULL;
     46 
     47     if ((family == AF_INET) && (addr == 0))
     48         return NULL;
     49 
     50     ifa = malloc(sizeof(struct ifaddrs));
     51     if (!ifa)
     52         return NULL;
     53     memset(ifa, 0, sizeof(struct ifaddrs));
     54 
     55     ifa->ifa_name = malloc(strlen(name)+1);
     56     if (!ifa->ifa_name) {
     57         free(ifa);
     58         return NULL;
     59     }
     60     strcpy(ifa->ifa_name, name);
     61     ifa->ifa_flags = flags;
     62 
     63     if (family == AF_INET) {
     64         saddr = malloc(sizeof(struct sockaddr_in));
     65         if (saddr) {
     66             saddr->sin_addr.s_addr = addr;
     67             saddr->sin_family = family;
     68         }
     69         ifa->ifa_addr = (struct sockaddr *)saddr;
     70 
     71         if (masklen != 0) {
     72             smask = malloc(sizeof(struct sockaddr_in));
     73             if (smask) {
     74                 smask->sin_addr.s_addr = prefixLengthToIpv4Netmask(masklen);
     75                 smask->sin_family = family;
     76             }
     77         }
     78         ifa->ifa_netmask = (struct sockaddr *)smask;
     79     } else if (family == AF_PACKET) {
     80         if (!ifc_get_hwaddr(name, hwbuf)) {
     81             hwaddr = malloc(sizeof(struct sockaddr_ll));
     82             if (hwaddr) {
     83                 memset(hwaddr, 0, sizeof(struct sockaddr_ll));
     84                 hwaddr->sll_family = family;
     85                 /* hwaddr->sll_protocol = ETHERTYPE_IP; */
     86                 hwaddr->sll_hatype = ARPHRD_ETHER;
     87                 hwaddr->sll_halen = ETH_ALEN;
     88                 memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN);
     89             }
     90         }
     91         ifa->ifa_addr = (struct sockaddr *)hwaddr;
     92         ifa->ifa_netmask = (struct sockaddr *)smask;
     93     }
     94     return ifa;
     95 }
     96 
     97 int getifaddrs(struct ifaddrs **ifap)
     98 {
     99     DIR *d;
    100     struct dirent *de;
    101     struct ifaddrs *ifa;
    102     struct ifaddrs *ifah = NULL;
    103 
    104     if (!ifap)
    105         return -1;
    106     *ifap = NULL;
    107 
    108     if (ifc_init())
    109        return -1;
    110 
    111     d = opendir("/sys/class/net");
    112     if (d == 0)
    113         return -1;
    114     while ((de = readdir(d))) {
    115         if (de->d_name[0] == '.')
    116             continue;
    117         ifa = get_interface(de->d_name, AF_INET);
    118         if (ifa != NULL) {
    119             ifa->ifa_next = ifah;
    120             ifah = ifa;
    121         }
    122         ifa = get_interface(de->d_name, AF_PACKET);
    123         if (ifa != NULL) {
    124             ifa->ifa_next = ifah;
    125             ifah = ifa;
    126         }
    127     }
    128     *ifap = ifah;
    129     closedir(d);
    130     ifc_close();
    131     return 0;
    132 }
    133 
    134 void freeifaddrs(struct ifaddrs *ifa)
    135 {
    136     struct ifaddrs *ifp;
    137 
    138     while (ifa) {
    139         ifp = ifa;
    140         free(ifp->ifa_name);
    141         if (ifp->ifa_addr)
    142             free(ifp->ifa_addr);
    143         if (ifp->ifa_netmask)
    144             free(ifp->ifa_netmask);
    145         ifa = ifa->ifa_next;
    146         free(ifp);
    147     }
    148 }
    149