babel.c 21.9 KB
Newer Older
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
Copyright (c) 2007 by Juliusz Chroboczek

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <assert.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

41
#include "babel.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
42 43 44
#include "util.h"
#include "net.h"
#include "kernel.h"
45
#include "network.h"
46
#include "source.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
47 48 49 50
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
51
#include "request.h"
52
#include "filter.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
53 54 55 56 57 58 59 60

struct timeval now;

unsigned char myid[16];
int debug = 0;

int reboot_time;

61
int idle_time = 320;
62
int link_detect = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
63
int all_wireless = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
64 65
int wireless_hello_interval = -1;
int wired_hello_interval = -1;
66
int idle_hello_interval = -1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
67 68
int update_interval = -1;

69 70 71
unsigned char *receive_buffer = NULL;
int receive_buffer_size = 0;

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
72
const unsigned char zeroes[16] = {0};
73 74 75
const unsigned char ones[16] =
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
76

77
char *state_file = "/var/lib/babel-state";
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
78 79 80 81

int protocol_port;
unsigned char protocol_group[16];
int protocol_socket = -1;
82
int kernel_socket = -1;
83
static int kernel_routes_changed = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
84

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
85
static volatile sig_atomic_t exiting = 0, dumping = 0, changed = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
86

87
static int kernel_routes_callback(void *closure);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
88
static void init_signals(void);
89
static void dump_tables(FILE *out);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
90 91 92 93 94 95

int
main(int argc, char **argv)
{
    struct sockaddr_in6 sin6;
    int i, rc, fd;
96
    struct timeval check_neighbours_time;
97
    int expiry_time, kernel_dump_time;
98
    char *config_file = NULL;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
99 100 101 102
    void *vrc;
    unsigned int seed;
    char **arg;

103
    parse_address("ff02::cca6:c0f9:e182:5373", protocol_group, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
104 105
    protocol_port = 8475;

106
#define SHIFT() do { arg++; } while(0)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
107 108 109 110 111 112 113 114 115 116 117 118
#define SHIFTE() do { arg++; if(*arg == NULL) goto syntax; } while(0)

    arg = argv;

    SHIFTE();

    while((*arg)[0] == '-') {
        if(strcmp(*arg, "--") == 0) {
            SHIFTE();
            break;
        } else if(strcmp(*arg, "-m") == 0) {
            SHIFTE();
119
            rc = parse_address(*arg, protocol_group, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
            if(rc < 0)
                goto syntax;
            if(protocol_group[0] != 0xff) {
                fprintf(stderr,
                        "%s is not a multicast address\n", *arg);
                goto syntax;
            }
            if(protocol_group[1] != 2) {
                fprintf(stderr,
                        "Warning: %s is not a link-local multicast address\n",
                        *arg);
            }
        } else if(strcmp(*arg, "-p") == 0) {
            SHIFTE();
            protocol_port = atoi(*arg);
135
        } else if(strcmp(*arg, "-X") == 0) {
136 137
            if(numxroutes >= MAXXROUTES) {
                fprintf(stderr, "Too many exported routes.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
138 139 140 141
                exit(1);
            }
            SHIFTE();
            rc = parse_net(*arg,
142
                           xroutes[numxroutes].prefix,
143
                           &xroutes[numxroutes].plen, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
144 145 146
            if(rc < 0)
                goto syntax;
            SHIFTE();
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
147
            if(strcmp(*arg, "infinity") == 0)
148 149 150 151 152 153 154
                xroutes[numxroutes].metric = INFINITY;
            else {
                int metric = atoi(*arg);
                if(metric < 0 || metric > INFINITY)
                    goto syntax;
                xroutes[numxroutes].metric = metric;
            }
155 156
            xroutes[numxroutes].forced = 1;
            xroutes[numxroutes].ifindex = 0;
157
            numxroutes++;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
158 159 160 161 162 163
        } else if(strcmp(*arg, "-h") == 0) {
            SHIFTE();
            wireless_hello_interval = atoi(*arg);
        } else if(strcmp(*arg, "-H") == 0) {
            SHIFTE();
            wired_hello_interval = atoi(*arg);
164 165 166
        } else if(strcmp(*arg, "-i") == 0) {
            SHIFTE();
            idle_hello_interval = atoi(*arg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
167 168 169 170 171 172
        } else if(strcmp(*arg, "-u") == 0) {
            SHIFTE();
            update_interval = atoi(*arg);
        } else if(strcmp(*arg, "-k") == 0) {
            SHIFTE();
            kernel_metric = atoi(*arg);
173
            if(kernel_metric < 0 || kernel_metric > 0xFFFF)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
174 175 176 177 178 179 180 181 182 183 184
                goto syntax;
        } else if(strcmp(*arg, "-P") == 0) {
            parasitic = 1;
        } else if(strcmp(*arg, "-s") == 0) {
            split_horizon = 0;
        } else if(strcmp(*arg, "-S") == 0) {
            SHIFTE();
            state_file = *arg;
        } else if(strcmp(*arg, "-d") == 0) {
            SHIFTE();
            debug = atoi(*arg);
185 186
        } else if(strcmp(*arg, "-l") == 0) {
            link_detect = 1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
187 188
        } else if(strcmp(*arg, "-w") == 0) {
            all_wireless = 1;
189 190 191 192 193 194 195 196 197 198
        } else if(strcmp(*arg, "-t") == 0) {
            SHIFTE();
            export_table = atoi(*arg);
            if(export_table < 0 || export_table > 0xFFFF)
                goto syntax;
        } else if(strcmp(*arg, "-T") == 0) {
            SHIFTE();
            import_table = atoi(*arg);
            if(import_table < 0 || import_table > 0xFFFF)
                goto syntax;
199 200 201 202 203 204 205 206 207 208 209 210
        } else if(strcmp(*arg, "-c") == 0) {
            SHIFTE();
            config_file = *arg;
        } else if(strcmp(*arg, "-C") == 0) {
            int rc;
            SHIFTE();
            rc = parse_config_from_string(*arg);
            if(rc < 0) {
                fprintf(stderr,
                        "Couldn't parse configuration from command line.\n");
                exit(1);
            }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
211 212 213 214 215 216
        } else {
            goto syntax;
        }
        SHIFTE();
    }

217 218 219 220 221 222 223 224 225

    if(!config_file) {
        if(access("/etc/babel.conf", R_OK) >= 0)
            config_file = "/etc/babel.conf";
    }
    if(config_file) {
        rc = parse_config_from_file(config_file);
        if(rc < 0) {
            fprintf(stderr,
226 227
                    "Couldn't parse configuration from file %s.\n",
                    config_file);
228 229 230 231
            exit(1);
        }
    }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
232
    if(wireless_hello_interval <= 0)
233
        wireless_hello_interval = 6;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
234 235 236 237 238 239 240

    if(wired_hello_interval <= 0)
        wired_hello_interval = 30;

    if(update_interval <= 0)
        update_interval =
            MIN(MAX(wireless_hello_interval * 5, wired_hello_interval),
241
                70);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
242 243

    if(seqno_interval <= 0)
244
        seqno_interval = MAX(wireless_hello_interval - 1, 2);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
245

246
    rc = parse_address(*arg, myid, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
247 248 249 250 251
    if(rc < 0)
        goto syntax;
    SHIFTE();

    gettimeofday(&now, NULL);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

    fd = open("/dev/urandom", O_RDONLY);
    if(fd < 0) {
        perror("open(random)");
        memcpy(&seed, myid + 12, 4);
    } else {
        rc = read(fd, &seed, sizeof(unsigned int));
        if(rc < sizeof(unsigned int)) {
            perror("read(random)");
            exit(1);
        }
        close(fd);
    }
    seed ^= (now.tv_sec ^ now.tv_usec);
    srandom(seed);

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
268
    reboot_time = now.tv_sec;
269
    myseqno = (random() & 0xFFFF);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
270 271 272

    fd = open(state_file, O_RDONLY);
    if(fd < 0 && errno != ENOENT)
273
        perror("open(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
274
    rc = unlink(state_file);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
275
    if(rc < 0)
276
        perror("unlink(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
277
    if(fd >= 0 && rc < 0) {
278
        /* If we couldn't unlink it, it's probably stale. */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
279 280 281 282 283
        close(fd);
        fd = -1;
    }
    if(fd >= 0) {
        char buf[100];
284 285 286
        char buf2[100];
        int s;
        long t;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
287 288
        rc = read(fd, buf, 99);
        if(rc < 0) {
289
            perror("read(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
290 291
        } else {
            buf[rc] = '\0';
292 293 294
            rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
            if(rc == 3 && s >= 0 && s <= 0xFFFF) {
                unsigned char sid[16];
295
                rc = parse_address(buf2, sid, NULL);
296 297 298 299 300
                if(rc < 0) {
                    fprintf(stderr, "Couldn't parse babel-state.\n");
                } else {
                    debugf("Got %s %d %ld from babel-state.\n",
                           format_address(sid), s, t);
301 302 303 304
                    if(memcmp(sid, myid, 16) == 0)
                        myseqno = seqno_plus(s, 1);
                    else
                        fprintf(stderr, "ID mismatch in babel-state.\n");
305 306 307
                    if(t >= 1176800000L && t <= now.tv_sec)
                        reboot_time = t;
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
308
            } else {
309
                fprintf(stderr, "Couldn't parse babel-state.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
310 311 312 313 314
            }
        }
        close(fd);
    }

315 316 317 318
    if(reboot_time + silent_time > now.tv_sec)
        fprintf(stderr, "Respecting %ld second silent time.\n",
                (long int)(reboot_time + silent_time - now.tv_sec));

319
    rc = kernel_setup(1);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
320 321 322 323 324
    if(rc < 0) {
        fprintf(stderr, "kernel_setup failed.\n");
        exit(1);
    }

325 326 327 328 329 330
    rc = kernel_setup_socket(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup_socket failed.\n");
        exit(1);
    }

331
    protocol_socket = babel_socket(protocol_port);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
332 333 334 335 336 337
    if(protocol_socket < 0) {
        perror("Couldn't create link local socket");
        goto fail;
    }

    while(*arg) {
338 339
        debugf("Adding network %s.\n", *arg);
        vrc = add_network(*arg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
340 341 342 343 344
        if(vrc == NULL)
            goto fail;
        SHIFT();
    }

345 346
    init_signals();
    check_networks();
347
    if(receive_buffer == NULL) {
348
        fprintf(stderr, "Warning: couldn't find any operational interfaces.\n");
349 350 351
        resize_receive_buffer(1500);
        if(receive_buffer == NULL)
            goto fail;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
352
    }
353
    check_xroutes();
354 355
    kernel_routes_changed = 0;
    kernel_dump_time = now.tv_sec + 20 + random() % 20;
356
    timeval_plus_msec(&check_neighbours_time, &now, 5000 + random() % 5000);
357
    expiry_time = now.tv_sec + 20 + random() % 20;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
358

359
    /* Make some noise so that others notice us */
360
    for(i = 0; i < numnets; i++) {
361 362
        if(!nets[i].up)
            continue;
363
        gettimeofday(&now, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
364
        send_hello(&nets[i]);
365
        send_self_update(&nets[i], 0);
366
        send_request(&nets[i], NULL, 0, 0, 0, 0);
367 368
        flushbuf(&nets[i]);
        usleep(50000 + random() % 100000);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
369 370 371 372 373 374 375 376 377 378
    }

    debugf("Entering main loop.\n");

    while(1) {
        struct timeval tv;
        fd_set readfds;

        gettimeofday(&now, NULL);

379 380
        tv = check_neighbours_time;
        timeval_min_sec(&tv, expiry_time);
381 382
        if(request_resend_time)
            timeval_min_sec(&tv, request_resend_time);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
383
        for(i = 0; i < numnets; i++) {
384 385
            if(!nets[i].up)
                continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
386 387 388
            timeval_min(&tv, &nets[i].flush_time);
            timeval_min_sec(&tv,
                            nets[i].hello_time + nets[i].hello_interval);
389 390 391 392 393
            if(!network_idle(&nets[i])) {
                timeval_min_sec(&tv, nets[i].self_update_time +
                                nets[i].self_update_interval);
                timeval_min_sec(&tv, nets[i].update_time + update_interval);
            }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
394 395
        }
        timeval_min(&tv, &update_flush_time);
396
        FD_ZERO(&readfds);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
397 398 399
        if(timeval_compare(&tv, &now) > 0) {
            timeval_minus(&tv, &tv, &now);
            FD_SET(protocol_socket, &readfds);
400
            if(kernel_socket < 0) kernel_setup_socket(1);
401 402 403 404
            if(kernel_socket >= 0)
                FD_SET(kernel_socket, &readfds);
            rc = select(MAX(protocol_socket, kernel_socket) + 1,
                        &readfds, NULL, NULL, &tv);
405
            if(rc < 0) {
406 407 408 409
                if(errno == EINTR) {
                    rc = 0;
                    FD_ZERO(&readfds);
                } else {
410 411 412 413
                    perror("select");
                    sleep(1);
                    continue;
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
414 415 416 417 418 419 420 421
            }
        }

        gettimeofday(&now, NULL);

        if(exiting)
            break;

422
        if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds))
423
            kernel_callback(kernel_routes_callback, NULL);
424

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
425
        if(FD_ISSET(protocol_socket, &readfds)) {
426 427 428
            rc = babel_recv(protocol_socket,
                            receive_buffer, receive_buffer_size,
                            (struct sockaddr*)&sin6, sizeof(sin6));
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
429 430 431 432 433 434 435
            if(rc < 0) {
                if(errno != EAGAIN && errno != EINTR) {
                    perror("recv");
                    sleep(1);
                }
            } else {
                for(i = 0; i < numnets; i++) {
436 437
                    if(!nets[i].up)
                        continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
438 439
                    if(nets[i].ifindex == sin6.sin6_scope_id) {
                        parse_packet((unsigned char*)&sin6.sin6_addr, &nets[i],
440 441 442
                                     receive_buffer, rc);
                        VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer,
                                                    receive_buffer_size);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
443 444 445 446 447 448
                        break;
                    }
                }
            }
        }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
449 450 451 452 453 454 455
        if(changed) {
            kernel_dump_time = now.tv_sec;
            check_neighbours_time = now;
            expiry_time = now.tv_sec;
            changed = 0;
        }

456
        if(kernel_routes_changed || now.tv_sec >= kernel_dump_time) {
457
            rc = check_xroutes();
458 459 460
            if(rc > 0)
                send_self_update(NULL, 1);
            else if(rc < 0)
461
                fprintf(stderr, "Warning: couldn't check exported routes.\n");
462 463
            kernel_routes_changed = 0;
            if(kernel_socket >= 0)
464
                kernel_dump_time = now.tv_sec + 200 + random() % 200;
465 466 467 468
            else
                kernel_dump_time = now.tv_sec + 20 + random() % 20;
        }

469 470 471 472 473 474 475 476 477
        if(timeval_compare(&check_neighbours_time, &now) < 0) {
            int msecs;
            msecs = check_neighbours();
            msecs = MAX(msecs, 500);
            timeval_plus_msec(&check_neighbours_time, &now,
                              msecs / 2 + random() % msecs);
        }

        if(now.tv_sec >= expiry_time) {
478
            check_networks();
479
            expire_routes();
480
            expire_requests();
481 482 483
            expiry_time = now.tv_sec + 20 + random() % 20;
        }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
484
        for(i = 0; i < numnets; i++) {
485 486
            if(!nets[i].up)
                continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
487 488
            if(now.tv_sec >= nets[i].hello_time + nets[i].hello_interval)
                send_hello(&nets[i]);
489 490
            if(now.tv_sec >= nets[i].ihu_time + nets[i].ihu_interval)
                send_ihu(NULL, &nets[i]);
491 492
            if(!network_idle(&nets[i])) {
                if(now.tv_sec >= nets[i].update_time + update_interval)
493
                    send_update(&nets[i], 0, NULL, 0);
494 495 496 497
                if(now.tv_sec >=
                   nets[i].self_update_time + nets[i].self_update_interval) {
                    send_self_update(&nets[i], 0);
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
498 499 500
            }
        }

501 502 503
        if(now.tv_sec >= request_resend_time)
            resend_requests();

504 505 506 507 508 509
        if(update_flush_time.tv_sec != 0) {
            if(now.tv_sec >= update_flush_time.tv_sec)
                flushupdates();
        }

        for(i = 0; i < numnets; i++) {
510 511
            if(!nets[i].up)
                continue;
512 513 514 515 516 517
            if(nets[i].flush_time.tv_sec != 0) {
                if(timeval_compare(&now, &nets[i].flush_time) >= 0)
                    flushbuf(&nets[i]);
            }
        }

518
        if(debug || dumping) {
519
            dump_tables(stdout);
520 521
            dumping = 0;
        }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
522 523 524 525 526 527 528
    }

    debugf("Exiting...\n");
    for(i = 0; i < numroutes; i++) {
        /* Uninstall and retract all routes. */
        if(routes[i].installed) {
            uninstall_route(&routes[i]);
529
            send_update(NULL, 1, routes[i].src->prefix, routes[i].src->plen);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
530 531 532
        }
    }
    for(i = 0; i < numnets; i++) {
533 534
        if(!nets[i].up)
            continue;
535
        /* Retract exported routes. */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
536 537 538
        send_self_retract(&nets[i]);
        /* Make sure that we expire quickly from our neighbours'
           association caches. */
539
        send_hello_noupdate(&nets[i], 15 * numnets);
540
        flushupdates();
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
541
        flushbuf(&nets[i]);
542
        usleep(50000 + random() % 100000);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
543 544
    }
    for(i = 0; i < numnets; i++) {
545 546
        if(!nets[i].up)
            continue;
547
        /* Make sure they got it. */
548
        send_self_retract(&nets[i]);
549
        send_hello_noupdate(&nets[i], 1);
550
        flushupdates();
551
        flushbuf(&nets[i]);
552
        usleep(50000 + random() % 100000);
553
        network_up(&nets[i], 0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
554
    }
555
    kernel_setup_socket(0);
556
    kernel_setup(0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
557 558 559

    fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
    if(fd < 0) {
560
        perror("creat(babel-state)");
561
        unlink(state_file);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
562 563
    } else {
        char buf[100];
564 565
        rc = snprintf(buf, 100, "%s %d %ld\n",
                      format_address(myid), (int)myseqno, (long)now.tv_sec);
566 567
        if(rc < 0 || rc >= 100) {
            fprintf(stderr, "write(babel-state): overflow.\n");
568
            unlink(state_file);
569 570 571 572 573 574 575
        } else {
            rc = write(fd, buf, rc);
            if(rc < 0) {
                perror("write(babel-state)");
                unlink(state_file);
            }
            fsync(fd);
576
        }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
577 578
        close(fd);
    }
579
    debugf("Done.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
580 581 582 583 584 585 586
    return 0;

 syntax:
    fprintf(stderr,
            "Syntax: %s "
            "[-m multicast_address] [-p port] [-S state-file]\n"
            "                "
587
            "[-h hello] [-H wired_hello] [-i idle_hello] [-u update]\n"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
588
            "                "
589
            "[-k metric] [-s] [-P] [-l] [-w] [-d level]\n"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
590
            "                "
591
            "[-t table] [-T table] [-X net cost] [-c file] [-C statement]\n"
592 593
            "                "
            "id interface...\n",
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
594 595 596 597
            argv[0]);
    exit(1);

 fail:
598 599 600
    for(i = 0; i < numnets; i++) {
        if(!nets[i].up)
            continue;
601
        network_up(&nets[i], 0);
602
    }
603
    kernel_setup_socket(0);
604
    kernel_setup(0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
605 606 607
    exit(1);
}

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
void
resize_receive_buffer(int size)
{
    char *new;

    if(size <= receive_buffer_size)
        return;

    if(receive_buffer == NULL) {
        receive_buffer = malloc(size);
        if(receive_buffer == NULL)
            return;
        receive_buffer_size = size;
    }

    new = realloc(receive_buffer, size);
    if(new == NULL) {
        perror("malloc(receive_buffer)");
        return;
    }
    receive_buffer_size = size;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
631 632 633 634 635 636
static void
sigexit(int signo)
{
    exiting = 1;
}

637 638 639 640 641 642
static void
sigdump(int signo)
{
    dumping = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
643 644 645 646 647 648
static void
sigchanged(int signo)
{
    changed = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
static void
init_signals(void)
{
    struct sigaction sa;
    sigset_t ss;

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGHUP, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
672 673 674 675 676 677

    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);
678

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
679 680 681 682 683 684
    sigemptyset(&ss);
    sa.sa_handler = sigchanged;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);

685 686 687 688 689 690 691
#ifdef SIGINFO
    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINFO, &sa, NULL);
#endif
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
692 693
}

694 695 696 697 698 699
static void
dump_tables(FILE *out)
{
    int i;

    fprintf(out, "\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
700

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
701
    fprintf(out, "My id %s seqno %d\n", format_address(myid), myseqno);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
702

703
    for(i = 0; i < numneighs; i++) {
704
        if(neighs[i].id[0] == 0xFF)
705 706
            continue;
        fprintf(out, "Neighbour %s ", format_address(neighs[i].id));
707 708 709 710 711 712 713
        fprintf(out, "at %s dev %s reach %04x rxcost %d txcost %d%s.\n",
                format_address(neighs[i].address),
                neighs[i].network->ifname,
                neighs[i].reach,
                neighbour_rxcost(&neighs[i]),
                neighs[i].txcost,
                neighs[i].network->up ? "" : " (down)");
714 715
    }
    for(i = 0; i < numxroutes; i++) {
716 717
        fprintf(out, "%s metric %d (%s)\n",
                format_prefix(xroutes[i].prefix, xroutes[i].plen),
718
                xroutes[i].metric,
719
                xroutes[i].forced ? "forced" : "exported");
720 721
    }
    for(i = 0; i < numroutes; i++) {
722 723 724
        int id =
            routes[i].src->plen != 128 ||
            memcmp(routes[i].src->prefix, routes[i].src->address, 16) != 0;
725 726 727
        const unsigned char *nexthop =
            memcmp(routes[i].nexthop, routes[i].neigh->address, 16) == 0 ?
            NULL : routes[i].nexthop;
728
        fprintf(out, "%s metric %d refmetric %d %s%s seqno %d age %d "
729
                "via %s neigh %s%s%s%s\n",
730
                format_prefix(routes[i].src->prefix, routes[i].src->plen),
731 732 733 734
                routes[i].metric, routes[i].refmetric,
                id ? "id " : "",
                id ? format_address(routes[i].src->address) : "",
                (int)routes[i].seqno,
735
                (int)(now.tv_sec - routes[i].time),
736 737
                routes[i].neigh->network->ifname,
                format_address(routes[i].neigh->address),
738 739
                nexthop ? " nexthop " : "",
                nexthop ? format_address(nexthop) : "",
740 741
                routes[i].installed ? " (installed)" :
                route_feasible(&routes[i]) ? " (feasible)" : "");
742 743 744 745
    }
    fflush(out);
}

746
static int
747
kernel_routes_callback(void *closure)
748
{
749
    kernel_routes_changed = 1;
750
    return 1;
751
}