]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 11 Dec 2009 21:31:27 +0000 (22:31 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 11 Dec 2009 21:31:27 +0000 (22:31 +0100)
Conflicts:
src/subnet.c

1  2 
src/graph.c
src/route.c
src/subnet.c
src/subnet.h

diff --combined src/graph.c
index 06bf36d793cc43e6d76bba2fee33df75b5f26c33,f5aff5bfd7a2511e71042162408e390a332d19ea..d54e5cd6a99de011bb64030ed648b9190deeb8b1
@@@ -44,7 -44,7 +44,7 @@@
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "config.h"
  #include "connection.h"
  #include "device.h"
  #include "utils.h"
  #include "xalloc.h"
  
 -static bool graph_changed = true;
 -
  /* Implementation of Kruskal's algorithm.
 -   Running time: O(EN)
 +   Running time: O(E)
     Please note that sorting on weight is already done by add_edge().
  */
  
  void mst_kruskal(void) {
 -      avl_node_t *node, *next;
 +      splay_node_t *node, *next;
        edge_t *e;
        node_t *n;
        connection_t *c;
 -      int nodes = 0;
 -      int safe_edges = 0;
 -      bool skipped;
  
        /* Clear MST status on connections */
  
                c->status.mst = false;
        }
  
 -      /* Do we have something to do at all? */
 -
 -      if(!edge_weight_tree->head)
 -              return;
 -
        ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
  
        /* Clear visited status on nodes */
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
                n->status.visited = false;
 -              nodes++;
 -      }
 -
 -      /* Starting point */
 -
 -      for(node = edge_weight_tree->head; node; node = node->next) {
 -              e = node->data;
 -              if(e->from->status.reachable) {
 -                      e->from->status.visited = true;
 -                      break;
 -              }
        }
  
        /* Add safe edges */
  
 -      for(skipped = false, node = edge_weight_tree->head; node; node = next) {
 +      for(node = edge_weight_tree->head; node; node = next) {
                next = node->next;
                e = node->data;
  
 -              if(!e->reverse || e->from->status.visited == e->to->status.visited) {
 -                      skipped = true;
 +              if(!e->reverse || (e->from->status.visited && e->to->status.visited))
                        continue;
 -              }
  
                e->from->status.visited = true;
                e->to->status.visited = true;
                if(e->reverse->connection)
                        e->reverse->connection->status.mst = true;
  
 -              safe_edges++;
 -
                ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
                                   e->to->name, e->weight);
 +      }
 +}
  
 -              if(skipped) {
 -                      skipped = false;
 -                      next = edge_weight_tree->head;
 -                      continue;
 +/* Implementation of Dijkstra's algorithm.
 +   Running time: O(N^2)
 +*/
 +
 +void sssp_dijkstra(void) {
 +      splay_node_t *node, *to;
 +      edge_t *e;
 +      node_t *n, *m;
 +      list_t *todo_list;
 +      list_node_t *lnode, *nnode;
 +      bool indirect;
 +
 +      todo_list = list_alloc(NULL);
 +
 +      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:");
 +
 +      /* Clear visited status on nodes */
 +
 +      for(node = node_tree->head; node; node = node->next) {
 +              n = node->data;
 +              n->status.visited = false;
 +              n->status.indirect = true;
 +              n->distance = -1;
 +      }
 +
 +      /* Begin with myself */
 +
 +      myself->status.indirect = false;
 +      myself->nexthop = myself;
 +      myself->via = myself;
 +      myself->distance = 0;
 +      list_insert_head(todo_list, myself);
 +
 +      /* Loop while todo_list is filled */
 +
 +      while(todo_list->head) {
 +              n = NULL;
 +              nnode = NULL;
 +
 +              /* Select node from todo_list with smallest distance */
 +
 +              for(lnode = todo_list->head; lnode; lnode = lnode->next) {
 +                      m = lnode->data;
 +                      if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) {
 +                              n = m;
 +                              nnode = lnode;
 +                      }
 +              }
 +
 +              /* Mark this node as visited and remove it from the todo_list */
 +
 +              n->status.visited = true;
 +              list_unlink_node(todo_list, nnode);
 +
 +              /* Update distance of neighbours and add them to the todo_list */
 +
 +              for(to = n->edge_tree->head; to; to = to->next) {       /* "to" is the edge connected to "from" */
 +                      e = to->data;
 +
 +                      if(e->to->status.visited || !e->reverse)
 +                              continue;
 +
 +                      /* Situation:
 +
 +                                 /
 +                                /
 +                         ----->(n)---e-->(e->to)
 +                                \
 +                                 \
 +
 +                         Where e is an edge, (n) and (e->to) are nodes.
 +                         n->address is set to the e->address of the edge left of n to n.
 +                         We are currently examining the edge e right of n from n:
 +
 +                         - If e->reverse->address != n->address, then e->to is probably
 +                           not reachable for the nodes left of n. We do as if the indirectdata
 +                           flag is set on edge e.
 +                         - If edge e provides for better reachability of e->to, update e->to.
 +                       */
 +
 +                      if(e->to->distance < 0)
 +                              list_insert_tail(todo_list, e->to);
 +
 +                      indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address));
 +
 +                      if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight)
 +                              continue;
 +
 +                      e->to->distance = n->distance + e->weight;
 +                      e->to->status.indirect = indirect;
 +                      e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
 +                      e->to->via = indirect ? n->via : e->to;
 +                      e->to->options = e->options;
 +
 +                      if(sockaddrcmp(&e->to->address, &e->address)) {
 +                              node = splay_unlink(node_udp_tree, e->to);
 +                              sockaddrfree(&e->to->address);
 +                              sockaddrcpy(&e->to->address, &e->address);
 +
 +                              if(e->to->hostname)
 +                                      free(e->to->hostname);
 +
 +                              e->to->hostname = sockaddr2hostname(&e->to->address);
 +
 +                              if(node)
 +                                      splay_insert_node(node_udp_tree, node);
 +
 +                              if(e->to->options & OPTION_PMTU_DISCOVERY) {
 +                                      e->to->mtuprobes = 0;
 +                                      e->to->minmtu = 0;
 +                                      e->to->maxmtu = MTU;
 +                                      if(e->to->status.validkey)
 +                                              send_mtu_probe(e->to);
 +                              }
 +                      }
 +
 +                      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name,
 +                                         e->to->name, e->weight, e->to->distance);
                }
        }
  
 -      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
 -                         safe_edges);
 +      list_free(todo_list);
  }
  
  /* Implementation of a simple breadth-first search algorithm.
  */
  
  void sssp_bfs(void) {
 -      avl_node_t *node, *next, *to;
 +      splay_node_t *node, *to;
        edge_t *e;
        node_t *n;
        list_t *todo_list;
        list_node_t *from, *todonext;
        bool indirect;
 -      char *name;
 -      char *address, *port;
 -      char *envp[7];
 -      int i;
  
        todo_list = list_alloc(NULL);
  
        }
  
        list_free(todo_list);
 +}
 +
 +void check_reachability() {
 +      splay_node_t *node, *next;
 +      node_t *n;
 +      char *name;
 +      char *address, *port;
 +      char *envp[7];
 +      int i;
  
        /* Check reachability status. */
  
                        n->minmtu = 0;
                        n->mtuprobes = 0;
  
 -                      if(n->mtuevent) {
 -                              event_del(n->mtuevent);
 -                              n->mtuevent = NULL;
 -                      }
 +                      event_del(&n->mtuevent);
  
                        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
                        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
                                free(envp[i]);
  
                        subnet_update(n, NULL, n->status.reachable);
+                       if(!n->status.reachable)
+                               update_node_udp(n, NULL);
                }
        }
  }
  
  void graph(void) {
        subnet_cache_flush();
 -      sssp_bfs();
 +      sssp_dijkstra();
 +      check_reachability();
        mst_kruskal();
 -      graph_changed = true;
 -}
 -
 -
 -
 -/* Dump nodes and edges to a graphviz file.
 -         
 -   The file can be converted to an image with
 -   dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
 -*/
 -
 -void dump_graph(void) {
 -      avl_node_t *node;
 -      node_t *n;
 -      edge_t *e;
 -      char *filename = NULL, *tmpname = NULL;
 -      FILE *file;
 -      
 -      if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename))
 -              return;
 -
 -      graph_changed = false;
 -
 -      ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
 -      
 -      if(filename[0] == '|') {
 -              file = popen(filename + 1, "w");
 -      } else {
 -              xasprintf(&tmpname, "%s.new", filename);
 -              file = fopen(tmpname, "w");
 -      }
 -
 -      if(!file) {
 -              logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
 -              free(tmpname);
 -              return;
 -      }
 -
 -      fprintf(file, "digraph {\n");
 -      
 -      /* dump all nodes first */
 -      for(node = node_tree->head; node; node = node->next) {
 -              n = node->data;
 -              fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name);
 -      }
 -
 -      /* now dump all edges */
 -      for(node = edge_weight_tree->head; node; node = node->next) {
 -              e = node->data;
 -              fprintf(file, " %s -> %s;\n", e->from->name, e->to->name);
 -      }
 -
 -      fprintf(file, "}\n");   
 -      
 -      if(filename[0] == '|') {
 -              pclose(file);
 -      } else {
 -              fclose(file);
 -#ifdef HAVE_MINGW
 -              unlink(filename);
 -#endif
 -              rename(tmpname, filename);
 -              free(tmpname);
 -      }
  }
diff --combined src/route.c
index 758801be80bbd38582b08d5a39724b453652a6db,16423892fa58c479c987d520a26fa6dae1d7afd3..3c0cf5b5b3a0d7aedc02807da006d46f26dbcc1a
@@@ -20,7 -20,7 +20,7 @@@
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "connection.h"
  #include "ethernet.h"
  #include "ipv4.h"
@@@ -49,8 -49,6 +49,8 @@@ static const size_t icmp6_size = sizeof
  static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
  static const size_t opt_size = sizeof(struct nd_opt_hdr);
  
 +static struct event age_subnets_event;
 +
  /* RFC 1071 */
  
  static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
@@@ -74,7 -72,6 +74,7 @@@
  static bool ratelimit(int frequency) {
        static time_t lasttime = 0;
        static int count = 0;
 +      time_t now = time(NULL);
        
        if(lasttime == now) {
                if(++count > frequency)
@@@ -102,46 -99,12 +102,46 @@@ static void swap_mac_addresses(vpn_pack
        memcpy(&packet->data[6], &tmp, sizeof tmp);
  }
        
 +static void age_subnets(int fd, short events, void *data) {
 +      subnet_t *s;
 +      connection_t *c;
 +      splay_node_t *node, *next, *node2;
 +      bool left = false;
 +      time_t now = time(NULL);
 +
 +      for(node = myself->subnet_tree->head; node; node = next) {
 +              next = node->next;
 +              s = node->data;
 +              if(s->expires && s->expires < now) {
 +                      ifdebug(TRAFFIC) {
 +                              char netstr[MAXNETSTR];
 +                              if(net2str(netstr, sizeof netstr, s))
 +                                      logger(LOG_INFO, "Subnet %s expired", netstr);
 +                      }
 +
 +                      for(node2 = connection_tree->head; node2; node2 = node2->next) {
 +                              c = node2->data;
 +                              if(c->status.active)
 +                                      send_del_subnet(c, s);
 +                      }
 +
 +                      subnet_del(myself, s);
 +              } else {
 +                      if(s->expires)
 +                              left = true;
 +              }
 +      }
 +
 +      if(left)
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +}
 +
  static void learn_mac(mac_t *address) {
        subnet_t *subnet;
 -      avl_node_t *node;
 +      splay_node_t *node;
        connection_t *c;
  
-       subnet = lookup_subnet_mac(address);
+       subnet = lookup_subnet_mac(myself, address);
  
        /* If we don't know this MAC address yet, store it */
  
  
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
 -              subnet->expires = now + macexpire;
 +              subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
                subnet->weight = 10;
                subnet_add(myself, subnet);
                        if(c->status.active)
                                send_add_subnet(c, subnet);
                }
 -      }
 -
 -      if(subnet->expires)
 -              subnet->expires = now + macexpire;
 -}
 -
 -void age_subnets(void) {
 -      subnet_t *s;
 -      connection_t *c;
 -      avl_node_t *node, *next, *node2;
 -
 -      for(node = myself->subnet_tree->head; node; node = next) {
 -              next = node->next;
 -              s = node->data;
 -              if(s->expires && s->expires < now) {
 -                      ifdebug(TRAFFIC) {
 -                              char netstr[MAXNETSTR];
 -                              if(net2str(netstr, sizeof netstr, s))
 -                                      logger(LOG_INFO, "Subnet %s expired", netstr);
 -                      }
  
 -                      for(node2 = connection_tree->head; node2; node2 = node2->next) {
 -                              c = node2->data;
 -                              if(c->status.active)
 -                                      send_del_subnet(c, s);
 -                      }
 -
 -                      subnet_del(myself, s);
 -              }
 +              if(!timeout_initialized(&age_subnets_event))
 +                      timeout_set(&age_subnets_event, age_subnets, NULL);
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +      } else {
 +              if(subnet->expires)
 +                      subnet->expires = time(NULL) + macexpire;
        }
  }
  
@@@ -423,7 -408,7 +423,7 @@@ static void route_ipv6_unreachable(node
  
        /* Generate checksum */
        
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&icmp6, icmp6_size, checksum);
        checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
  
@@@ -542,7 -527,7 +542,7 @@@ static void route_neighborsol(node_t *s
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
@@@ -666,7 -651,7 +666,7 @@@ static void route_arp(node_t *source, v
        /* Check if this is a valid ARP request */
  
        if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
 -         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
 +         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) {
                ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request");
                return;
        }
        memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN);        /* copy destination address */
        packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
  
 -      memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
 -      memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
 -      memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
 +      memcpy(&addr, arp.arp_tpa, sizeof addr);        /* save protocol addr */
 +      memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr);  /* swap destination and source protocol address */
 +      memcpy(arp.arp_spa, &addr, sizeof addr);        /* ... */
  
        memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
        memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
@@@ -720,7 -705,7 +720,7 @@@ static void route_mac(node_t *source, v
        /* Lookup destination address */
  
        memcpy(&dest, &packet->data[0], sizeof dest);
-       subnet = lookup_subnet_mac(&dest);
+       subnet = lookup_subnet_mac(NULL, &dest);
  
        if(!subnet) {
                broadcast_packet(source, packet);
diff --combined src/subnet.c
index 0669b8a0bceaf649ce39a7ae8c5338962f7c2e41,bc66fecccdf69ab2d1dfaa5151f1484254adab96..8bc8fce89efdc5040f6ba1c04c27b6d157d7c917
@@@ -20,8 -20,7 +20,8 @@@
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "control_common.h"
  #include "device.h"
  #include "logger.h"
  #include "net.h"
@@@ -34,7 -33,7 +34,7 @@@
  
  /* lists type of subnet */
  
 -avl_tree_t *subnet_tree;
 +splay_tree_t *subnet_tree;
  
  /* Subnet lookup cache */
  
@@@ -64,7 -63,7 +64,7 @@@ void subnet_cache_flush() 
  static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
        int result;
  
 -      result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
 +      result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address);
  
        if(result)
                return result;
@@@ -146,21 -145,21 +146,21 @@@ int subnet_compare(const subnet_t *a, c
  /* Initialising trees */
  
  void init_subnets(void) {
 -      subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
 +      subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet);
  
        subnet_cache_flush();
  }
  
  void exit_subnets(void) {
 -      avl_delete_tree(subnet_tree);
 +      splay_delete_tree(subnet_tree);
  }
  
 -avl_tree_t *new_subnet_tree(void) {
 -      return avl_alloc_tree((avl_compare_t) subnet_compare, NULL);
 +splay_tree_t *new_subnet_tree(void) {
 +      return splay_alloc_tree((splay_compare_t) subnet_compare, NULL);
  }
  
 -void free_subnet_tree(avl_tree_t *subnet_tree) {
 -      avl_delete_tree(subnet_tree);
 +void free_subnet_tree(splay_tree_t *subnet_tree) {
 +      splay_delete_tree(subnet_tree);
  }
  
  /* Allocating and freeing space for subnets */
@@@ -178,15 -177,15 +178,15 @@@ void free_subnet(subnet_t *subnet) 
  void subnet_add(node_t *n, subnet_t *subnet) {
        subnet->owner = n;
  
 -      avl_insert(subnet_tree, subnet);
 -      avl_insert(n->subnet_tree, subnet);
 +      splay_insert(subnet_tree, subnet);
 +      splay_insert(n->subnet_tree, subnet);
  
        subnet_cache_flush();
  }
  
  void subnet_del(node_t *n, subnet_t *subnet) {
 -      avl_delete(n->subnet_tree, subnet);
 -      avl_delete(subnet_tree, subnet);
 +      splay_delete(n->subnet_tree, subnet);
 +      splay_delete(subnet_tree, subnet);
  
        subnet_cache_flush();
  }
@@@ -274,7 -273,7 +274,7 @@@ bool str2net(subnet_t *subnet, const ch
  
  bool net2str(char *netstr, int len, const subnet_t *subnet) {
        if(!netstr || !subnet) {
 -              logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!\n", netstr, subnet);
 +              logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", netstr, subnet);
                return false;
        }
  
  /* Subnet lookup routines */
  
  subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
 -      return avl_search(owner->subnet_tree, subnet);
 +      return splay_search(owner->subnet_tree, subnet);
  }
  
- subnet_t *lookup_subnet_mac(const mac_t *address) {
-       subnet_t *p, *r = NULL, subnet = {0};
+ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
+       subnet_t *p, *r = NULL;
 -      avl_node_t *n;
 +      splay_node_t *n;
        int i;
  
        // Check if this address is cached
        for(i = 0; i < 2; i++) {
                if(!cache_mac_valid[i])
                        continue;
+               if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner)
+                       continue;
                if(!memcmp(address, &cache_mac_address[i], sizeof *address))
                        return cache_mac_subnet[i];
        }
  
        // Search all subnets for a matching one
  
-       subnet.type = SUBNET_MAC;
-       subnet.net.mac.address = *address;
-       subnet.owner = NULL;
-       for(n = subnet_tree->head; n; n = n->next) {
+       for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) {
                p = n->data;
                
-               if(!p || p->type != subnet.type)
+               if(!p || p->type != SUBNET_MAC)
                        continue;
  
                if(!memcmp(address, &p->net.mac.address, sizeof *address)) {
  }
  
  subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
-       subnet_t *p, *r = NULL, subnet = {0};
+       subnet_t *p, *r = NULL;
 -      avl_node_t *n;
 +      splay_node_t *n;
        int i;
  
        // Check if this address is cached
  
        // Search all subnets for a matching one
  
-       subnet.type = SUBNET_IPV4;
-       subnet.net.ipv4.address = *address;
-       subnet.net.ipv4.prefixlength = 32;
-       subnet.owner = NULL;
        for(n = subnet_tree->head; n; n = n->next) {
                p = n->data;
                
-               if(!p || p->type != subnet.type)
+               if(!p || p->type != SUBNET_IPV4)
                        continue;
  
                if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
  }
  
  subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
-       subnet_t *p, *r = NULL, subnet = {0};
+       subnet_t *p, *r = NULL;
 -      avl_node_t *n;
 +      splay_node_t *n;
        int i;
  
        // Check if this address is cached
  
        // Search all subnets for a matching one
  
-       subnet.type = SUBNET_IPV6;
-       subnet.net.ipv6.address = *address;
-       subnet.net.ipv6.prefixlength = 128;
-       subnet.owner = NULL;
        for(n = subnet_tree->head; n; n = n->next) {
                p = n->data;
                
-               if(!p || p->type != subnet.type)
+               if(!p || p->type != SUBNET_IPV6)
                        continue;
  
                if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
  }
  
  void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        int i;
        char *envp[9] = {0};
        char netstr[MAXNETSTR];
                free(envp[i]);
  }
  
 -void dump_subnets(void) {
 +bool dump_subnets(connection_t *c) {
        char netstr[MAXNETSTR];
        subnet_t *subnet;
 -      avl_node_t *node;
 -
 -      logger(LOG_DEBUG, "Subnet list:");
 +      splay_node_t *node;
  
        for(node = subnet_tree->head; node; node = node->next) {
                subnet = node->data;
                if(!net2str(netstr, sizeof netstr, subnet))
                        continue;
 -              logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
 +              send_request(c, "%d %d %s owner %s",
 +                              CONTROL, REQ_DUMP_SUBNETS,
 +                              netstr, subnet->owner->name);
        }
  
 -      logger(LOG_DEBUG, "End of subnet list.");
 +      return send_request(c, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
  }
diff --combined src/subnet.h
index 466eb20c1806f11fc9cfbea3bdbec0eedb346e09,b2124a0ef87037a00d00b9daed4cbf411c3b1270..df48f60eda8268cc989cb9591bf47b4c72076c8f
@@@ -69,18 -69,18 +69,18 @@@ extern subnet_t *new_subnet(void) __att
  extern void free_subnet(subnet_t *);
  extern void init_subnets(void);
  extern void exit_subnets(void);
 -extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
 -extern void free_subnet_tree(avl_tree_t *);
 +extern splay_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
 +extern void free_subnet_tree(splay_tree_t *);
  extern void subnet_add(struct node_t *, subnet_t *);
  extern void subnet_del(struct node_t *, subnet_t *);
  extern void subnet_update(struct node_t *, subnet_t *, bool);
  extern bool net2str(char *, int, const subnet_t *);
  extern bool str2net(subnet_t *, const char *);
  extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *);
- extern subnet_t *lookup_subnet_mac(const mac_t *);
+ extern subnet_t *lookup_subnet_mac(const struct node_t *, const mac_t *);
  extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
  extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
 -extern void dump_subnets(void);
 +extern bool dump_subnets(struct connection_t *);
  extern void subnet_cache_flush(void);
  
  #endif                                                        /* __TINC_SUBNET_H__ */