babel.c 22.2 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 */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
360
    for(i = 0; i < numnets; i++) {
361 362
        if(!nets[i].up)
            continue;
363
        gettimeofday(&now, NULL);
364
        send_hello(&nets[i]);
365
        send_request(&nets[i], NULL, 0, 0, 0, 0);
366 367
        flushbuf(&nets[i]);
        usleep(50000 + random() % 100000);
368
    }
369

370
    for(i = 0; i < numnets; i++) {
371 372
        if(!nets[i].up)
            continue;
373
        gettimeofday(&now, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
374
        send_hello(&nets[i]);
375
        send_self_update(&nets[i], 0);
376
        send_request(&nets[i], NULL, 0, 0, 0, 0);
377 378
        flushbuf(&nets[i]);
        usleep(50000 + random() % 100000);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
379 380 381 382 383 384 385 386 387 388
    }

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

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

        gettimeofday(&now, NULL);

389 390
        tv = check_neighbours_time;
        timeval_min_sec(&tv, expiry_time);
391 392
        if(request_resend_time)
            timeval_min_sec(&tv, request_resend_time);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
393
        for(i = 0; i < numnets; i++) {
394 395
            if(!nets[i].up)
                continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
396 397 398
            timeval_min(&tv, &nets[i].flush_time);
            timeval_min_sec(&tv,
                            nets[i].hello_time + nets[i].hello_interval);
399 400 401 402 403
            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
404 405
        }
        timeval_min(&tv, &update_flush_time);
406
        FD_ZERO(&readfds);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
407 408 409
        if(timeval_compare(&tv, &now) > 0) {
            timeval_minus(&tv, &tv, &now);
            FD_SET(protocol_socket, &readfds);
410
            if(kernel_socket < 0) kernel_setup_socket(1);
411 412 413 414
            if(kernel_socket >= 0)
                FD_SET(kernel_socket, &readfds);
            rc = select(MAX(protocol_socket, kernel_socket) + 1,
                        &readfds, NULL, NULL, &tv);
415
            if(rc < 0) {
416 417 418 419
                if(errno == EINTR) {
                    rc = 0;
                    FD_ZERO(&readfds);
                } else {
420 421 422 423
                    perror("select");
                    sleep(1);
                    continue;
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
424 425 426 427 428 429 430 431
            }
        }

        gettimeofday(&now, NULL);

        if(exiting)
            break;

432
        if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds))
433
            kernel_callback(kernel_routes_callback, NULL);
434

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
435
        if(FD_ISSET(protocol_socket, &readfds)) {
436 437 438
            rc = babel_recv(protocol_socket,
                            receive_buffer, receive_buffer_size,
                            (struct sockaddr*)&sin6, sizeof(sin6));
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
439 440 441 442 443 444 445
            if(rc < 0) {
                if(errno != EAGAIN && errno != EINTR) {
                    perror("recv");
                    sleep(1);
                }
            } else {
                for(i = 0; i < numnets; i++) {
446 447
                    if(!nets[i].up)
                        continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
448 449
                    if(nets[i].ifindex == sin6.sin6_scope_id) {
                        parse_packet((unsigned char*)&sin6.sin6_addr, &nets[i],
450 451 452
                                     receive_buffer, rc);
                        VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer,
                                                    receive_buffer_size);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
453 454 455 456 457 458
                        break;
                    }
                }
            }
        }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
459 460 461 462 463 464 465
        if(changed) {
            kernel_dump_time = now.tv_sec;
            check_neighbours_time = now;
            expiry_time = now.tv_sec;
            changed = 0;
        }

466
        if(kernel_routes_changed || now.tv_sec >= kernel_dump_time) {
467
            rc = check_xroutes();
468 469 470
            if(rc > 0)
                send_self_update(NULL, 1);
            else if(rc < 0)
471
                fprintf(stderr, "Warning: couldn't check exported routes.\n");
472 473
            kernel_routes_changed = 0;
            if(kernel_socket >= 0)
474
                kernel_dump_time = now.tv_sec + 200 + random() % 200;
475 476 477 478
            else
                kernel_dump_time = now.tv_sec + 20 + random() % 20;
        }

479 480 481 482 483 484 485 486 487
        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) {
488
            check_networks();
489
            expire_routes();
490
            expire_requests();
491 492 493
            expiry_time = now.tv_sec + 20 + random() % 20;
        }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
494
        for(i = 0; i < numnets; i++) {
495 496
            if(!nets[i].up)
                continue;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
497 498
            if(now.tv_sec >= nets[i].hello_time + nets[i].hello_interval)
                send_hello(&nets[i]);
499 500
            if(now.tv_sec >= nets[i].ihu_time + nets[i].ihu_interval)
                send_ihu(NULL, &nets[i]);
501 502
            if(!network_idle(&nets[i])) {
                if(now.tv_sec >= nets[i].update_time + update_interval)
503
                    send_update(&nets[i], 0, NULL, 0);
504 505 506 507
                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
508 509 510
            }
        }

511 512 513
        if(now.tv_sec >= request_resend_time)
            resend_requests();

514 515 516 517 518 519
        if(update_flush_time.tv_sec != 0) {
            if(now.tv_sec >= update_flush_time.tv_sec)
                flushupdates();
        }

        for(i = 0; i < numnets; i++) {
520 521
            if(!nets[i].up)
                continue;
522 523 524 525 526 527
            if(nets[i].flush_time.tv_sec != 0) {
                if(timeval_compare(&now, &nets[i].flush_time) >= 0)
                    flushbuf(&nets[i]);
            }
        }

528
        if(debug || dumping) {
529
            dump_tables(stdout);
530 531
            dumping = 0;
        }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
532 533 534 535 536 537 538
    }

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

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

 syntax:
    fprintf(stderr,
            "Syntax: %s "
            "[-m multicast_address] [-p port] [-S state-file]\n"
            "                "
597
            "[-h hello] [-H wired_hello] [-i idle_hello] [-u update]\n"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
598
            "                "
599
            "[-k metric] [-s] [-P] [-l] [-w] [-d level]\n"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
600
            "                "
601
            "[-t table] [-T table] [-X net cost] [-c file] [-C statement]\n"
602 603
            "                "
            "id interface...\n",
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
604 605 606 607
            argv[0]);
    exit(1);

 fail:
608 609 610
    for(i = 0; i < numnets; i++) {
        if(!nets[i].up)
            continue;
611
        network_up(&nets[i], 0);
612
    }
613
    kernel_setup_socket(0);
614
    kernel_setup(0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
615 616 617
    exit(1);
}

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
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
641 642 643 644 645 646
static void
sigexit(int signo)
{
    exiting = 1;
}

647 648 649 650 651 652
static void
sigdump(int signo)
{
    dumping = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
653 654 655 656 657 658
static void
sigchanged(int signo)
{
    changed = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
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);
682 683 684 685 686 687

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

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
689 690 691 692 693 694
    sigemptyset(&ss);
    sa.sa_handler = sigchanged;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);

695 696 697 698 699 700 701
#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
702 703
}

704 705 706 707 708 709
static void
dump_tables(FILE *out)
{
    int i;

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

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

713
    for(i = 0; i < numneighs; i++) {
714
        if(neighs[i].id[0] == 0xFF)
715 716
            continue;
        fprintf(out, "Neighbour %s ", format_address(neighs[i].id));
717 718 719 720 721 722 723
        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)");
724 725
    }
    for(i = 0; i < numxroutes; i++) {
726 727
        fprintf(out, "%s metric %d (%s)\n",
                format_prefix(xroutes[i].prefix, xroutes[i].plen),
728
                xroutes[i].metric,
729
                xroutes[i].forced ? "forced" : "exported");
730 731
    }
    for(i = 0; i < numroutes; i++) {
732 733 734
        int id =
            routes[i].src->plen != 128 ||
            memcmp(routes[i].src->prefix, routes[i].src->address, 16) != 0;
735 736 737
        const unsigned char *nexthop =
            memcmp(routes[i].nexthop, routes[i].neigh->address, 16) == 0 ?
            NULL : routes[i].nexthop;
738
        fprintf(out, "%s metric %d refmetric %d %s%s seqno %d age %d "
739
                "via %s neigh %s%s%s%s\n",
740
                format_prefix(routes[i].src->prefix, routes[i].src->plen),
741 742 743 744
                routes[i].metric, routes[i].refmetric,
                id ? "id " : "",
                id ? format_address(routes[i].src->address) : "",
                (int)routes[i].seqno,
745
                (int)(now.tv_sec - routes[i].time),
746 747
                routes[i].neigh->network->ifname,
                format_address(routes[i].neigh->address),
748 749
                nexthop ? " nexthop " : "",
                nexthop ? format_address(nexthop) : "",
750 751
                routes[i].installed ? " (installed)" :
                route_feasible(&routes[i]) ? " (feasible)" : "");
752 753 754 755
    }
    fflush(out);
}

756
static int
757
kernel_routes_callback(void *closure)
758
{
759
    kernel_routes_changed = 1;
760
    return 1;
761
}