]> git.meshlink.io Git - meshlink/blobdiff - src/meshlink.c
Allow Catta to be disabled.
[meshlink] / src / meshlink.c
index 446e8d24a65961777211c5906c4d1f5dc7aa14b3..6a2c99da68d8c416f79704a3dd8b615ba8906921 100644 (file)
@@ -165,9 +165,9 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port
                p += strspn(p, "\t ");
                p[strcspn(p, "\t ")] = 0;
 
-               if(!*port && !strcasecmp(line, "Port")) {
+               if(!*port && !strcasecmp(line, "Port"))
                        *port = xstrdup(q);
-               else if(!*hostname && !strcasecmp(line, "Address")) {
+               else if(!*hostname && !strcasecmp(line, "Address")) {
                        *hostname = xstrdup(q);
                        if(*p) {
                                free(*port);
@@ -191,6 +191,18 @@ static bool is_valid_hostname(const char *hostname) {
        return true;
 }
 
+static void set_timeout(int sock, int timeout) {
+#ifdef _WIN32
+       DWORD tv = timeout;
+#else
+       struct timeval tv;
+       tv.tv_sec = timeout / 1000;
+       tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
+#endif
+       setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
+       setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
+}
+
 char *meshlink_get_external_address(meshlink_handle_t *mesh) {
        char *hostname = NULL;
 
@@ -203,6 +215,7 @@ char *meshlink_get_external_address(meshlink_handle_t *mesh) {
        while(aip) {
                int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
                if(s >= 0) {
+                       set_timeout(s, 5000);
                        if(connect(s, aip->ai_addr, aip->ai_addrlen)) {
                                closesocket(s);
                                s = -1;
@@ -265,9 +278,8 @@ static char *get_my_hostname(meshlink_handle_t* mesh) {
        if(f) {
                fprintf(f, "\nAddress = %s\n", hostname);
                fclose(f);
-       } else {
+       } else
                logger(mesh, MESHLINK_DEBUG, "Could not append Address to %s: %s\n", filename, strerror(errno));
-       }
 
 done:
        if(port) {
@@ -518,7 +530,7 @@ static bool finalize_join(meshlink_handle_t *mesh) {
        if(!b64key) {
                fclose(fh);
                return false;
-               }
+       }
 
        fprintf(fh, "ECDSAPublicKey = %s\n", b64key);
        fprintf(fh, "Port = %s\n", mesh->myport);
@@ -557,28 +569,28 @@ static bool invitation_send(void *handle, uint8_t type, const void *data, size_t
 static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint16_t len) {
        meshlink_handle_t* mesh = handle;
        switch(type) {
-               case SPTPS_HANDSHAKE:
-                       return sptps_send_record(&(mesh->sptps), 0, mesh->cookie, sizeof mesh->cookie);
-
-               case 0:
-                       mesh->data = xrealloc(mesh->data, mesh->thedatalen + len + 1);
-                       memcpy(mesh->data + mesh->thedatalen, msg, len);
-                       mesh->thedatalen += len;
-                       mesh->data[mesh->thedatalen] = 0;
-                       break;
+       case SPTPS_HANDSHAKE:
+               return sptps_send_record(&(mesh->sptps), 0, mesh->cookie, sizeof mesh->cookie);
 
-               case 1:
-                       mesh->thedatalen = 0;
-                       return finalize_join(mesh);
+       case 0:
+               mesh->data = xrealloc(mesh->data, mesh->thedatalen + len + 1);
+               memcpy(mesh->data + mesh->thedatalen, msg, len);
+               mesh->thedatalen += len;
+               mesh->data[mesh->thedatalen] = 0;
+               break;
 
-               case 2:
-                       logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n");
-                       shutdown(mesh->sock, SHUT_RDWR);
-                       mesh->success = true;
-                       break;
+       case 1:
+               mesh->thedatalen = 0;
+               return finalize_join(mesh);
 
-               default:
-                       return false;
+       case 2:
+               logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n");
+               shutdown(mesh->sock, SHUT_RDWR);
+               mesh->success = true;
+               break;
+
+       default:
+               return false;
        }
 
        return true;
@@ -832,7 +844,7 @@ static bool meshlink_setup(meshlink_handle_t *mesh) {
 meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) {
        // Validate arguments provided by the application
        bool usingname = false;
-       
+
        logger(NULL, MESHLINK_DEBUG, "meshlink_open called\n");
 
        if(!confbase || !*confbase) {
@@ -850,14 +862,14 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c
        if(!name || !*name) {
                logger(NULL, MESHLINK_ERROR, "No name given!\n");
                //return NULL;
-       }
-       else { //check name only if there is a name != NULL
+       } else { //check name only if there is a name != NULL
 
                if(!check_id(name)) {
                        logger(NULL, MESHLINK_ERROR, "Invalid name given!\n");
                        meshlink_errno = MESHLINK_EINVAL;
                        return NULL;
-               } else { usingname = true;}
+               } else
+                       usingname = true;
        }
 
        if(devclass < 0 || devclass > _DEV_CLASS_MAX) {
@@ -870,14 +882,14 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c
        mesh->confbase = xstrdup(confbase);
        mesh->appname = xstrdup(appname);
        mesh->devclass = devclass;
-       if (usingname) mesh->name = xstrdup(name);
+       if(usingname) mesh->name = xstrdup(name);
 
        // initialize mutex
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        pthread_mutex_init(&(mesh->mesh_mutex), &attr);
-       
+
        mesh->threadstarted = false;
        event_loop_init(&mesh->loop);
        mesh->loop.data = mesh;
@@ -954,7 +966,7 @@ bool meshlink_start(meshlink_handle_t *mesh) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
-       
+
        logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n");
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
@@ -976,7 +988,7 @@ bool meshlink_start(meshlink_handle_t *mesh) {
        // TODO: open listening sockets first
 
        //Check that a valid name is set
-       if(!mesh->name ) {
+       if(!mesh->name) {
                logger(mesh, MESHLINK_DEBUG, "No name given!\n");
                meshlink_errno = MESHLINK_EINVAL;
                pthread_mutex_unlock(&(mesh->mesh_mutex));
@@ -997,7 +1009,8 @@ bool meshlink_start(meshlink_handle_t *mesh) {
 
        mesh->threadstarted=true;
 
-       discovery_start(mesh);
+       if(mesh->discovery)
+               discovery_start(mesh);
 
        pthread_mutex_unlock(&(mesh->mesh_mutex));
        return true;
@@ -1013,10 +1026,8 @@ void meshlink_stop(meshlink_handle_t *mesh) {
        logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
 
        // Stop discovery
-       discovery_stop(mesh);
-
-       pthread_mutex_lock(&(mesh->mesh_mutex));
-       logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n");
+       if(mesh->discovery)
+               discovery_stop(mesh);
 
        // Shut down the main thread
        event_loop_stop(&mesh->loop);
@@ -1184,7 +1195,7 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const
        // leave the last byte as 0 to make sure strings are always
        // null-terminated if they are longer than the buffer
        strncpy(hdr->destination, destination->name, (sizeof hdr->destination) - 1);
-       strncpy(hdr->source, mesh->self->name, (sizeof hdr->source) -1 );
+       strncpy(hdr->source, mesh->self->name, (sizeof hdr->source) -1);
 
        memcpy(packet->data + sizeof *hdr, data, len);
 
@@ -1197,7 +1208,7 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const
 
        // Notify event loop
        signal_trigger(&(mesh->loop),&(mesh->datafromapp));
-       
+
        return true;
 }
 
@@ -1222,13 +1233,11 @@ ssize_t meshlink_get_pmtu(meshlink_handle_t *mesh, meshlink_node_t *destination)
        if(!n->status.reachable) {
                pthread_mutex_unlock(&(mesh->mesh_mutex));
                return 0;
-       
-       }
-       else if(n->mtuprobes > 30 && n->minmtu) {
+
+       } else if(n->mtuprobes > 30 && n->minmtu) {
                pthread_mutex_unlock(&(mesh->mesh_mutex));
                return n->minmtu;
-       }
-       else {
+       } else {
                pthread_mutex_unlock(&(mesh->mesh_mutex));
                return MTU;
        }
@@ -1354,16 +1363,15 @@ bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const voi
        if(!n->ecdsa) {
                meshlink_errno = MESHLINK_EINTERNAL;
                rval = false;
-       } else {
+       } else
                rval = ecdsa_verify(((struct node_t *)source)->ecdsa, data, len, signature);
-       }
        pthread_mutex_unlock(&(mesh->mesh_mutex));
        return rval;
 }
 
 static bool refresh_invitation_key(meshlink_handle_t *mesh) {
        char filename[PATH_MAX];
-       
+
        pthread_mutex_lock(&(mesh->mesh_mutex));
 
        snprintf(filename, sizeof filename, "%s" SLASH "invitations", mesh->confbase);
@@ -1577,7 +1585,7 @@ char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
                meshlink_errno = MESHLINK_EINVAL;
                return NULL;
        }
-       
+
        pthread_mutex_lock(&(mesh->mesh_mutex));
 
        // Check validity of the new node's name
@@ -1660,7 +1668,7 @@ char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
        // Fill in the details.
        fprintf(f, "Name = %s\n", name);
        //if(netname)
-       //      fprintf(f, "NetName = %s\n", netname);
+       //      fprintf(f, "NetName = %s\n", netname);
        fprintf(f, "ConnectTo = %s\n", mesh->self->name);
 
        // Copy Broadcast and Mode
@@ -1670,7 +1678,7 @@ char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
                char buf[1024];
                while(fgets(buf, sizeof buf, tc)) {
                        if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4]))
-                                       || (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
+                                       || (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
                                fputs(buf, f);
                                // Make sure there is a newline character.
                                if(!strchr(buf, '\n'))
@@ -1706,7 +1714,7 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
-       
+
        pthread_mutex_lock(&(mesh->mesh_mutex));
 
        //TODO: think of a better name for this variable, or of a different way to tokenize the invitation URL.
@@ -1757,9 +1765,8 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
        char *b64key = ecdsa_get_base64_public_key(key);
 
        //Before doing meshlink_join make sure we are not connected to another mesh
-       if ( mesh->threadstarted ){
+       if(mesh->threadstarted)
                goto invalid;
-       }
 
        // Connect to the meshlink daemon mentioned in the URL.
        struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
@@ -1778,6 +1785,8 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
                return false;
        }
 
+       set_timeout(mesh->sock, 5000);
+
        if(connect(mesh->sock, ai->ai_addr, ai->ai_addrlen)) {
                logger(mesh, MESHLINK_DEBUG, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
                closesocket(mesh->sock);
@@ -1841,7 +1850,7 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
        }
 
        // Start an SPTPS session
-       if(!sptps_start(&mesh->sptps, mesh, true, false, key, hiskey, "meshlink invitation", 15, invitation_send, invitation_receive)) {
+       if(!sptps_start(&mesh->sptps, mesh, true, false, key, hiskey, meshlink_invitation_label, sizeof meshlink_invitation_label, invitation_send, invitation_receive)) {
                meshlink_errno = MESHLINK_EINTERNAL;
                pthread_mutex_unlock(&(mesh->mesh_mutex));
                return false;
@@ -1902,7 +1911,7 @@ char *meshlink_export(meshlink_handle_t *mesh) {
        }
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
-       
+
        char filename[PATH_MAX];
        snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->self->name);
        FILE *f = fopen(filename, "r");
@@ -1930,7 +1939,7 @@ char *meshlink_export(meshlink_handle_t *mesh) {
 
        fclose(f);
        buf[len - 1] = 0;
-       
+
        pthread_mutex_unlock(&(mesh->mesh_mutex));
        return buf;
 }
@@ -1940,7 +1949,7 @@ bool meshlink_import(meshlink_handle_t *mesh, const char *data) {
                meshlink_errno = MESHLINK_EINVAL;
                return false;
        }
-       
+
        pthread_mutex_lock(&(mesh->mesh_mutex));
 
        if(strncmp(data, "Name = ", 7)) {
@@ -2009,7 +2018,7 @@ void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) {
        }
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
-       
+
        node_t *n;
        n = (node_t*)node;
        n->status.blacklisted=true;
@@ -2029,7 +2038,7 @@ void meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) {
        }
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
-       
+
        node_t *n = (node_t *)node;
        n->status.blacklisted = false;
 
@@ -2053,15 +2062,15 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const
        // Ignore hints about ourself.
        if((node_t *)node == mesh->self)
                return;
-       
+
        pthread_mutex_lock(&(mesh->mesh_mutex));
-       
+
        char *host = NULL, *port = NULL, *str = NULL;
        sockaddr2str((const sockaddr_t *)addr, &host, &port);
 
        if(host && port) {
                xasprintf(&str, "%s %s", host, port);
-               if ( (strncmp ("fe80",host,4) != 0) && ( strncmp("127.",host,4) != 0 ) && ( strcmp("localhost",host) !=0 ) )
+               if((strncmp("fe80",host,4) != 0) && (strncmp("127.",host,4) != 0) && (strcmp("localhost",host) !=0))
                        append_config_file(mesh, node->name, "Address", str);
                else
                        logger(mesh, MESHLINK_DEBUG, "Not adding Link Local IPv6 Address to config\n");
@@ -2086,7 +2095,7 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink
        }
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
-       
+
        meshlink_edge_t **result = NULL;
        meshlink_edge_t *copy = NULL;
        int result_size = 0;
@@ -2094,11 +2103,10 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink
        result_size = mesh->edges->count;
 
        // if result is smaller than edges, we have to dealloc all the excess meshlink_edge_t
-       if(result_size > *nmemb) {
-               result = realloc(edges, result_size * sizeof (meshlink_edge_t*));
-       } else {
+       if(result_size > *nmemb)
+               result = realloc(edges, result_size * sizeof(meshlink_edge_t*));
+       else
                result = edges;
-       }
 
        if(result) {
                meshlink_edge_t **p = result;
@@ -2111,12 +2119,10 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink
                        }
                        n++;
                        // the first *nmemb members of result can be re-used
-                       if(n > *nmemb) {
+                       if(n > *nmemb)
                                copy = xzalloc(sizeof *copy);
-                       }
-                       else {
+                       else
                                copy = *p;
-                       }
                        copy->from = (meshlink_node_t*)e->from;
                        copy->to = (meshlink_node_t*)e->to;
                        copy->address = e->address.storage;
@@ -2125,10 +2131,9 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink
                        *p++ = copy;
                }
                // shrink result to the actual amount of memory used
-               for(int i = *nmemb; i > result_size; i--) {
+               for(int i = *nmemb; i > result_size; i--)
                        free(result[i - 1]);
-               }
-               result = realloc(result, result_size * sizeof (meshlink_edge_t*));
+               result = realloc(result, result_size * sizeof(meshlink_edge_t*));
                *nmemb = result_size;
        } else {
                *nmemb = 0;
@@ -2151,12 +2156,9 @@ static ssize_t channel_recv(struct utcp_connection *connection, const void *data
                abort();
        node_t *n = channel->node;
        meshlink_handle_t *mesh = n->mesh;
-       if(!channel->receive_cb)
-               return -1;
-       else {
+       if(channel->receive_cb)
                channel->receive_cb(mesh, channel, data, len);
-               return len;
-       }
+       return len;
 }
 
 static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) {
@@ -2178,9 +2180,6 @@ static void channel_accept(struct utcp_connection *utcp_connection, uint16_t por
 static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) {
        node_t *n = utcp->priv;
        meshlink_handle_t *mesh = n->mesh;
-       char hex[len * 2 + 1];
-       bin2hex(data, hex, len);
-       logger(mesh, MESHLINK_WARNING, "channel_send(%p, %p, %zu): %s\n", utcp, data, len, hex);
        return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? len : -1;
 }
 
@@ -2197,9 +2196,6 @@ static void channel_receive(meshlink_handle_t *mesh, meshlink_node_t *source, co
        node_t *n = (node_t *)source;
        if(!n->utcp)
                abort();
-       char hex[len * 2 + 1];
-       bin2hex(data, hex, len);
-       logger(mesh, MESHLINK_WARNING, "channel_receive(%p, %p, %zu): %s\n", n->utcp, data, len, hex);
        utcp_recv(n->utcp, data, len);
 }
 
@@ -2228,21 +2224,18 @@ void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_ac
        mesh->channel_accept_cb = cb;
        mesh->receive_cb = channel_receive;
        for splay_each(node_t, n, mesh->nodes) {
-               if(!n->utcp && n != mesh->self) {
-                       logger(mesh, MESHLINK_WARNING, "utcp_init on node %s", n->name);
+               if(!n->utcp && n != mesh->self)
                        n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
-               }
        }
        pthread_mutex_unlock(&mesh->mesh_mutex);
 }
 
-meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len) {
+meshlink_channel_t *meshlink_channel_open_ex(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len, uint32_t flags) {
        if(!mesh || !node) {
                meshlink_errno = MESHLINK_EINVAL;
                return NULL;
        }
 
-       logger(mesh, MESHLINK_WARNING, "meshlink_channel_open(%p, %s, %u, %p, %p, %zu)\n", mesh, node->name, port, cb, data, len);
        node_t *n = (node_t *)node;
        if(!n->utcp) {
                n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
@@ -2255,7 +2248,7 @@ meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node
        meshlink_channel_t *channel = xzalloc(sizeof *channel);
        channel->node = n;
        channel->receive_cb = cb;
-       channel->c = utcp_connect(n->utcp, port, channel_recv, channel);
+       channel->c = utcp_connect_ex(n->utcp, port, channel_recv, channel, flags);
        if(!channel->c) {
                meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL;
                free(channel);
@@ -2264,6 +2257,10 @@ meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node
        return channel;
 }
 
+meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len) {
+       return meshlink_channel_open_ex(mesh, node, port, cb, data, len, MESHLINK_CHANNEL_TCP);
+}
+
 void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction) {
        if(!mesh || !channel) {
                meshlink_errno = MESHLINK_EINVAL;
@@ -2311,6 +2308,15 @@ ssize_t meshlink_channel_send(meshlink_handle_t *mesh, meshlink_channel_t *chann
        return retval;
 }
 
+uint32_t meshlink_channel_get_flags(meshlink_handle_t *mesh, meshlink_channel_t *channel) {
+       if(!mesh || !channel) {
+               meshlink_errno = MESHLINK_EINVAL;
+               return -1;
+       }
+
+       return channel->c->flags;
+}
+
 void update_node_status(meshlink_handle_t *mesh, node_t *n) {
        if(n->status.reachable && mesh->channel_accept_cb && !n->utcp)
                n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n);
@@ -2318,8 +2324,35 @@ void update_node_status(meshlink_handle_t *mesh, node_t *n) {
                mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable);
 }
 
+void meshlink_enable_discovery(meshlink_handle_t *mesh, bool enable) {
+       if(!mesh) {
+               meshlink_errno = MESHLINK_EINVAL;
+               return;
+       }
+
+       pthread_mutex_lock(&mesh->mesh_mutex);
+
+       if(mesh->discovery == enable)
+               goto end;
+
+       if(mesh->threadstarted) {
+               if(enable)
+                       discovery_start(mesh);
+               else
+                       discovery_stop(mesh);
+       }
+
+       mesh->discovery = enable;
+
+end:
+       pthread_mutex_unlock(&mesh->mesh_mutex);
+}
+
 static void __attribute__((constructor)) meshlink_init(void) {
        crypto_init();
+       unsigned int seed;
+       randomize(&seed, sizeof seed);
+       srand(seed);
 }
 
 static void __attribute__((destructor)) meshlink_exit(void) {
@@ -2328,8 +2361,8 @@ static void __attribute__((destructor)) meshlink_exit(void) {
 
 /// Device class traits
 dev_class_traits_t dev_class_traits[_DEV_CLASS_MAX +1] = {
-       { .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE
-       { .min_connects = 3, .max_connects = 100, .edge_weight = 3 },   // DEV_CLASS_STATIONARY
-       { .min_connects = 3, .max_connects = 3, .edge_weight = 6 },             // DEV_CLASS_PORTABLE
-       { .min_connects = 1, .max_connects = 1, .edge_weight = 9 },             // DEV_CLASS_UNKNOWN
+       { .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE
+       { .min_connects = 3, .max_connects = 100, .edge_weight = 3 },   // DEV_CLASS_STATIONARY
+       { .min_connects = 3, .max_connects = 3, .edge_weight = 6 },             // DEV_CLASS_PORTABLE
+       { .min_connects = 1, .max_connects = 1, .edge_weight = 9 },             // DEV_CLASS_UNKNOWN
 };