/* Serval Distributed Numbering Architecture (DNA) Copyright (C) 2010 Paul Gardner-Stephen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "serval.h" #include "strbuf.h" #include "overlay_buffer.h" #include "overlay_packet.h" #include "str.h" #ifdef HAVE_IFADDRS_H #include #endif int overlay_ready=0; int overlay_interface_count=0; overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; int overlay_last_interface_number=-1; struct interface_rules { char *namespec; unsigned long long speed_in_bits; int port; char type; char excludeP; struct interface_rules *next; }; struct interface_rules *interface_filter=NULL; struct profile_total interface_poll_stats; struct profile_total dummy_poll_stats; struct sched_ent sock_any; struct sockaddr_in sock_any_addr; struct profile_total sock_any_stats; static void overlay_interface_poll(struct sched_ent *alarm); static void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len); static long long parse_quantity(char *q); #define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __WHENCE__, (M), (P), (N)) static int overlay_interface_type(char *s) { if (!strcasecmp(s,"ethernet")) return OVERLAY_INTERFACE_ETHERNET; if (!strcasecmp(s,"wifi")) return OVERLAY_INTERFACE_WIFI; if (!strcasecmp(s,"other")) return OVERLAY_INTERFACE_UNKNOWN; if (!strcasecmp(s,"catear")) return OVERLAY_INTERFACE_PACKETRADIO; return WHY("Invalid interface type -- consider using 'wifi','ethernet' or 'other'"); } static long long parse_quantity(char *q) { if (strlen(q) >= 80) return WHY("quantity string >=80 characters"); long long result; if (str_to_ll_scaled(q, 10, &result, NULL)) return result; return WHYF("Illegal quantity: %s", alloca_str_toprint(q)); } int overlay_interface_arg(char *arg) { /* Parse an interface argument, of the form: <+|->[interfacename][=type] +interface tells DNA to sit on that interface -interface tells DNA to not sit on that interface +/- without an interface tells DNA to sit on all interfaces. The first match rules, so -en0+ tells DNA to use all interfaces, excepting en0 The optional =type specifier tells DNA how to handle the interface in terms of bandwidth:distance relationship for calculating tick times etc. The special type =custom allows full specification: XXX - Settle the custom specification now that we have changed the interface management. */ char sign[80]="+"; char interface_name[80]=""; char speed[80]="1m"; char typestring[80]="wifi"; int port=PORT_DNA; int type=OVERLAY_INTERFACE_UNKNOWN; int n=0; /* Too long */ if (strlen(arg)>79) return WHY("interface specification was >79 characters"); struct interface_rules *r=calloc(sizeof(struct interface_rules),1); if (!r) return WHY("calloc(struct interface rules),1) failed"); if (sscanf(arg,"%[+-]%n%[^=:,]%n=%[^:]%n:%d%n:%[^:]%n", sign,&n,interface_name,&n,typestring,&n,&port,&n,speed,&n)>=1) { if (n1) { free(r); return WHY("Sign must be + or -"); } switch(sign[0]) { case '+': break; case '-': r->excludeP=1; break; default: free(r); return WHY("Invalid interface list item: Must begin with + or -"); } long long speed_in_bits=parse_quantity(speed); if (speed_in_bits<=1) { free(r); return WHY("Interfaces must be capable of at least 1 bit per second"); } if (nnamespec=strdup(interface_name); r->speed_in_bits=speed_in_bits; r->port=port; r->type=type; r->next=interface_filter; interface_filter=r; return 0; } else { free(r); return WHY("Bad interface specification"); } } int overlay_interface_args(const char *arg) { /* Parse series of comma-separated interface definitions from a single argument */ int i=0; char interface[80]; int len=0; for(i=0;arg[i];i++) { if (arg[i]==','||arg[i]=='\n') { interface[len]=0; if (overlay_interface_arg(interface)) return WHY("Could not add interface"); len=0; } else { if (len<79) { interface[len++]=arg[i]; interface[len]=0; } else return WHY("Interface definition is too long (each must be <80 characters)"); } } if (len) if (overlay_interface_arg(interface)) return WHY("Could not add final interface"); return 0; } static void overlay_interface_close(overlay_interface *interface){ if (interface->fileP){ INFOF("Interface %s is down", interface->name); }else{ INFOF("Interface %s addr %s is down", interface->name, inet_ntoa(interface->broadcast_address.sin_addr)); } unschedule(&interface->alarm); unwatch(&interface->alarm); close(interface->alarm.poll.fd); interface->alarm.poll.fd=-1; interface->state=INTERFACE_STATE_DOWN; } // create a socket with options common to all our UDP sockets static int overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interface_name){ int fd; int reuseP = 1; int broadcastP = 1; fd = socket(PF_INET,SOCK_DGRAM,0); if (fd < 0) { WHY_perror("Error creating socket"); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) { WHY_perror("setsockopt(SO_REUSEADR)"); goto error; } #ifdef SO_REUSEPORT if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuseP, sizeof(reuseP)) < 0) { WHY_perror("setsockopt(SO_REUSEPORT)"); goto error; } #endif if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcastP, sizeof(broadcastP)) < 0) { WHY_perror("setsockopt(SO_BROADCAST)"); goto error; } /* Automatically close socket on calls to exec(). This makes life easier when we restart with an exec after receiving a bad signal. */ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, NULL) | #ifdef FD_CLOEXEC FD_CLOEXEC #else O_CLOEXEC #endif ); #ifdef SO_BINDTODEVICE /* Limit incoming and outgoing packets to this interface, no matter what the routing table says. This should allow for a device with multiple interfaces on the same subnet. Don't abort if this fails, I believe it requires root, just log it. */ if (interface_name && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, strlen(interface_name)+1) < 0) { WHY_perror("setsockopt(SO_BINDTODEVICE)"); } #endif if (bind(fd, addr, addr_size)) { WHY_perror("Bind failed"); goto error; } return fd; error: close(fd); return -1; } overlay_interface * overlay_interface_find(struct in_addr addr){ int i; overlay_interface *ret = NULL; for (i=0;i'?name+1:name), (*overlay_interfaces[i].name=='>'?overlay_interfaces[i].name+1:overlay_interfaces[i].name) )==0){ return &overlay_interfaces[i]; } } return NULL; } // OSX doesn't recieve broadcast packets on sockets bound to an interface's address // So we have to bind a socket to INADDR_ANY to receive these packets. static void overlay_interface_read_any(struct sched_ent *alarm){ if (alarm->poll.revents & POLLIN) { int plen=0; int recvttl=1; unsigned char packet[16384]; overlay_interface *interface=NULL; struct sockaddr src_addr; socklen_t addrlen = sizeof(src_addr); /* Read only one UDP packet per call to share resources more fairly, and also enable stats to accurately count packets received */ plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &src_addr, &addrlen); if (plen == -1) { WHY_perror("recvwithttl(c)"); unwatch(alarm); close(alarm->poll.fd); return; } struct in_addr src = ((struct sockaddr_in *)&src_addr)->sin_addr; /* Try to identify the real interface that the packet arrived on */ interface = overlay_interface_find(src); /* Drop the packet if we don't find a match */ if (!interface){ if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(src)); return; } /* We have a frame from this interface */ if (debug&DEBUG_PACKETRX) DEBUG_packet_visualise("Read from real interface", packet,plen); if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Received %d bytes from %s on interface %s (ANY)",plen, inet_ntoa(src), interface->name); if (packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen)) { WHY("Malformed packet"); } } if (alarm->poll.revents & (POLLHUP | POLLERR)) { INFO("Closing broadcast socket due to error"); unwatch(alarm); close(alarm->poll.fd); alarm->poll.fd=-1; } } // bind a socket to INADDR_ANY:port // for now, we don't have a graceful close for this interface but it should go away when the process dies static int overlay_interface_init_any(int port){ struct sockaddr_in addr; if (sock_any.poll.fd>0){ // Check the port number matches if (sock_any_addr.sin_port != htons(port)) return WHYF("Unable to listen to broadcast packets for ports %d & %d", port, ntohs(sock_any_addr.sin_port)); return 0; } addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; sock_any.poll.fd = overlay_bind_socket((const struct sockaddr *)&addr, sizeof(addr), NULL); if (sock_any.poll.fd<0) return -1; sock_any_addr = addr; sock_any.poll.events=POLLIN; sock_any.function = overlay_interface_read_any; sock_any_stats.name="overlay_interface_read_any"; sock_any.stats=&sock_any_stats; watch(&sock_any); return 0; } static int overlay_interface_init_socket(int interface_index) { overlay_interface *const interface = &overlay_interfaces[interface_index]; interface->fileP = 0; /* On linux you can bind to the broadcast address to receive broadcast packets per interface [or subnet], but then you can't receive unicast packets on the same socket. On osx, you can only receive broadcast packets if you bind to INADDR_ANY. So the most portable way to do this is to bind to each interface's IP address for sending broadcasts and receiving unicasts, and bind a separate socket to INADDR_ANY just for receiving broadcast packets. Sending packets from INADDR_ANY would probably work, but gives us less control over which interfaces are sending packets. But there may be some platforms that need some other combination for everything to work. */ overlay_interface_init_any(interface->port); const struct sockaddr *addr = (const struct sockaddr *)&interface->address; interface->alarm.poll.fd = overlay_bind_socket(addr, sizeof(interface->broadcast_address), interface->name); if (interface->alarm.poll.fd<0){ interface->state=INTERFACE_STATE_DOWN; return -1; } if (debug & (DEBUG_PACKETRX | DEBUG_IO)){ char srctxt[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, (const void *)&interface->broadcast_address.sin_addr, srctxt, INET_ADDRSTRLEN)) DEBUGF("Bound to %s:%d", srctxt, ntohs(interface->broadcast_address.sin_port)); } interface->alarm.poll.events=POLLIN; interface->alarm.function = overlay_interface_poll; interface_poll_stats.name="overlay_interface_poll"; interface->alarm.stats=&interface_poll_stats; watch(&interface->alarm); if (interface->tick_ms>0){ // run the first tick asap interface->alarm.alarm=gettime_ms(); interface->alarm.deadline=interface->alarm.alarm+10; schedule(&interface->alarm); } interface->state=INTERFACE_STATE_UP; INFOF("Interface %s addr %s, is up",interface->name, inet_ntoa(interface->broadcast_address.sin_addr)); directory_registration(); return 0; } static int overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netmask, struct in_addr broadcast, 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"); overlay_interface *const interface = &overlay_interfaces[overlay_interface_count]; strncpy(interface->name, name, sizeof interface->name); /* Pick a reasonable default MTU. This will ultimately get tuned by the bandwidth and other properties of the interface */ interface->mtu=1200; interface->state=INTERFACE_STATE_DOWN; interface->bits_per_second=speed_in_bits; interface->port=port; interface->type=type; interface->last_tick_ms= -1; // not ticked yet interface->alarm.poll.fd=0; // how often do we announce ourselves on this interface? switch (type) { case OVERLAY_INTERFACE_PACKETRADIO: interface->tick_ms = confValueGetInt64Range("mdp.packetradio.tick_ms", 15000LL, 1LL, 3600000LL); break; case OVERLAY_INTERFACE_ETHERNET: interface->tick_ms = confValueGetInt64Range("mdp.ethernet.tick_ms", 500LL, 1LL, 3600000LL); break; case OVERLAY_INTERFACE_WIFI: interface->tick_ms = confValueGetInt64Range("mdp.wifi.tick_ms", 500LL, 1LL, 3600000LL); break; case OVERLAY_INTERFACE_UNKNOWN: interface->tick_ms = confValueGetInt64Range("mdp.unknown.tick_ms", 500LL, 1LL, 3600000LL); break; default: return WHYF("Unsupported interface type %d", type); } // allow for a per interface override of tick interval { char option_name[64]; snprintf(option_name, sizeof(option_name), "mdp.%s.tick_ms", (*name=='>'?name+1:name)); interface->tick_ms = confValueGetInt64Range(option_name, interface->tick_ms, 1LL, 3600000LL); snprintf(option_name, sizeof(option_name), "interface.%s.default_route", (*name=='>'?name+1:name)); interface->default_route=confValueGetBoolean(option_name,0); } // disable announcements and other broadcasts if tick_ms=0. if (interface->tick_ms>0) interface->send_broadcasts=1; else{ interface->send_broadcasts=0; INFOF("Interface %s is running tickless", name); } if (name[0]=='>') { interface->fileP=1; char dummyfile[1024]; if (name[1]=='/') { /* Absolute path */ snprintf(dummyfile, sizeof(dummyfile), "%s", &name[1]); } else { const char *interface_folder = confValueGet("interface.folder", serval_instancepath()); snprintf(dummyfile, sizeof(dummyfile), "%s/%s", interface_folder, &name[1]); } if ((interface->alarm.poll.fd = open(dummyfile,O_APPEND|O_RDWR)) < 1) { return WHYF("could not open dummy interface file %s for append", dummyfile); } interface->address.sin_family=AF_INET; interface->address.sin_port = 0; interface->address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); interface->netmask.s_addr=0xFFFFFF00; interface->broadcast_address.sin_family=AF_INET; interface->broadcast_address.sin_port = 0; interface->broadcast_address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr; /* Seek to end of file as initial reading point */ interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END); /* XXX later add pretend location information so that we can decide which "packets" to receive based on closeness */ // schedule an alarm for this interface interface->alarm.function=overlay_dummy_poll; interface->alarm.alarm=gettime_ms()+10; interface->alarm.deadline=interface->alarm.alarm; dummy_poll_stats.name="overlay_dummy_poll"; interface->alarm.stats=&dummy_poll_stats; schedule(&interface->alarm); interface->state=INTERFACE_STATE_UP; INFOF("Dummy interface %s is up",interface->name); directory_registration(); } else { interface->netmask = netmask; interface->address.sin_addr = src_addr; interface->address.sin_family = AF_INET; interface->address.sin_port = htons(interface->port); interface->broadcast_address.sin_addr = broadcast; interface->broadcast_address.sin_family = AF_INET; interface->broadcast_address.sin_port = htons(interface->port); if (overlay_interface_init_socket(overlay_interface_count)) return WHY("overlay_interface_init_socket() failed"); } overlay_interface_count++; return 0; } static void overlay_interface_poll(struct sched_ent *alarm) { struct overlay_interface *interface = (overlay_interface *)alarm; if (alarm->poll.revents==0){ if (interface->state==INTERFACE_STATE_UP && interface->tick_ms>0){ // tick the interface time_ms_t now = gettime_ms(); int i = (interface - overlay_interfaces); overlay_tick_interface(i, now); alarm->alarm=now+interface->tick_ms; alarm->deadline=alarm->alarm+interface->tick_ms/2; schedule(alarm); } return; } if (alarm->poll.revents & POLLIN) { int plen=0; unsigned char packet[16384]; struct sockaddr src_addr; socklen_t addrlen = sizeof(src_addr); /* Read only one UDP packet per call to share resources more fairly, and also enable stats to accurately count packets received */ int recvttl=1; plen = recvwithttl(alarm->poll.fd,packet, sizeof(packet), &recvttl, &src_addr, &addrlen); if (plen == -1) { WHY_perror("recvwithttl(c)"); overlay_interface_close(interface); return; } /* We have a frame from this interface */ if (debug&DEBUG_PACKETRX) DEBUG_packet_visualise("Read from real interface", packet,plen); if (debug&DEBUG_OVERLAYINTERFACES) { struct in_addr src = ((struct sockaddr_in *)&src_addr)->sin_addr; // avoid strict-alias warning on Solaris (gcc 4.4) DEBUGF("Received %d bytes from %s on interface %s",plen, inet_ntoa(src), interface->name); } if (packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen)) { WHY("Malformed packet"); // Do we really want to attempt to parse it again? //DEBUG_packet_visualise("Malformed packet", packet,plen); } } if (alarm->poll.revents & (POLLHUP | POLLERR)) { overlay_interface_close(interface); } } void overlay_dummy_poll(struct sched_ent *alarm) { overlay_interface *interface = (overlay_interface *)alarm; /* Grab packets, unpackage and dispatch frames to consumers */ /* XXX Okay, so how are we managing out-of-process consumers? They need some way to register their interest in listening to a port. */ unsigned char packet[2048]; int plen=0; struct sockaddr_in src_addr={ .sin_family = AF_INET, .sin_port = 0, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; size_t addrlen = sizeof(src_addr); time_ms_t now = gettime_ms(); /* Read from dummy interface file */ long long length=lseek(alarm->poll.fd,0,SEEK_END); int new_packets = (length - interface->recv_offset) / sizeof packet; if (new_packets > 20) WARNF("Getting behind, there are %d unread packets", new_packets); if (interface->recv_offset >= length) { /* if there's no input, while we want to check for more soon, we need to allow all other low priority alarms to fire first, otherwise we'll dominate the scheduler without accomplishing anything */ alarm->alarm = gettime_ms() + 5; if (interface->last_tick_ms != -1 && alarm->alarm > interface->last_tick_ms + interface->tick_ms) alarm->alarm = interface->last_tick_ms + interface->tick_ms; alarm->deadline = alarm->alarm + 10000; } else { if (lseek(alarm->poll.fd,interface->recv_offset,SEEK_SET) == -1) WHY_perror("lseek"); else { if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Read interface %s (size=%lld) at offset=%d",interface->name, length, interface->recv_offset); ssize_t nread = read(alarm->poll.fd, packet, sizeof packet); if (nread == -1) WHY_perror("read"); else { if (nread == sizeof packet) { interface->recv_offset += nread; plen = packet[110] + (packet[111] << 8); if (plen > nread - 128) plen = -1; if (debug&DEBUG_PACKETRX) DEBUG_packet_visualise("Read from dummy interface", &packet[128], plen); if (packetOkOverlay(interface, &packet[128], plen, -1, (struct sockaddr*)&src_addr, addrlen)) { WARN("Unsupported packet from dummy interface"); } } else WARNF("Read %lld bytes from dummy interface", nread); } } /* keep reading new packets as fast as possible, but don't completely prevent other high priority alarms */ if (interface->recv_offset >= length) alarm->alarm = gettime_ms() + 5; else alarm->alarm = gettime_ms(); alarm->deadline = alarm->alarm + 100; } // only tick the interface if we've caught up reading all the packets if (interface->recv_offset >= length && interface->tick_ms>0 && (interface->last_tick_ms == -1 || now >= interface->last_tick_ms + interface->tick_ms)) { // tick the interface int i = (interface - overlay_interfaces); overlay_tick_interface(i, now); } schedule(alarm); return ; } int overlay_broadcast_ensemble(int interface_number, struct sockaddr_in *recipientaddr, unsigned char *bytes,int len) { if (debug&DEBUG_PACKETTX) { DEBUGF("Sending this packet via interface #%d",interface_number); DEBUG_packet_visualise(NULL,bytes,len); } overlay_interface *interface = &overlay_interfaces[interface_number]; if (interface->state!=INTERFACE_STATE_UP){ return WHYF("Cannot send to interface %s as it is down", interface->name); } if (interface->fileP) { char buf[2048]; bzero(&buf[0],128); /* Version information */ buf[0]=1; buf[1]=0; buf[2]=0; buf[3]=0; /* PID of creator */ buf[4]=getpid()&0xff; buf[5]=getpid()>>8; /* TODO make a structure for all this stuff */ /* bytes 4-5 = half-power beam height (uint16) */ /* bytes 6-7 = half-power beam width (uint16) */ /* bytes 8-11 = range in metres, centre beam (uint32) */ /* bytes 16-47 = sender */ /* bytes 48-79 = next hop */ /* bytes 80-83 = latitude (uint32) */ /* bytes 84-87 = longitude (uint32) */ /* bytes 88-89 = X/Z direction (uint16) */ /* bytes 90-91 = Y direction (uint16) */ /* bytes 92-93 = speed in metres per second (uint16) */ /* bytes 94-97 = TX frequency in Hz, uncorrected for doppler (which must be done at the receiving end to take into account relative motion) */ /* bytes 98-109 = coding method (use for doppler response etc) null terminated string */ /* bytes 110-111 = length of packet body in bytes */ /* bytes 112-127 reserved for future use */ if (len>2048-128) { WARN("Truncating long packet to fit within 1920 byte limit for dummy interface"); len=2048-128; } /* Record length of packet */ buf[110]=len&0xff; buf[111]=(len>>8)&0xff; bzero(&buf[128+len],2048-(128+len)); bcopy(bytes,&buf[128],len); /* This lseek() is unneccessary because the dummy file is opened in O_APPEND mode. It's only purpose is to find out the offset to print in the DEBUG statement. It is vulnerable to a race condition with other processes appending to the same file. */ off_t fsize = lseek(interface->alarm.poll.fd, (off_t) 0, SEEK_END); if (fsize == -1) return WHY_perror("lseek"); if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Write to interface %s at offset=%d", interface->name, fsize); ssize_t nwrite = write(interface->alarm.poll.fd, buf, 2048); if (nwrite == -1) return WHY_perror("write"); if (nwrite != 2048) return WHYF("only wrote %lld of %lld bytes", nwrite, 2048); return 0; } else { if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Sending %d byte overlay frame on %s to %s",len,interface->name,inet_ntoa(recipientaddr->sin_addr)); if(sendto(interface->alarm.poll.fd, bytes, len, 0, (struct sockaddr *)recipientaddr, sizeof(struct sockaddr_in)) != len){ int e=errno; WHY_perror("sendto(c)"); // only close the interface on some kinds of errors if (e==ENETDOWN || e==EINVAL) overlay_interface_close(interface); return -1; } return 0; } } /* Register the interface, or update the existing interface registration */ int overlay_interface_register(char *name, struct in_addr addr, struct in_addr mask) { struct interface_rules *r, *me; int i; struct in_addr broadcast = {.s_addr = addr.s_addr | ~mask.s_addr}; if (debug & DEBUG_OVERLAYINTERFACES) { // note, inet_ntop doesn't seem to behave on android DEBUGF("%s address: %s", name, inet_ntoa(addr)); DEBUGF("%s broadcast address: %s", name, inet_ntoa(broadcast)); } /* See if the interface is listed in the filter */ me = NULL; for (r = interface_filter; r && !me; r = r->next) if (r->namespec[0] == '\0' || strcasecmp(name, r->namespec) == 0) me = r; if (me == NULL || me->excludeP) { if (debug & DEBUG_OVERLAYINTERFACES) DEBUGF("Interface %s is not interesting.",name); return 0; } int found_interface= -1; /* Search in the exist list of interfaces */ for(i = 0; i < overlay_interface_count; i++){ int broadcast_match = 0; int name_match =0; if (overlay_interfaces[i].broadcast_address.sin_addr.s_addr == broadcast.s_addr) broadcast_match = 1; name_match = !strcasecmp(overlay_interfaces[i].name, name); // if we find an exact match we can stop searching if (name_match && broadcast_match){ // mark this interface as still alive if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interfaces[i].state=INTERFACE_STATE_UP; // try to bring the interface back up again even if the address has changed if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){ overlay_interfaces[i].address.sin_addr = addr; overlay_interface_init_socket(i); } // we already know about this interface, and it's up so stop looking immediately return 0; } // remember this slot to bring the interface back up again, even if the address has changed if (name_match && overlay_interfaces[i].state==INTERFACE_STATE_DOWN) found_interface=i; } if (found_interface>=0){ // try to reactivate the existing interface overlay_interfaces[found_interface].address.sin_addr = addr; overlay_interfaces[found_interface].broadcast_address.sin_addr = broadcast; overlay_interfaces[found_interface].netmask = mask; return overlay_interface_init_socket(found_interface); } /* New interface, so register it */ if (overlay_interface_init(name, addr, mask, broadcast, me->speed_in_bits, me->port, me->type)) return WHYF("Could not initialise newly seen interface %s", name); else if (debug & DEBUG_OVERLAYINTERFACES) DEBUGF("Registered interface %s", name); return 0; } void overlay_interface_discover(struct sched_ent *alarm){ int i; struct interface_rules *r; struct in_addr dummyaddr; int detect_real_interfaces = 0; /* Mark all UP interfaces as DETECTING, so we can tell which interfaces are new, and which are dead */ for (i = 0; i < overlay_interface_count; i++) if (overlay_interfaces[i].state==INTERFACE_STATE_UP) overlay_interfaces[i].state=INTERFACE_STATE_DETECTING; /* Check through for any virtual dummy interfaces */ for (r = interface_filter; r != NULL; r = r->next) { if (r->namespec[0] != '>'){ detect_real_interfaces = 1; continue; } for (i = 0; i < overlay_interface_count; i++) if (!strcasecmp(overlay_interfaces[i].name,r->namespec)){ if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interfaces[i].state=INTERFACE_STATE_UP; break; } if (i >= overlay_interface_count){ /* New interface, so register it */ overlay_interface_init(r->namespec,dummyaddr,dummyaddr,dummyaddr,1000000,PORT_DNA,OVERLAY_INTERFACE_WIFI); } } /* Look for real interfaces */ if (detect_real_interfaces){ int no_route = 1; #ifdef HAVE_IFADDRS_H if (no_route != 0) no_route = doifaddrs(); #endif #ifdef SIOCGIFCONF if (no_route != 0) no_route = lsif(); #endif #ifdef linux if (no_route != 0) no_route = scrapeProcNetRoute(); #endif if (no_route != 0) { FATAL("Unable to get any interface information"); } } // detect if any interfaces have gone away and need to be closed for(i = 0; i < overlay_interface_count; i++) if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interface_close(&overlay_interfaces[i]); alarm->alarm = gettime_ms()+5000; alarm->deadline = alarm->alarm + 10000; schedule(alarm); return; } static void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len) { struct mallocbuf mb = STRUCT_MALLOCBUF_NULL; if (serval_packetvisualise(XPRINTF_MALLOCBUF(&mb), message, packet, len) == -1) WHY("serval_packetvisualise() failed"); else if (mb.buffer == NULL) WHYF("serval_packetvisualise() output buffer missing, message=%s packet=%p len=%lu", alloca_toprint(-1, message, strlen(message)), packet, len); else logString(level, __whence, mb.buffer); if (mb.buffer) free(mb.buffer); }