Put new linux-specific interface listing routine in that is needed

for android, where the portable method isn't easily available.
This commit is contained in:
gardners 2012-04-28 12:25:19 +09:30
parent 6fad530b28
commit 2ab32197a7
5 changed files with 193 additions and 64 deletions

View File

@ -64,7 +64,8 @@ LOCAL_SRC_FILES:= \
serval-dna/simulate.c \
serval-dna/srandomdev.c \
serval-dna/keyring.c \
serval-dna/vomp.c
serval-dna/vomp.c \
serval-dna/lsif.c
LOCAL_MODULE:= serval

View File

@ -37,7 +37,8 @@ SRCS= batman.c \
sqlite3.c \
srandomdev.c \
trans_cache.c \
vomp.c
vomp.c \
lsif.c
HAVE_VOIPTEST= @HAVE_VOIPTEST@
ifeq ($(HAVE_VOIPTEST), 1)

109
lsif.c Normal file
View File

@ -0,0 +1,109 @@
/*
* Derived from https://github.com/ajrisi/lsif/blob/master/lsif.c
* No copyright information in the file, and published publicly,
* so presume no rights reserved.
*
* This method doesn't work properly on OSX, but is for Android where no other
* option seems to work. Should work on any linux system.
* ********************************
*
* Updated code to obtain IP and MAC address for all "up" network
* interfaces on a linux system. Now IPv6 friendly and updated to use
* inet_ntop instead of the deprecated inet_ntoa function. This version
* should not seg fault on newer linux systems
*
* Version 2.0
*
* Authors:
* Adam Pierce
* Adam Risi
* William Schaub
*
* Date: 11/11/2009
* http://www.adamrisi.com
* http://www.doctort.org/adam/
* http://teotwawki.steubentech.com/
*
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#if __MACH__ || __NetBSD__ || __OpenBSD__ || __FreeBSD__
#include <sys/sysctl.h>
#endif
/* Include sockio.h if needed */
#ifndef SIOCGIFCONF
#include <sys/sockio.h>
#endif
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#if __MACH__
#include <net/if_dl.h>
#endif
/* On platforms that have variable length
ifreq use the old fixed length interface instead */
#ifdef OSIOCGIFCONF
#undef SIOCGIFCONF
#define SIOCGIFCONF OSIOCGIFCONF
#undef SIOCGIFADDR
#define SIOCGIFADDR OSIOCGIFADDR
#undef SIOCGIFBRDADDR
#define SIOCGIFBRDADDR OSIOCGIFBRDADDR
#endif
#ifdef HAVE_LINUX_IF_H
int lsif(void)
{
char buf[8192] = {0};
struct ifconf ifc = {0};
struct ifreq *ifr = NULL;
int sck = 0;
int nInterfaces = 0;
int i = 0;
struct ifreq *item;
struct sockaddr_in local,broadcast;
/* Get a socket handle. */
sck = socket(PF_INET, SOCK_DGRAM, 0);
if(sck < 0) {
return 1;
}
/* Query available interfaces. */
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if(ioctl(sck, SIOCGIFCONF, &ifc) < 0) {
return 1;
}
/* Iterate through the list of interfaces. */
ifr = ifc.ifc_req;
nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
for(i = 0; i < nInterfaces; i++) {
item = &ifr[i];
bcopy(&item->ifr_addr,&local,sizeof(local));
/* get broadcast address */
if(ioctl(sck, SIOCGIFBRDADDR, item)== 0) {
bcopy(&item->ifr_broadaddr,&broadcast,sizeof(broadcast));
} else continue;
printf("name=%s addr=%08x, broad=%08x\n",
item->ifr_name,
local.sin_addr,
broadcast.sin_addr);
overlay_interface_register(item->ifr_name,local,broadcast);
}
return 0;
}
#endif

View File

@ -175,13 +175,11 @@ int overlay_interface_args(char *arg)
return 0;
}
int overlay_interface_init_socket(int interface,struct sockaddr_in src_addr,struct sockaddr_in broadcast,
struct sockaddr_in netmask)
int overlay_interface_init_socket(int interface,struct sockaddr_in src_addr,struct sockaddr_in broadcast)
{
#define I(X) overlay_interfaces[interface].X
I(local_address)=src_addr;
I(broadcast_address)=broadcast;
I(netmask)=netmask;
I(fileP)=0;
I(fd)=socket(PF_INET,SOCK_DGRAM,0);
@ -219,7 +217,7 @@ int overlay_interface_init_socket(int interface,struct sockaddr_in src_addr,stru
}
int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockaddr_in broadcast,
struct sockaddr_in netmask,int speed_in_bits,int port,int type)
int speed_in_bits,int port,int type)
{
/* Too many interfaces */
if (overlay_interface_count>=OVERLAY_MAX_INTERFACES) return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES");
@ -258,7 +256,7 @@ int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockadd
/* XXX later add pretend location information so that we can decide which "packets" to receive
based on closeness */
} else {
if (overlay_interface_init_socket(overlay_interface_count,src_addr,broadcast,netmask))
if (overlay_interface_init_socket(overlay_interface_count,src_addr,broadcast))
return WHY("overlay_interface_init_socket() failed");
}
@ -477,6 +475,52 @@ int overlay_sendto(struct sockaddr_in *recipientaddr,unsigned char *bytes,int le
return len;
}
int overlay_interface_register(unsigned char *name,
struct sockaddr_in local,
struct sockaddr_in broadcast)
{
/* Now register the interface, or update the existing interface registration */
struct interface_rules *r=interface_filter,*me=NULL;
while(r) {
if (!strcasecmp((char *)name,r->namespec)) me=r;
if (!r->namespec[0]) me=r;
r=r->next;
}
if (me&&(!me->excludeP)) {
if (debug&DEBUG_OVERLAYINTERFACES)
fprintf(stderr,"Interface %s is interesting.\n",name);
/* We should register or update this interface. */
int i;
for(i=0;i<overlay_interface_count;i++) if (!strcasecmp(overlay_interfaces[i].name,(char *)name)) break;
if (i<overlay_interface_count) {
/* We already know about this interface, so just update it */
if ((overlay_interfaces[i].local_address.sin_addr.s_addr==local.sin_addr.s_addr)&&
(overlay_interfaces[i].broadcast_address.sin_addr.s_addr==broadcast.sin_addr.s_addr))
{
/* Mark it as being seen */
overlay_interfaces[i].observed=1;
return 0;
}
else
{
/* Interface has changed */
close(overlay_interfaces[i].fd);
if (overlay_interface_init_socket(i,local,broadcast))
WHY("Could not reinitialise changed interface");
}
}
else {
/* New interface, so register it */
if (overlay_interface_init((char *)name,local,broadcast,
me->speed_in_bits,me->port,me->type))
WHY("Could not initialise newly seen interface");
else
if (debug&DEBUG_OVERLAYINTERFACES) fprintf(stderr,"Registered interface %s\n",name);
}
}
return 0;
}
time_t overlay_last_interface_discover_time=0;
int overlay_interface_discover()
{
@ -485,16 +529,15 @@ int overlay_interface_discover()
if ((time(0)-overlay_last_interface_discover_time)<2) return 0;
overlay_last_interface_discover_time=time(0);
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifaddr,*ifa;
int family,i;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddr()");
return WHY("getifaddrs() failed");
}
/* The Android ndk doesn't have ifaddrs.h, so we have to use the netlink interface.
However, netlink is only available on Linux, so for BSD systems, e.g., Mac, we
need to use the ifaddrs method.
Also, ifaddrs will work on non-linux systems which is considered critical.
*/
/* Mark all interfaces as not observed, so that we know if we need to cull any */
int i;
for(i=0;i<overlay_interface_count;i++) overlay_interfaces[i].observed--;
/* Check through for any virtual dummy interfaces */
@ -508,7 +551,7 @@ int overlay_interface_discover()
else {
/* New interface, so register it */
struct sockaddr_in dummyaddr;
if (overlay_interface_init(r->namespec,dummyaddr,dummyaddr,dummyaddr,
if (overlay_interface_init(r->namespec,dummyaddr,dummyaddr,
1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI))
WHY("Could not initialise newly seen interface");
else
@ -518,6 +561,15 @@ int overlay_interface_discover()
r=r->next;
}
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifaddr,*ifa;
int family;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddr()");
return WHY("getifaddrs() failed");
}
/* Check through actual network interfaces */
for (ifa=ifaddr;ifa!=NULL;ifa=ifa->ifa_next) {
family=ifa->ifa_addr->sa_family;
@ -527,56 +579,24 @@ int overlay_interface_discover()
unsigned char *name=(unsigned char *)ifa->ifa_name;
struct sockaddr_in local=*(struct sockaddr_in *)ifa->ifa_addr;
struct sockaddr_in netmask=*(struct sockaddr_in *)ifa->ifa_netmask;
unsigned int broadcast_bits=local.sin_addr.s_addr|~netmask.sin_addr.s_addr;
struct sockaddr_in broadcast=local;
broadcast.sin_addr.s_addr=broadcast_bits;
struct sockaddr_in broadcast=local;
if (debug&DEBUG_OVERLAYINTERFACES) printf("%s: %08x %08x %08x\n",name,local.sin_addr.s_addr,netmask.sin_addr.s_addr,broadcast.sin_addr.s_addr);
/* Now register the interface, or update the existing interface registration */
struct interface_rules *r=interface_filter,*me=NULL;
while(r) {
if (!strcasecmp((char *)name,r->namespec)) me=r;
if (!r->namespec[0]) me=r;
r=r->next;
}
if (me&&(!me->excludeP)) {
if (debug&DEBUG_OVERLAYINTERFACES)
fprintf(stderr,"Interface %s is interesting.\n",name);
/* We should register or update this interface. */
int i;
for(i=0;i<overlay_interface_count;i++) if (!strcasecmp(overlay_interfaces[i].name,(char *)name)) break;
if (i<overlay_interface_count) {
/* We already know about this interface, so just update it */
if ((overlay_interfaces[i].local_address.sin_addr.s_addr==local.sin_addr.s_addr)&&
(overlay_interfaces[i].broadcast_address.sin_addr.s_addr==broadcast.sin_addr.s_addr)&&
(overlay_interfaces[i].netmask.sin_addr.s_addr==netmask.sin_addr.s_addr))
{
/* Mark it as being seen */
overlay_interfaces[i].observed=1;
continue;
}
else
{
/* Interface has changed */
close(overlay_interfaces[i].fd);
if (overlay_interface_init_socket(i,local,broadcast,netmask))
WHY("Could not reinitialise changed interface");
}
}
else {
/* New interface, so register it */
if (overlay_interface_init((char *)name,local,broadcast,netmask,
me->speed_in_bits,me->port,me->type))
WHY("Could not initialise newly seen interface");
else
if (debug&DEBUG_OVERLAYINTERFACES) fprintf(stderr,"Registered interface %s\n",name);
}
}
overlay_interface_register(name,local,broadcast);
break;
}
}
}
freeifaddrs(ifaddr);
#else
#ifdef HAVE_LINUX_IF_H
/* Use alternative linux-only method to find and register interfaces. */
lsif();
#else
#error Don't know how to get interface list on this platform
#endif
#endif
return 0;
}
@ -689,7 +709,7 @@ int overlay_stuff_packet_from_queue(int i,overlay_buffer *e,int q,long long now,
/* Consider next in queue */
p=&(*p)->next;
if (0) printf("D p=%p, *p=%p, queue=%d\n",p,p?*p:-1,q);
if (0) printf("D p=%p, *p=%p, queue=%d\n",p,p?*p:NULL,q);
}
if (0) printf("returning from stuffing\n");
return 0;

View File

@ -603,7 +603,6 @@ typedef struct overlay_interface {
/* Broadcast address and netmask, if known */
struct sockaddr_in local_address;
struct sockaddr_in broadcast_address;
struct sockaddr_in netmask;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX on this interface.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
@ -756,9 +755,8 @@ overlay_frame *op_dup(overlay_frame *f);
long long parse_quantity(char *q);
int overlay_interface_init(char *name,struct sockaddr_in src_addr,struct sockaddr_in broadcast,
struct sockaddr_in netmask,int speed_in_bits,int port,int type);
int overlay_interface_init_socket(int i,struct sockaddr_in src_addr,struct sockaddr_in broadcast,
struct sockaddr_in netmask);
int speed_in_bits,int port,int type);
int overlay_interface_init_socket(int i,struct sockaddr_in src_addr,struct sockaddr_in broadcast);
int overlay_interface_discover();
int overlay_interface_discover();
long long overlay_time_until_next_tick();