Blame view

interface.c 16.9 KB
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
/*
Copyright (c) 2007, 2008 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 <stdio.h>
#include <stdlib.h>
Juliusz Chroboczek committed
26
#include <errno.h>
Juliusz Chroboczek committed
27
#include <assert.h>
Juliusz Chroboczek committed
28
#include <sys/time.h>
Juliusz Chroboczek committed
29 30 31 32 33
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
Juliusz Chroboczek committed
34

Juliusz Chroboczek committed
35
#include "babeld.h"
Juliusz Chroboczek committed
36 37
#include "util.h"
#include "kernel.h"
Juliusz Chroboczek committed
38
#include "interface.h"
Juliusz Chroboczek committed
39 40
#include "neighbour.h"
#include "message.h"
Juliusz Chroboczek committed
41
#include "route.h"
Juliusz Chroboczek committed
42
#include "configuration.h"
Juliusz Chroboczek committed
43
#include "local.h"
Matthieu Boutier committed
44
#include "xroute.h"
Juliusz Chroboczek committed
45
#include "hmac.h"
Juliusz Chroboczek committed
46

Matthieu Boutier committed
47
struct interface *interfaces = NULL;
Juliusz Chroboczek committed
48

Matthieu Boutier committed
49 50
static struct interface *
last_interface(void)
Juliusz Chroboczek committed
51
{
Matthieu Boutier committed
52
    struct interface *ifp = interfaces;
Juliusz Chroboczek committed
53

Matthieu Boutier committed
54
    if(!ifp)
Juliusz Chroboczek committed
55 56
        return NULL;

Matthieu Boutier committed
57 58
    while(ifp->next)
        ifp = ifp->next;
Juliusz Chroboczek committed
59

Matthieu Boutier committed
60
    return ifp;
Juliusz Chroboczek committed
61
}
Juliusz Chroboczek committed
62

Matthieu Boutier committed
63 64
struct interface *
add_interface(char *ifname, struct interface_conf *if_conf)
Juliusz Chroboczek committed
65
{
Matthieu Boutier committed
66
    struct interface *ifp;
Juliusz Chroboczek committed
67

Matthieu Boutier committed
68 69
    FOR_ALL_INTERFACES(ifp) {
        if(strcmp(ifp->name, ifname) == 0) {
Juliusz Chroboczek committed
70 71
            if(if_conf)
                fprintf(stderr,
Christof Schulze committed
72 73
                        "Warning: attempting to add existing interface (%s), "
                        "new configuration ignored.\n", ifname);
Matthieu Boutier committed
74
            return ifp;
Juliusz Chroboczek committed
75
        }
Juliusz Chroboczek committed
76 77
    }

Juliusz Chroboczek committed
78
    ifp = calloc(1, sizeof(struct interface));
Matthieu Boutier committed
79
    if(ifp == NULL)
Juliusz Chroboczek committed
80
        return NULL;
Juliusz Chroboczek committed
81

Matthieu Boutier committed
82
    strncpy(ifp->name, ifname, IF_NAMESIZE);
Juliusz Chroboczek committed
83
    ifp->conf = if_conf ? if_conf : default_interface_conf;
Matthieu Boutier committed
84
    ifp->hello_seqno = (random() & 0xFFFF);
Juliusz Chroboczek committed
85

Matthieu Boutier committed
86 87
    if(interfaces == NULL)
        interfaces = ifp;
Juliusz Chroboczek committed
88
    else
Matthieu Boutier committed
89
        last_interface()->next = ifp;
Juliusz Chroboczek committed
90

Juliusz Chroboczek committed
91 92
    local_notify_interface(ifp, LOCAL_ADD);

Matthieu Boutier committed
93
    return ifp;
Juliusz Chroboczek committed
94 95
}

Juliusz Chroboczek committed
96
int
Juliusz Chroboczek committed
97 98 99 100 101 102 103 104 105 106 107 108 109
flush_interface(char *ifname)
{
    struct interface *ifp, *prev;

    prev = NULL;
    ifp = interfaces;
    while(ifp) {
        if(strcmp(ifp->name, ifname) == 0)
            break;
        prev = ifp;
        ifp = ifp->next;
    }

Juliusz Chroboczek committed
110 111 112
    if(ifp == NULL)
        return 0;

Juliusz Chroboczek committed
113 114 115 116 117 118 119 120
    interface_up(ifp, 0);
    if(prev)
        prev->next = ifp->next;
    else
        interfaces = ifp->next;

    if(ifp->conf != NULL && ifp->conf != default_interface_conf)
        flush_ifconf(ifp->conf);
Juliusz Chroboczek committed
121 122 123

    local_notify_interface(ifp, LOCAL_FLUSH);

Juliusz Chroboczek committed
124
    free(ifp);
Juliusz Chroboczek committed
125 126

    return 1;
Juliusz Chroboczek committed
127 128
}

Juliusz Chroboczek committed
129 130
/* This should be no more than half the hello interval, so that hellos
   aren't sent late.  The result is in milliseconds. */
Juliusz Chroboczek committed
131
unsigned
Juliusz Chroboczek committed
132
jitter(struct buffered *buf, int urgent)
Juliusz Chroboczek committed
133
{
Juliusz Chroboczek committed
134
    unsigned interval = buf->flush_interval;
Juliusz Chroboczek committed
135
    if(urgent)
Juliusz Chroboczek committed
136
        interval = MIN(interval, 20);
Juliusz Chroboczek committed
137
    else
Juliusz Chroboczek committed
138 139
        interval = MIN(interval, 2000);
    return roughly(interval / 2);
Juliusz Chroboczek committed
140 141
}

Juliusz Chroboczek committed
142
unsigned
Matthieu Boutier committed
143
update_jitter(struct interface *ifp, int urgent)
Juliusz Chroboczek committed
144
{
Matthieu Boutier committed
145
    unsigned interval = ifp->hello_interval;
Juliusz Chroboczek committed
146 147
    if(urgent)
        interval = MIN(interval, 100);
Juliusz Chroboczek committed
148 149
    else
        interval = MIN(interval, 4000);
Juliusz Chroboczek committed
150
    return roughly(interval);
Juliusz Chroboczek committed
151
}
Juliusz Chroboczek committed
152

Juliusz Chroboczek committed
153
void
Juliusz Chroboczek committed
154
set_timeout(struct timeval *timeout, int msecs)
Juliusz Chroboczek committed
155
{
Juliusz Chroboczek committed
156
    timeval_add_msec(timeout, &now, roughly(msecs));
Juliusz Chroboczek committed
157 158
}

Juliusz Chroboczek committed
159
static int
Matthieu Boutier committed
160
check_interface_ipv4(struct interface *ifp)
Juliusz Chroboczek committed
161 162 163 164
{
    unsigned char ipv4[4];
    int rc;

Matthieu Boutier committed
165 166
    if(ifp->ifindex > 0)
        rc = kernel_interface_ipv4(ifp->name, ifp->ifindex, ipv4);
Juliusz Chroboczek committed
167 168 169 170
    else
        rc = 0;

    if(rc > 0) {
Matthieu Boutier committed
171 172 173 174 175 176 177
        if(!ifp->ipv4 || memcmp(ipv4, ifp->ipv4, 4) != 0) {
            debugf("Noticed IPv4 change for %s.\n", ifp->name);
            flush_interface_routes(ifp, 0);
            if(!ifp->ipv4)
                ifp->ipv4 = malloc(4);
            if(ifp->ipv4)
                memcpy(ifp->ipv4, ipv4, 4);
Juliusz Chroboczek committed
178
            local_notify_interface(ifp, LOCAL_CHANGE);
Juliusz Chroboczek committed
179 180 181
            return 1;
        }
    } else {
Matthieu Boutier committed
182 183 184 185 186
        if(ifp->ipv4) {
            debugf("Noticed IPv4 change for %s.\n", ifp->name);
            flush_interface_routes(ifp, 0);
            free(ifp->ipv4);
            ifp->ipv4 = NULL;
Juliusz Chroboczek committed
187
            local_notify_interface(ifp, LOCAL_CHANGE);
Juliusz Chroboczek committed
188 189 190 191 192 193
            return 1;
        }
    }
    return 0;
}

Matthieu Boutier committed
194
static int
Matthieu Boutier committed
195
check_interface_channel(struct interface *ifp)
Juliusz Chroboczek committed
196
{
Matthieu Boutier committed
197
    int channel = IF_CONF(ifp, channel);
Juliusz Chroboczek committed
198
    int rc = 1;
Juliusz Chroboczek committed
199

Matthieu Boutier committed
200
    if(channel == IF_CHANNEL_UNKNOWN) {
Juliusz Chroboczek committed
201 202 203 204 205 206 207 208
        /* IF_WIRELESS merely means that we know for sure that the
           interface is wireless, so check unconditionally. */
        channel = kernel_interface_channel(ifp->name, ifp->ifindex);
        if(channel < 0) {
            if((ifp->flags & IF_WIRELESS))
                rc = -1;
            channel = (ifp->flags & IF_WIRELESS) ?
                IF_CHANNEL_INTERFERING : IF_CHANNEL_NONINTERFERING;
Juliusz Chroboczek committed
209 210 211
        }
    }

Matthieu Boutier committed
212 213
    if(ifp->channel != channel) {
        ifp->channel = channel;
Juliusz Chroboczek committed
214
        return rc;
Juliusz Chroboczek committed
215 216 217 218
    }
    return 0;
}

Matthieu Boutier committed
219 220 221 222 223
static int
check_link_local_addresses(struct interface *ifp)
{
    struct kernel_route ll[32];
    int rc, i;
Juliusz Chroboczek committed
224

Matthieu Boutier committed
225
    rc = kernel_addresses(ifp->ifindex, 1, ll, 32);
Juliusz Chroboczek committed
226 227 228 229 230 231 232 233 234 235 236 237
    if(rc <= 0) {
        if(rc < 0)
            perror("kernel_addresses(link local)");
        else
            fprintf(stderr, "Interface %s has no link-local address.\n",
                    ifp->name);
        if(ifp->ll) {
            free(ifp->ll);
            ifp->numll = 0;
            ifp->ll = NULL;
        }
        local_notify_interface(ifp, LOCAL_CHANGE);
Matthieu Boutier committed
238 239 240 241 242
        /* Most probably DAD hasn't finished yet.  Reschedule us
           real soon. */
        schedule_interfaces_check(2000, 0);
        return -1;
    } else {
Juliusz Chroboczek committed
243 244 245 246 247 248 249 250 251
        int changed;
        if(rc == ifp->numll) {
            changed = 0;
            for(i = 0; i < rc; i++) {
                if(memcmp(ifp->ll[i], ll[i].prefix, 16) != 0) {
                    changed = 1;
                    break;
                }
            }
Matthieu Boutier committed
252
        } else {
Juliusz Chroboczek committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
            changed = 1;
        }

        if(changed) {
            free(ifp->ll);
            ifp->numll = 0;
            ifp->ll = malloc(16 * rc);
            if(ifp->ll == NULL) {
                perror("malloc(ll)");
            } else {
                for(i = 0; i < rc; i++)
                    memcpy(ifp->ll[i], ll[i].prefix, 16);
                ifp->numll = rc;
            }
            local_notify_interface(ifp, LOCAL_CHANGE);
Matthieu Boutier committed
268 269 270 271 272 273
        }
    }

    return 0;
}

Juliusz Chroboczek committed
274
int
Matthieu Boutier committed
275
interface_up(struct interface *ifp, int up)
Juliusz Chroboczek committed
276
{
Juliusz Chroboczek committed
277
    int mtu, rc, type;
Juliusz Chroboczek committed
278
    struct ipv6_mreq mreq;
Juliusz Chroboczek committed
279

Matthieu Boutier committed
280
    if((!!up) == if_up(ifp))
Juliusz Chroboczek committed
281 282
        return 0;

Juliusz Chroboczek committed
283
    if(up)
Matthieu Boutier committed
284
        ifp->flags |= IF_UP;
Juliusz Chroboczek committed
285
    else
Matthieu Boutier committed
286
        ifp->flags &= ~IF_UP;
Juliusz Chroboczek committed
287

Juliusz Chroboczek committed
288
    if(up) {
Matthieu Boutier committed
289
        if(ifp->ifindex <= 0) {
Juliusz Chroboczek committed
290
            fprintf(stderr,
Matthieu Boutier committed
291
                    "Upping unknown interface %s.\n", ifp->name);
Juliusz Chroboczek committed
292
            goto fail;
Juliusz Chroboczek committed
293 294
        }

Matthieu Boutier committed
295
        rc = kernel_setup_interface(1, ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
296
        if(rc < 0) {
Antonin Décimo committed
297
            fprintf(stderr, "kernel_setup_interface(%s, %u) failed.\n",
Matthieu Boutier committed
298
                    ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
299
            goto fail;
Juliusz Chroboczek committed
300 301
        }

Juliusz Chroboczek committed
302 303 304 305 306 307
        memset(&ifp->buf.sin6, 0, sizeof(ifp->buf.sin6));
        ifp->buf.sin6.sin6_family = AF_INET6;
        memcpy(&ifp->buf.sin6.sin6_addr, protocol_group, 16);
        ifp->buf.sin6.sin6_port = htons(protocol_port);
        ifp->buf.sin6.sin6_scope_id = ifp->ifindex;

Matthieu Boutier committed
308
        mtu = kernel_interface_mtu(ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
309
        if(mtu < 0) {
Antonin Décimo committed
310
            fprintf(stderr, "Warning: couldn't get MTU of interface %s (%u).\n",
Matthieu Boutier committed
311
                    ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
312 313
            mtu = 1280;
        }
Juliusz Chroboczek committed
314 315 316 317 318 319

        /* We need to be able to fit at least two messages into a packet,
           so MTUs below 116 require lower layer fragmentation. */
        /* In IPv6, the minimum MTU is 1280, and every host must be able
           to reassemble up to 1500 bytes, but I'd rather not rely on this. */
        if(mtu < 128) {
Antonin Décimo committed
320
            fprintf(stderr, "Suspiciously low MTU %d on interface %s (%u).\n",
Matthieu Boutier committed
321
                    mtu, ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
322 323 324
            mtu = 128;
        }

Juliusz Chroboczek committed
325 326
        if(ifp->buf.buf)
            free(ifp->buf.buf);
Juliusz Chroboczek committed
327 328

        /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
Juliusz Chroboczek committed
329 330 331
        ifp->buf.size = mtu - sizeof(packet_header) - 60;
        ifp->buf.buf = malloc(ifp->buf.size);
        if(ifp->buf.buf == NULL) {
Juliusz Chroboczek committed
332
            fprintf(stderr, "Couldn't allocate sendbuf.\n");
Juliusz Chroboczek committed
333
            ifp->buf.size = 0;
Juliusz Chroboczek committed
334
            goto fail;
Juliusz Chroboczek committed
335
        }
Juliusz Chroboczek committed
336

Juliusz Chroboczek committed
337 338 339
        rc = resize_receive_buffer(mtu);
        if(rc < 0)
            fprintf(stderr, "Warning: couldn't resize "
Antonin Décimo committed
340
                    "receive buffer for interface %s (%u) (%d bytes).\n",
Juliusz Chroboczek committed
341
                    ifp->name, ifp->ifindex, mtu);
Juliusz Chroboczek committed
342

Juliusz Chroboczek committed
343 344 345 346
        type = IF_CONF(ifp, type);
        if(type == IF_TYPE_DEFAULT) {
            if(all_wireless) {
                type = IF_TYPE_WIRELESS;
Juliusz Chroboczek committed
347
            } else {
Juliusz Chroboczek committed
348 349 350
                rc = kernel_interface_wireless(ifp->name, ifp->ifindex);
                if(rc < 0) {
                    fprintf(stderr,
Antonin Décimo committed
351
                            "Warning: couldn't determine whether %s (%u) "
Juliusz Chroboczek committed
352 353 354 355 356
                            "is a wireless interface.\n",
                            ifp->name, ifp->ifindex);
                } else if(rc) {
                    type = IF_TYPE_WIRELESS;
                }
Juliusz Chroboczek committed
357 358 359
            }
        }

Juliusz Chroboczek committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
        /* Type is CONFIG_TYPE_AUTO if interface is not known to be
           wireless, so provide sane defaults for that case. */

        if(type == IF_TYPE_WIRELESS)
            ifp->flags |= IF_WIRELESS;
        else
            ifp->flags &= ~IF_WIRELESS;

        ifp->cost = IF_CONF(ifp, cost);
        if(ifp->cost <= 0)
            ifp->cost = type == IF_TYPE_WIRELESS ? 256 : 96;

        if(IF_CONF(ifp, split_horizon) == CONFIG_YES)
            ifp->flags |= IF_SPLIT_HORIZON;
        else if(IF_CONF(ifp, split_horizon) == CONFIG_NO)
            ifp->flags &= ~IF_SPLIT_HORIZON;
        else if(type == IF_TYPE_WIRED)
            ifp->flags |= IF_SPLIT_HORIZON;
        else
            ifp->flags &= ~IF_SPLIT_HORIZON;

        if(IF_CONF(ifp, lq) == CONFIG_YES)
            ifp->flags |= IF_LQ;
        else if(IF_CONF(ifp, lq) == CONFIG_NO)
            ifp->flags &= ~IF_LQ;
        else if(type == IF_TYPE_WIRELESS)
            ifp->flags |= IF_LQ;
        else
            ifp->flags &= ~IF_LQ;
Juliusz Chroboczek committed
389

Matthieu Boutier committed
390 391
        if(IF_CONF(ifp, faraway) == CONFIG_YES)
            ifp->flags |= IF_FARAWAY;
Juliusz Chroboczek committed
392

Juliusz Chroboczek committed
393 394 395
        if(IF_CONF(ifp, unicast) == CONFIG_YES)
            ifp->flags |= IF_UNICAST;

Juliusz Chroboczek committed
396 397
        if(IF_CONF(ifp, hello_interval) > 0)
            ifp->hello_interval = IF_CONF(ifp, hello_interval);
Juliusz Chroboczek committed
398
        else if(type == IF_TYPE_WIRELESS)
Juliusz Chroboczek committed
399
            ifp->hello_interval = default_wireless_hello_interval;
Juliusz Chroboczek committed
400 401
        else
            ifp->hello_interval = default_wired_hello_interval;
Juliusz Chroboczek committed
402

Matthieu Boutier committed
403 404 405
        ifp->update_interval =
            IF_CONF(ifp, update_interval) > 0 ?
            IF_CONF(ifp, update_interval) :
Matthieu Boutier committed
406
            ifp->hello_interval * 4;
Juliusz Chroboczek committed
407

Juliusz Chroboczek committed
408 409 410 411
        /* This must be no more than half the Hello interval, or else
           Hellos will arrive late. */
        ifp->buf.flush_interval = ifp->hello_interval / 2;

Juliusz Chroboczek committed
412 413 414
        ifp->rtt_decay =
            IF_CONF(ifp, rtt_decay) > 0 ?
            IF_CONF(ifp, rtt_decay) : 42;
Baptiste Jonglez committed
415 416 417 418 419 420 421 422 423

        ifp->rtt_min =
            IF_CONF(ifp, rtt_min) > 0 ?
            IF_CONF(ifp, rtt_min) : 10000;
        ifp->rtt_max =
            IF_CONF(ifp, rtt_max) > 0 ?
            IF_CONF(ifp, rtt_max) : 120000;
        if(ifp->rtt_max <= ifp->rtt_min) {
            fprintf(stderr,
Antonin Décimo committed
424 425
                    "Uh, rtt-max is less than or equal to rtt-min (%u <= %u). "
                    "Setting it to %u.\n", ifp->rtt_max, ifp->rtt_min,
Baptiste Jonglez committed
426 427 428 429
                    ifp->rtt_min + 10000);
            ifp->rtt_max = ifp->rtt_min + 10000;
        }
        ifp->max_rtt_penalty = IF_CONF(ifp, max_rtt_penalty);
Juliusz Chroboczek committed
430 431
        if(ifp->max_rtt_penalty == 0 && type == IF_TYPE_TUNNEL)
            ifp->max_rtt_penalty = 96;
Baptiste Jonglez committed
432

Juliusz Chroboczek committed
433
        if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES)
Juliusz Chroboczek committed
434
            ifp->flags |= IF_TIMESTAMPS;
Juliusz Chroboczek committed
435
        else if(IF_CONF(ifp, enable_timestamps) == CONFIG_NO)
Juliusz Chroboczek committed
436
            ifp->flags &= ~IF_TIMESTAMPS;
Juliusz Chroboczek committed
437
        else if(type == IF_TYPE_TUNNEL)
Juliusz Chroboczek committed
438
            ifp->flags |= IF_TIMESTAMPS;
Juliusz Chroboczek committed
439
        else
Juliusz Chroboczek committed
440 441
            ifp->flags &= ~IF_TIMESTAMPS;
        if(ifp->max_rtt_penalty > 0 && !(ifp->flags & IF_TIMESTAMPS))
Juliusz Chroboczek committed
442 443 444 445
            fprintf(stderr,
                    "Warning: max_rtt_penalty is set "
                    "but timestamps are disabled on interface %s.\n",
                    ifp->name);
Juliusz Chroboczek committed
446

Juliusz Chroboczek committed
447 448 449 450
        if(IF_CONF(ifp, rfc6126) == CONFIG_YES)
            ifp->flags |= IF_RFC6126;
        else
            ifp->flags &= ~IF_RFC6126;
Juliusz Chroboczek committed
451

Matthieu Boutier committed
452 453 454 455
        rc = check_link_local_addresses(ifp);
        if(rc < 0) {
            goto fail;
        }
Juliusz Chroboczek committed
456 457 458
        memset(&mreq, 0, sizeof(mreq));
        memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
        mreq.ipv6mr_interface = ifp->ifindex;
Juliusz Chroboczek committed
459 460 461 462 463 464 465
        rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                        (char*)&mreq, sizeof(mreq));
        if(rc < 0) {
            perror("setsockopt(IPV6_JOIN_GROUP)");
            goto fail;
        }

Juliusz Chroboczek committed
466 467 468 469 470
        rc = check_interface_channel(ifp);
        if(rc < 0)
            fprintf(stderr,
                    "Warning: couldn't determine channel of interface %s.\n",
                    ifp->name);
Juliusz Chroboczek committed
471 472 473
        update_interface_metric(ifp);
        rc = check_interface_ipv4(ifp);

Juliusz Chroboczek committed
474 475 476 477 478 479 480 481 482
        if(IF_CONF(ifp, key) != ifp->key) {
            if(ifp->key != NULL)
                release_key(ifp->key);
            if(IF_CONF(ifp, key) != NULL)
                ifp->key = retain_key(IF_CONF(ifp, key));
            else
                ifp->key = NULL;
        }

Juliusz Chroboczek committed
483
        debugf("Upped interface %s (cost=%d, channel=%d%s).\n",
Juliusz Chroboczek committed
484 485 486 487 488
               ifp->name,
               ifp->cost,
               ifp->channel,
               ifp->ipv4 ? ", IPv4" : "");

Matthieu Boutier committed
489 490 491
        set_timeout(&ifp->hello_timeout, ifp->hello_interval);
        set_timeout(&ifp->update_timeout, ifp->update_interval);
        send_hello(ifp);
Juliusz Chroboczek committed
492
        if(rc > 0)
Matthieu Boutier committed
493
            send_update(ifp, 0, NULL, 0, NULL, 0);
Juliusz Chroboczek committed
494
        send_multicast_request(ifp, NULL, 0, NULL, 0);
Juliusz Chroboczek committed
495
    } else {
Matthieu Boutier committed
496
        flush_interface_routes(ifp, 0);
Juliusz Chroboczek committed
497 498 499
        ifp->buf.len = 0;
        ifp->buf.size = 0;
        free(ifp->buf.buf);
Matthieu Boutier committed
500 501 502 503 504
        ifp->num_buffered_updates = 0;
        ifp->update_bufsize = 0;
        if(ifp->buffered_updates)
            free(ifp->buffered_updates);
        ifp->buffered_updates = NULL;
Juliusz Chroboczek committed
505
        ifp->buf.buf = NULL;
Matthieu Boutier committed
506
        if(ifp->ifindex > 0) {
Juliusz Chroboczek committed
507 508
            memset(&mreq, 0, sizeof(mreq));
            memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
Matthieu Boutier committed
509
            mreq.ipv6mr_interface = ifp->ifindex;
Juliusz Chroboczek committed
510 511
            rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
                            (char*)&mreq, sizeof(mreq));
Juliusz Chroboczek committed
512
            if(rc < 0)
Juliusz Chroboczek committed
513
                perror("setsockopt(IPV6_LEAVE_GROUP)");
Matthieu Boutier committed
514
            kernel_setup_interface(0, ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
515
        }
Matthieu Boutier committed
516 517 518 519
        if(ifp->ll)
            free(ifp->ll);
        ifp->ll = NULL;
        ifp->numll = 0;
Juliusz Chroboczek committed
520 521
    }

Juliusz Chroboczek committed
522 523
    local_notify_interface(ifp, LOCAL_CHANGE);

Juliusz Chroboczek committed
524
    return 1;
Juliusz Chroboczek committed
525 526 527 528

 fail:
    assert(up);
    interface_up(ifp, 0);
Juliusz Chroboczek committed
529
    local_notify_interface(ifp, LOCAL_CHANGE);
Juliusz Chroboczek committed
530
    return -1;
Juliusz Chroboczek committed
531 532
}

Juliusz Chroboczek committed
533
int
Matthieu Boutier committed
534
interface_ll_address(struct interface *ifp, const unsigned char *address)
Juliusz Chroboczek committed
535 536 537
{
    int i;

Matthieu Boutier committed
538
    if(!if_up(ifp))
Juliusz Chroboczek committed
539 540
        return 0;

Matthieu Boutier committed
541 542
    for(i = 0; i < ifp->numll; i++)
        if(memcmp(ifp->ll[i], address, 16) == 0)
Matthieu Boutier committed
543
            return 1;
Juliusz Chroboczek committed
544 545 546 547

    return 0;
}

Juliusz Chroboczek committed
548
void
Matthieu Boutier committed
549
check_interfaces(void)
Juliusz Chroboczek committed
550
{
Matthieu Boutier committed
551
    struct interface *ifp;
Matthieu Boutier committed
552 553
    int rc, ifindex_changed = 0;
    unsigned int ifindex;
Juliusz Chroboczek committed
554

Matthieu Boutier committed
555 556 557 558 559 560 561
    FOR_ALL_INTERFACES(ifp) {
        ifindex = if_nametoindex(ifp->name);
        if(ifindex != ifp->ifindex) {
            debugf("Noticed ifindex change for %s.\n", ifp->name);
            ifp->ifindex = 0;
            interface_up(ifp, 0);
            ifp->ifindex = ifindex;
Juliusz Chroboczek committed
562 563 564
            ifindex_changed = 1;
        }

Matthieu Boutier committed
565 566
        if(ifp->ifindex > 0)
            rc = kernel_interface_operational(ifp->name, ifp->ifindex);
Juliusz Chroboczek committed
567 568
        else
            rc = 0;
Matthieu Boutier committed
569 570 571
        if((rc > 0) != if_up(ifp)) {
            debugf("Noticed status change for %s.\n", ifp->name);
            interface_up(ifp, rc > 0);
Juliusz Chroboczek committed
572
        }
Juliusz Chroboczek committed
573

Juliusz Chroboczek committed
574
        if(if_up(ifp)) {
Juliusz Chroboczek committed
575
            /* Bother, said Pooh.  We should probably check for a change
Matthieu Boutier committed
576 577
               in IPv4 addresses at this point. */
            check_link_local_addresses(ifp);
Juliusz Chroboczek committed
578 579 580
            check_interface_channel(ifp);
            rc = check_interface_ipv4(ifp);
            if(rc > 0) {
Juliusz Chroboczek committed
581
                send_multicast_request(ifp, NULL, 0, NULL, 0);
Matthieu Boutier committed
582
                send_update(ifp, 0, NULL, 0, NULL, 0);
Juliusz Chroboczek committed
583 584
            }
        }
Juliusz Chroboczek committed
585
    }
Juliusz Chroboczek committed
586 587 588

    if(ifindex_changed)
        renumber_filters();
Juliusz Chroboczek committed
589
}