babel.c 23.4 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 "source.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"

struct timeval now;

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

static int maxmtu;

int reboot_time;

60 61
int idle_time = 320;

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
62 63
int wireless_hello_interval = -1;
int wired_hello_interval = -1;
64
int idle_hello_interval = -1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
65 66 67 68 69
int update_interval = -1;

struct network nets[MAXNETS];
int numnets = 0;

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
70
const unsigned char zeroes[16] = {0};
71 72 73
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
74

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

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

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

struct network *add_network(char *ifname, int ifindex, int bufsize,
86
                            int wired, unsigned int cost);
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 96 97

int
main(int argc, char **argv)
{
    struct sockaddr_in6 sin6;
    struct ipv6_mreq mreq;
    int i, rc, fd;
    static unsigned char *buf;
98
    struct timeval check_neighbours_time;
99
    int expiry_time, kernel_dump_time;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
100 101 102 103 104 105 106
    void *vrc;
    unsigned int seed;
    char **arg;

    parse_address("ff02::cca6:c0f9:e182:5373", protocol_group);
    protocol_port = 8475;

107
#define SHIFT() do { arg++; } while(0)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
#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();
            rc = parse_address(*arg, protocol_group);
            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);
136 137
        } else if(strcmp(*arg, "-x") == 0 || strcmp(*arg, "-X") == 0) {
            int force = (strcmp(*arg, "-X") == 0);
138 139
            if(numxroutes >= MAXXROUTES) {
                fprintf(stderr, "Too many exported routes.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
140 141 142 143
                exit(1);
            }
            SHIFTE();
            rc = parse_net(*arg,
144 145
                           xroutes[numxroutes].prefix,
                           &xroutes[numxroutes].plen);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
146 147 148
            if(rc < 0)
                goto syntax;
            SHIFTE();
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
149
            if(strcmp(*arg, "infinity") == 0)
150 151 152 153 154 155 156 157 158
                xroutes[numxroutes].metric = INFINITY;
            else {
                int metric = atoi(*arg);
                if(metric < 0 || metric > INFINITY)
                    goto syntax;
                xroutes[numxroutes].metric = metric;
            }
            xroutes[numxroutes].exported = force ? 2 : 0;
            numxroutes++;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
159 160 161 162 163 164
        } else if(strcmp(*arg, "-h") == 0) {
            SHIFTE();
            wireless_hello_interval = atoi(*arg);
        } else if(strcmp(*arg, "-H") == 0) {
            SHIFTE();
            wired_hello_interval = atoi(*arg);
165 166 167
        } else if(strcmp(*arg, "-i") == 0) {
            SHIFTE();
            idle_hello_interval = atoi(*arg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
168 169 170 171 172 173
        } else if(strcmp(*arg, "-u") == 0) {
            SHIFTE();
            update_interval = atoi(*arg);
        } else if(strcmp(*arg, "-k") == 0) {
            SHIFTE();
            kernel_metric = atoi(*arg);
174
            if(kernel_metric < 0 || kernel_metric > 0xFFFF)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
175 176 177
                goto syntax;
        } else if(strcmp(*arg, "-P") == 0) {
            parasitic = 1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
178 179 180 181 182
        } else if(strcmp(*arg, "-c") == 0) {
            SHIFTE();
            add_cost = atoi(*arg);
            if(add_cost < 0 || add_cost > INFINITY)
                goto syntax;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
183 184 185
        } else if(strcmp(*arg, "-s") == 0) {
            split_horizon = 0;
        } else if(strcmp(*arg, "-b") == 0) {
186
            broadcast_ihu = 1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
187 188 189 190 191 192 193 194 195 196 197 198 199
        } else if(strcmp(*arg, "-S") == 0) {
            SHIFTE();
            state_file = *arg;
        } else if(strcmp(*arg, "-d") == 0) {
            SHIFTE();
            debug = atoi(*arg);
        } else {
            goto syntax;
        }
        SHIFTE();
    }

    if(wireless_hello_interval <= 0)
200
        wireless_hello_interval = 6;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
201 202 203 204 205 206 207

    if(wired_hello_interval <= 0)
        wired_hello_interval = 30;

    if(update_interval <= 0)
        update_interval =
            MIN(MAX(wireless_hello_interval * 5, wired_hello_interval),
208
                70);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
209 210

    if(seqno_interval <= 0)
211
        seqno_interval = MAX(wireless_hello_interval - 1, 2);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
212 213 214 215 216 217 218

    rc = parse_address(*arg, myid);
    if(rc < 0)
        goto syntax;
    SHIFTE();

    gettimeofday(&now, NULL);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234

    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
235
    reboot_time = now.tv_sec;
236
    myseqno = (random() & 0xFFFF);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
237 238 239

    fd = open(state_file, O_RDONLY);
    if(fd < 0 && errno != ENOENT)
240
        perror("open(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
241 242
    rc = unlink(state_file);
    if(fd >= 0 && rc < 0) {
243
        perror("unlink(babel-state)");
244
        /* If we couldn't unlink it, it's probably stale. */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
245 246 247 248 249
        close(fd);
        fd = -1;
    }
    if(fd >= 0) {
        char buf[100];
250 251 252
        char buf2[100];
        int s;
        long t;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
253 254
        rc = read(fd, buf, 99);
        if(rc < 0) {
255
            perror("read(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
256 257
        } else {
            buf[rc] = '\0';
258 259 260 261 262 263 264 265 266 267 268
            rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
            if(rc == 3 && s >= 0 && s <= 0xFFFF) {
                unsigned char sid[16];
                rc = parse_address(buf2, sid);
                if(rc < 0) {
                    fprintf(stderr, "Couldn't parse babel-state.\n");
                } else if(memcmp(sid, myid, 16) != 0) {
                    fprintf(stderr, "ID mismatch in babel-state.\n");
                } else {
                    debugf("Got %s %d %ld from babel-state.\n",
                           format_address(sid), s, t);
269
                    myseqno = seqno_plus(s, 1);
270 271 272
                    if(t >= 1176800000L && t <= now.tv_sec)
                        reboot_time = t;
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
273
            } else {
274
                fprintf(stderr, "Couldn't parse babel-state.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
275 276 277 278 279 280 281 282 283 284 285
            }
        }
        close(fd);
    }

    rc = kernel_setup(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup failed.\n");
        exit(1);
    }

286 287 288 289 290 291
    rc = kernel_setup_socket(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup_socket failed.\n");
        exit(1);
    }

292
    protocol_socket = babel_socket(protocol_port);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
293 294 295 296 297 298 299 300 301 302 303 304 305
    if(protocol_socket < 0) {
        perror("Couldn't create link local socket");
        goto fail;
    }

    /* Just in case. */
    maxmtu = 1500;

    while(*arg) {
        int ifindex;
        int mtu;

        ifindex = if_nametoindex(*arg);
306 307
        if(ifindex <= 0) {
            fprintf(stderr, "Unknown interface %s.\n", *arg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
            goto fail;
        }

        rc = kernel_setup_interface(1, *arg, ifindex);
        if(rc < 0) {
            fprintf(stderr, "kernel_setup_interface(%s, %d) failed.\n",
                    *arg, ifindex);
            goto fail;
        }

        memset(&mreq, 0, sizeof(mreq));
        memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
        mreq.ipv6mr_interface = ifindex;

        rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                        (char*)&mreq, sizeof(mreq));
        if(rc < 0) {
            perror("setsockopt(IPV6_JOIN_GROUP)");
            goto fail;
        }

        mtu = kernel_interface_mtu(*arg, ifindex);
        if(mtu < 0) {
            fprintf(stderr, "Warning: couldn't get MTU of interface %s (%d).\n",
                    *arg, ifindex);
333 334
            mtu = 1280;
            maxmtu = MAX(maxmtu, 0x10000);
335
        } else if(mtu < 1280) {
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
336 337 338
            fprintf(stderr,
                    "Warning: suspiciously low MTU %d on interface %s (%d).\n",
                    mtu, *arg, ifindex);
339 340
            mtu = 1280;
            maxmtu = MAX(maxmtu, 0x10000);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
341 342 343 344 345 346 347 348 349 350
        } else {
            if(mtu >= 0x10000) {
                fprintf(stderr,
                        "Warning: "
                        "suspiciously high MTU %d on interface %s (%d).\n",
                        mtu, *arg, ifindex);
                maxmtu = MAX(maxmtu, mtu);
                mtu = 32768;
            }
        }
351 352 353
        maxmtu = MAX(maxmtu, mtu);
        /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
        mtu -= 60;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
354 355 356 357 358 359 360 361 362 363 364

        rc = kernel_interface_wireless(*arg, ifindex);
        if(rc < 0) {
            fprintf(stderr,
                    "Warning: "
                    "couldn't determine whether %s is a wireless interface.\n",
                    *arg);
            rc = 1;
        }
        debugf("Adding %s network %s (%d).\n",
               rc ? "wireless" : "wired", *arg, ifindex);
365
        vrc = add_network(*arg, ifindex, mtu, !rc, rc ? 256 : 128);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
366 367 368 369 370 371 372 373 374 375 376 377
        if(vrc == NULL)
            goto fail;
        SHIFT();
    }

    buf = malloc(maxmtu);
    if(buf == NULL) {
        perror("malloc");
        goto fail;
    }

    init_signals();
378
    check_xroutes();
379 380
    kernel_routes_changed = 0;
    kernel_dump_time = now.tv_sec + 20 + random() % 20;
381
    timeval_plus_msec(&check_neighbours_time, &now, 5000 + random() % 5000);
382
    expiry_time = now.tv_sec + 20 + random() % 20;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
383

384
    /* Make some noise so that others notice us */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
385
    for(i = 0; i < numnets; i++) {
386
        gettimeofday(&now, NULL);
387
        send_hello(&nets[i]);
388 389 390
        send_request(&nets[i], NULL, 0);
        flushbuf(&nets[i]);
        usleep(50000 + random() % 100000);
391
    }
392

393
    for(i = 0; i < numnets; i++) {
394
        gettimeofday(&now, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
395
        send_hello(&nets[i]);
396
        send_self_update(&nets[i], 0);
397 398 399
        send_request(&nets[i], NULL, 0);
        flushbuf(&nets[i]);
        usleep(50000 + random() % 100000);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
400 401 402 403 404 405 406 407 408 409
    }

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

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

        gettimeofday(&now, NULL);

410 411
        tv = check_neighbours_time;
        timeval_min_sec(&tv, expiry_time);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
412 413 414 415
        for(i = 0; i < numnets; i++) {
            timeval_min(&tv, &nets[i].flush_time);
            timeval_min_sec(&tv,
                            nets[i].hello_time + nets[i].hello_interval);
416 417 418 419 420
            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
421 422
        }
        timeval_min(&tv, &update_flush_time);
423
        FD_ZERO(&readfds);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
424 425 426
        if(timeval_compare(&tv, &now) > 0) {
            timeval_minus(&tv, &tv, &now);
            FD_SET(protocol_socket, &readfds);
427
            if(kernel_socket < 0) kernel_setup_socket(1);
428 429 430 431
            if(kernel_socket >= 0)
                FD_SET(kernel_socket, &readfds);
            rc = select(MAX(protocol_socket, kernel_socket) + 1,
                        &readfds, NULL, NULL, &tv);
432
            if(rc < 0) {
433 434 435 436
                if(errno == EINTR) {
                    rc = 0;
                    FD_ZERO(&readfds);
                } else {
437 438 439 440
                    perror("select");
                    sleep(1);
                    continue;
                }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
441 442 443 444 445 446 447 448
            }
        }

        gettimeofday(&now, NULL);

        if(exiting)
            break;

449
        if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds))
450
            kernel_callback(kernel_routes_callback, NULL);
451

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
452
        if(FD_ISSET(protocol_socket, &readfds)) {
453
            rc = babel_recv(protocol_socket, buf, maxmtu,
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
                              (struct sockaddr*)&sin6, sizeof(sin6));
            if(rc < 0) {
                if(errno != EAGAIN && errno != EINTR) {
                    perror("recv");
                    sleep(1);
                }
            } else {
                for(i = 0; i < numnets; i++) {
                    if(nets[i].ifindex == sin6.sin6_scope_id) {
                        parse_packet((unsigned char*)&sin6.sin6_addr, &nets[i],
                                     buf, rc);
                        VALGRIND_MAKE_MEM_UNDEFINED(buf, maxmtu);
                        break;
                    }
                }
            }
        }

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

485 486 487 488 489 490 491 492 493 494 495 496 497
        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) {
            expire_routes();
            expiry_time = now.tv_sec + 20 + random() % 20;
        }

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

513 514 515 516 517 518 519 520 521 522 523 524
        if(update_flush_time.tv_sec != 0) {
            if(now.tv_sec >= update_flush_time.tv_sec)
                flushupdates();
        }

        for(i = 0; i < numnets; i++) {
            if(nets[i].flush_time.tv_sec != 0) {
                if(timeval_compare(&now, &nets[i].flush_time) >= 0)
                    flushbuf(&nets[i]);
            }
        }

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

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

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

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

 fail:
    for(i = 0; i < numnets; i++)
        kernel_setup_interface(0, nets[i].ifname, nets[i].ifindex);
601
    kernel_setup_socket(0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
602 603 604 605 606 607 608 609 610 611
    kernel_setup(0);
    exit(1);
}

static void
sigexit(int signo)
{
    exiting = 1;
}

612 613 614 615 616 617
static void
sigdump(int signo)
{
    dumping = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
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);
641 642 643 644 645 646

    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);
647 648 649 650 651 652 653 654

#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
655 656
}

657 658 659 660 661 662
static void
dump_tables(FILE *out)
{
    int i;

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

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
664 665
    fprintf(out, "My id %s\n", format_address(myid));

666
    for(i = 0; i < numneighs; i++) {
667
        if(neighs[i].id[0] == 0xFF)
668 669 670 671 672 673 674 675 676 677
            continue;
        fprintf(out, "Neighbour %s ", format_address(neighs[i].id));
        fprintf(out, "at %s dev %s reach %04x rxcost %d txcost %d.\n",
               format_address(neighs[i].address),
               neighs[i].network->ifname,
               neighs[i].reach,
               neighbour_rxcost(&neighs[i]),
               neighs[i].txcost);
    }
    for(i = 0; i < numxroutes; i++) {
678 679
        fprintf(out, "%s metric %d (%s)\n",
                format_prefix(xroutes[i].prefix, xroutes[i].plen),
680
                xroutes[i].metric,
681 682 683 684 685
                xroutes[i].exported ?
                xroutes[i].exported > 1 ? "forced" : "exported" :
                "not exported");
    }
    for(i = 0; i < numroutes; i++) {
686 687 688 689
        int id =
            routes[i].src->plen != 128 ||
            memcmp(routes[i].src->prefix, routes[i].src->address, 16) != 0;
        fprintf(out, "%s metric %d refmetric %d %s%s seqno %d age %d "
690 691
                "via %s nexthop %s%s\n",
                format_prefix(routes[i].src->prefix, routes[i].src->plen),
692 693 694 695
                routes[i].metric, routes[i].refmetric,
                id ? "id " : "",
                id ? format_address(routes[i].src->address) : "",
                (int)routes[i].seqno,
696 697 698 699 700
                (int)(now.tv_sec - routes[i].time),
                routes[i].nexthop->network->ifname,
                format_address(routes[i].nexthop->address),
                routes[i].installed ? " (installed)" :
                route_feasible(&routes[i]) ? " (feasible)" : "");
701 702 703 704
    }
    fflush(out);
}

705
static int
706
kernel_routes_callback(void *closure)
707
{
708
    kernel_routes_changed = 1;
709
    return 1;
710 711
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
712
struct network *
713
add_network(char *ifname, int ifindex, int mtu, int wired, unsigned int cost)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
714 715 716 717 718 719 720 721 722 723 724 725
{
    void *p;

    if(numnets >= MAXNETS) {
        fprintf(stderr, "Too many networks.\n");
        return NULL;
    }

    memset(nets + numnets, 0, sizeof(struct network));
    nets[numnets].ifindex = ifindex;
    nets[numnets].wired = wired;
    nets[numnets].cost = cost;
726 727
    nets[numnets].activity_time = now.tv_sec;
    update_hello_interval(&nets[numnets]);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
728 729 730 731 732 733 734 735 736
    nets[numnets].bufsize = mtu - sizeof(packet_header);
    strncpy(nets[numnets].ifname, ifname, IF_NAMESIZE);
    p = malloc(nets[numnets].bufsize);
    if(p == NULL) {
        perror("malloc");
        return NULL;
    }
    nets[numnets].sendbuf = p;
    nets[numnets].buffered = 0;
737 738
    nets[numnets].bucket_time = now.tv_sec;
    nets[numnets].bucket = 0;
739
    nets[numnets].hello_seqno = (random() & 0xFFFF);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
740 741 742 743
    numnets++;
    return &nets[numnets - 1];
}

744 745 746 747 748 749 750
int
network_idle(struct network *net)
{
    return (idle_hello_interval > 0 &&
            net->activity_time < now.tv_sec - idle_time);
}

751
int
752 753
update_hello_interval(struct network *net)
{
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
    int rc = 0;

    if(network_idle(net)) {
        if(net->hello_interval != idle_hello_interval) {
            net->hello_interval = idle_hello_interval;
            rc = 1;
        }
    } else if(net->wired) {
        if(net->hello_interval != wired_hello_interval) {
            net->hello_interval = wired_hello_interval;
            rc = 1;
        }
    } else {
        if(net->hello_interval != wireless_hello_interval) {
            net->hello_interval = wireless_hello_interval;
            rc = 1;
        }
    }

    if(net->ihu_interval != 3 * net->hello_interval) {
        net->ihu_interval = 3 * net->hello_interval;
        rc = 1;
    }
777 778

    net->self_update_interval =
779
        MAX(15 + net->hello_interval / 2, net->hello_interval);
780

781
    return rc;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
782
}
783 784 785 786 787 788 789 790 791 792 793

/* This should be no more than half the hello interval, so that hellos
   aren't sent late.  The result is in milliseconds. */
unsigned int
jitter(struct network *net)
{
    unsigned interval = net->hello_interval * 1000;
    return (interval / 2 + random() % interval) / 4;
}

unsigned int
794
update_jitter(struct network *net, int urgent)
795 796
{
    unsigned interval = net->hello_interval * 1000;
797 798
    if(urgent)
        interval = MIN(interval, 1000);
799 800
    return (interval / 2 + random() % interval);
}