-int ack_h(connection_t *c)
-{
- char myaddress[MAX_STRING_SIZE];
- char hisport[MAX_STRING_SIZE];
- char *hisaddress, *dummy;
- long int options;
- node_t *n;
- avl_node_t *node;
-cp
- if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" %lx", hisport, myaddress, &options) != 3)
- {
- syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname);
- return -1;
- }
-
- /* Check if we already have a node_t for him */
-
- n = lookup_node(c->name);
-
- if(!n)
- {
- n = new_node();
- n->name = xstrdup(c->name);
- node_add(n);
- }
- else
- {
- if(n->connection)
- {
- /* Oh dear, we already have a connection to this node. */
- if(debug_lvl >= DEBUG_CONNECTIONS)
- syslog(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->name, n->hostname);
- terminate_connection(n->connection, 0);
- }
- }
-
- c->node = n;
- c->options |= options;
- c->myaddress = str2sockaddr(myaddress, myport);
-
- n->connection = c;
- sockaddr2str(&c->address, &hisaddress, &dummy);
- node = avl_unlink(node_udp_tree, n);
- n->address = str2sockaddr(hisaddress, hisport);
- avl_insert_node(node_udp_tree, node);
- if(n->hostname)
- free(n->hostname);
- n->hostname = sockaddr2hostname(&n->address);
- n->options = c->options;
- n->distance = 1;
- n->via = n->nexthop = n;
- n->status.reachable = 1;
- n->status.validkey = 0;
- n->status.waitingforkey = 0;
-
- /* Activate this connection */
-
- c->allow_request = ALL;
- c->status.active = 1;
-
- if(debug_lvl >= DEBUG_CONNECTIONS)
- syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name, c->hostname);
-
-cp
- /* Send him everything we know and tell the others about him */
-
- send_everything(c);
-cp
- return 0;
+bool send_ack(connection_t *c) {
+ if(c->protocol_minor == 1)
+ return send_upgrade(c);
+
+ /* ACK message contains rest of the information the other end needs
+ to create node_t and edge_t structures. */
+
+ struct timeval now;
+ bool choice;
+
+ /* Estimate weight */
+
+ gettimeofday(&now, NULL);
+ c->estimated_weight = (now.tv_sec - c->start.tv_sec) * 1000 + (now.tv_usec - c->start.tv_usec) / 1000;
+
+ /* Check some options */
+
+ if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT)
+ c->options |= OPTION_INDIRECT;
+
+ if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY)
+ c->options |= OPTION_TCPONLY | OPTION_INDIRECT;
+
+ if(myself->options & OPTION_PMTU_DISCOVERY)
+ c->options |= OPTION_PMTU_DISCOVERY;
+
+ choice = myself->options & OPTION_CLAMP_MSS;
+ get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice);
+ if(choice)
+ c->options |= OPTION_CLAMP_MSS;
+
+ get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
+
+ return send_request(c, "%d %s %d %x", ACK, myport, c->estimated_weight, c->options);
+}
+
+static void send_everything(connection_t *c) {
+ splay_node_t *node, *node2;
+ node_t *n;
+ subnet_t *s;
+ edge_t *e;
+
+ /* Send all known subnets and edges */
+
+ if(tunnelserver) {
+ for(node = myself->subnet_tree->head; node; node = node->next) {
+ s = node->data;
+ send_add_subnet(c, s);
+ }
+
+ return;
+ }
+
+ for(node = node_tree->head; node; node = node->next) {
+ n = node->data;
+
+ for(node2 = n->subnet_tree->head; node2; node2 = node2->next) {
+ s = node2->data;
+ send_add_subnet(c, s);
+ }
+
+ for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
+ e = node2->data;
+ send_add_edge(c, e);
+ }
+ }
+}
+
+static bool upgrade_h(connection_t *c, char *request) {
+ char pubkey[MAX_STRING_SIZE];
+
+ if(sscanf(request, "%*d " MAX_STRING, pubkey) != 1) {
+ logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname);
+ return false;
+ }
+
+ if(ecdsa_active(&c->ecdsa) || read_ecdsa_public_key(c)) {
+ logger(LOG_INFO, "Already have ECDSA public key from %s (%s), not upgrading.", c->name, c->hostname);
+ return false;
+ }
+
+ logger(LOG_INFO, "Got ECDSA public key from %s (%s), upgrading!", c->name, c->hostname);
+ append_connection_config(c, "ECDSAPublicKey", pubkey);
+ c->allow_request = TERMREQ;
+ return send_termreq(c);
+}
+
+bool ack_h(connection_t *c, char *request) {
+ if(c->protocol_minor == 1)
+ return upgrade_h(c, request);
+
+ char hisport[MAX_STRING_SIZE];
+ char *hisaddress;
+ int weight, mtu;
+ uint32_t options;
+ node_t *n;
+ bool choice;
+
+ if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) {
+ logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
+ c->hostname);
+ return false;
+ }
+
+ /* Check if we already have a node_t for him */
+
+ n = lookup_node(c->name);
+
+ if(!n) {
+ n = new_node();
+ n->name = xstrdup(c->name);
+ node_add(n);
+ } else {
+ if(n->connection) {
+ /* Oh dear, we already have a connection to this node. */
+ ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", n->connection->name, n->connection->hostname);
+
+ if(n->connection->outgoing) {
+ if(c->outgoing)
+ logger(LOG_WARNING, "Two outgoing connections to the same node!");
+ else
+ c->outgoing = n->connection->outgoing;
+
+ n->connection->outgoing = NULL;
+ }
+
+ terminate_connection(n->connection, false);
+ /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
+ graph();
+ }
+ }
+
+ n->connection = c;
+ c->node = n;
+ if(!(c->options & options & OPTION_PMTU_DISCOVERY)) {
+ c->options &= ~OPTION_PMTU_DISCOVERY;
+ options &= ~OPTION_PMTU_DISCOVERY;
+ }
+ c->options |= options;
+
+ if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
+ n->mtu = mtu;
+
+ if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu)
+ n->mtu = mtu;
+
+ if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) {
+ if(choice)
+ c->options |= OPTION_CLAMP_MSS;
+ else
+ c->options &= ~OPTION_CLAMP_MSS;
+ }
+
+ if(c->protocol_minor > 0)
+ c->node->status.ecdh = true;
+
+ /* Activate this connection */
+
+ c->allow_request = ALL;
+ c->status.active = true;
+
+ ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name,
+ c->hostname);
+
+ /* Send him everything we know */
+
+ send_everything(c);
+
+ /* Create an edge_t for this connection */
+
+ c->edge = new_edge();
+ c->edge->from = myself;
+ c->edge->to = n;
+ sockaddr2str(&c->address, &hisaddress, NULL);
+ c->edge->address = str2sockaddr(hisaddress, hisport);
+ free(hisaddress);
+ c->edge->weight = (weight + c->estimated_weight) / 2;
+ c->edge->connection = c;
+ c->edge->options = c->options;
+
+ edge_add(c->edge);
+
+ /* Notify everyone of the new edge */
+
+ if(tunnelserver)
+ send_add_edge(c, c->edge);
+ else
+ send_add_edge(broadcast, c->edge);
+
+ /* Run MST and SSSP algorithms */
+
+ graph();
+
+ return true;