aboutsummaryrefslogtreecommitdiffstats
path: root/ifaddrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'ifaddrs.c')
-rw-r--r--ifaddrs.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/ifaddrs.c b/ifaddrs.c
new file mode 100644
index 0000000..cb8fd76
--- /dev/null
+++ b/ifaddrs.c
@@ -0,0 +1,146 @@
+/* external/dhcpcd/ifaddrs.c
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");.
+** you may not use this file except in compliance with the License..
+** You may obtain a copy of the License at.
+**
+** http://www.apache.org/licenses/LICENSE-2.0.
+**
+** Unless required by applicable law or agreed to in writing, software.
+** distributed under the License is distributed on an "AS IS" BASIS,.
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied..
+** See the License for the specific language governing permissions and.
+** limitations under the License.
+*/
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include "ifaddrs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <netinet/ether.h>
+#include <netdb.h>
+#include <linux/if_packet.h>
+#include <netinet/if_ether.h>
+#include <linux/if_arp.h>
+#include <netutils/ifc.h>
+
+struct ifaddrs *get_interface(const char *name, sa_family_t family)
+{
+ unsigned addr, mask, flags;
+ struct ifaddrs *ifa;
+ struct sockaddr_in *saddr = NULL;
+ struct sockaddr_in *smask = NULL;
+ struct sockaddr_ll *hwaddr = NULL;
+ unsigned char hwbuf[ETH_ALEN];
+
+ if(ifc_get_info(name, &addr, &mask, &flags))
+ return NULL;
+
+ if ((family == AF_INET) && (addr == 0))
+ return NULL;
+
+ ifa = malloc(sizeof(struct ifaddrs));
+ if (!ifa)
+ return NULL;
+ memset(ifa, 0, sizeof(struct ifaddrs));
+
+ ifa->ifa_name = malloc(strlen(name)+1);
+ if (!ifa->ifa_name) {
+ free(ifa);
+ return NULL;
+ }
+ strcpy(ifa->ifa_name, name);
+ ifa->ifa_flags = flags;
+
+ if (family == AF_INET) {
+ saddr = malloc(sizeof(struct sockaddr_in));
+ if (saddr) {
+ saddr->sin_addr.s_addr = addr;
+ saddr->sin_family = family;
+ }
+ ifa->ifa_addr = (struct sockaddr *)saddr;
+
+ if (mask != 0) {
+ smask = malloc(sizeof(struct sockaddr_in));
+ if (smask) {
+ smask->sin_addr.s_addr = mask;
+ smask->sin_family = family;
+ }
+ }
+ ifa->ifa_netmask = (struct sockaddr *)smask;
+ } else if (family == AF_PACKET) {
+ if (!ifc_get_hwaddr(name, hwbuf)) {
+ hwaddr = malloc(sizeof(struct sockaddr_ll));
+ if (hwaddr) {
+ memset(hwaddr, 0, sizeof(struct sockaddr_ll));
+ hwaddr->sll_family = family;
+ /* hwaddr->sll_protocol = ETHERTYPE_IP; */
+ hwaddr->sll_hatype = ARPHRD_ETHER;
+ hwaddr->sll_halen = ETH_ALEN;
+ memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN);
+ }
+ }
+ ifa->ifa_addr = (struct sockaddr *)hwaddr;
+ ifa->ifa_netmask = (struct sockaddr *)smask;
+ }
+ return ifa;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+ DIR *d;
+ struct dirent *de;
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifah = NULL;
+
+ if (!ifap)
+ return -1;
+ *ifap = NULL;
+
+ if (ifc_init())
+ return -1;
+
+ d = opendir("/sys/class/net");
+ if (d == 0)
+ return -1;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ ifa = get_interface(de->d_name, AF_INET);
+ if (ifa != NULL) {
+ ifa->ifa_next = ifah;
+ ifah = ifa;
+ }
+ ifa = get_interface(de->d_name, AF_PACKET);
+ if (ifa != NULL) {
+ ifa->ifa_next = ifah;
+ ifah = ifa;
+ }
+ }
+ *ifap = ifah;
+ closedir(d);
+ ifc_close();
+ return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+ struct ifaddrs *ifp;
+
+ while (ifa) {
+ ifp = ifa;
+ free(ifp->ifa_name);
+ if (ifp->ifa_addr)
+ free(ifp->ifa_addr);
+ if (ifp->ifa_netmask)
+ free(ifp->ifa_netmask);
+ ifa = ifa->ifa_next;
+ free(ifp);
+ }
+}