OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [in6_ifattach.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/in6_ifattach.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: in6_ifattach.c,v 1.149 2001/12/07 07:07:09 itojun Exp $  */
23
 
24
/*
25
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
#include <sys/param.h>
54
#include <sys/malloc.h>
55
#include <sys/socket.h>
56
#include <sys/sockio.h>
57
#ifdef __bsdi__
58
#include <crypto/md5.h>
59
#elif defined(__OpenBSD__)
60
#include <sys/md5k.h>
61
#else
62
#include <sys/md5.h>
63
#endif
64
 
65
#ifdef __OpenBSD__
66
#include <dev/rndvar.h>
67
#endif
68
 
69
#include <net/if.h>
70
#include <net/if_dl.h>
71
#include <net/if_types.h>
72
#include <net/route.h>
73
 
74
#include <netinet/in.h>
75
#include <netinet/in_var.h>
76
#ifndef __NetBSD__
77
#include <netinet/if_ether.h>
78
#endif
79
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
80
#include <netinet/in_pcb.h>
81
#endif
82
 
83
#include <netinet/ip6.h>
84
#include <netinet6/ip6_var.h>
85
#include <netinet6/in6_var.h>
86
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
87
#include <netinet6/in6_pcb.h>
88
#endif
89
#include <netinet6/in6_ifattach.h>
90
#include <netinet6/ip6_var.h>
91
#include <netinet6/nd6.h>
92
#include <netinet6/scope6_var.h>
93
 
94
struct in6_ifstat **in6_ifstat = NULL;
95
struct icmp6_ifstat **icmp6_ifstat = NULL;
96
size_t in6_ifstatmax = 0;
97
size_t icmp6_ifstatmax = 0;
98
unsigned long in6_maxmtu = 0;
99
 
100
#ifdef IP6_AUTO_LINKLOCAL
101
int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
102
#else
103
int ip6_auto_linklocal = 1;     /* enable by default */
104
#endif
105
 
106
#ifdef __NetBSD__
107
struct callout in6_tmpaddrtimer_ch = CALLOUT_INITIALIZER;
108
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)
109
struct callout in6_tmpaddrtimer_ch;
110
#elif defined(__OpenBSD__)
111
struct timeout in6_tmpaddrtimer_ch;
112
#endif
113
 
114
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
115
extern struct inpcbinfo udbinfo;
116
extern struct inpcbinfo ripcbinfo;
117
#endif
118
 
119
#if defined(__NetBSD__) || defined(__OpenBSD__)
120
static int get_hostid_ifid __P((struct ifnet *, struct in6_addr *));
121
#endif
122
static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
123
static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *));
124
static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
125
#ifndef MIP6
126
static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
127
#endif /* !MIP6 */
128
static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
129
static int in6_ifattach_loopback __P((struct ifnet *));
130
 
131
#define EUI64_GBIT      0x01
132
#define EUI64_UBIT      0x02
133
#define EUI64_TO_IFID(in6)      do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
134
#define EUI64_GROUP(in6)        ((in6)->s6_addr[8] & EUI64_GBIT)
135
#define EUI64_INDIVIDUAL(in6)   (!EUI64_GROUP(in6))
136
#define EUI64_LOCAL(in6)        ((in6)->s6_addr[8] & EUI64_UBIT)
137
#define EUI64_UNIVERSAL(in6)    (!EUI64_LOCAL(in6))
138
 
139
#define IFID_LOCAL(in6)         (!EUI64_LOCAL(in6))
140
#define IFID_UNIVERSAL(in6)     (!EUI64_UNIVERSAL(in6))
141
 
142
#define GEN_TEMPID_RETRY_MAX 5
143
 
144
#if defined(__NetBSD__) || defined(__OpenBSD__)
145
/*
146
 * Generate a last-resort interface identifier from hostid.
147
 * works only for certain architectures (like sparc).
148
 * also, using hostid itself may constitute a privacy threat, much worse
149
 * than MAC addresses (hostids are used for software licensing).
150
 * maybe we should use MD5(hostid) instead.
151
 */
152
static int
153
get_hostid_ifid(ifp, in6)
154
        struct ifnet *ifp;
155
        struct in6_addr *in6;   /* upper 64bits are preserved */
156
{
157
        int off, len;
158
        static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
159
        static u_int8_t allone[8] =
160
                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
161
 
162
        if (!hostid)
163
                return -1;
164
 
165
        /* get up to 8 bytes from the hostid field - should we get */
166
        len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid);
167
        off = sizeof(*in6) - len;
168
        bcopy(&hostid, &in6->s6_addr[off], len);
169
 
170
        /* make sure we do not return anything bogus */
171
        if (bcmp(&in6->s6_addr[8], allzero, sizeof(allzero)))
172
                return -1;
173
        if (bcmp(&in6->s6_addr[8], allone, sizeof(allone)))
174
                return -1;
175
 
176
        /* make sure to set "u" bit to local, and "g" bit to individual. */
177
        in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
178
        in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
179
 
180
        /* convert EUI64 into IPv6 interface identifier */
181
        EUI64_TO_IFID(in6);
182
 
183
        return 0;
184
}
185
#endif
186
 
187
/*
188
 * Generate a last-resort interface identifier, when the machine has no
189
 * IEEE802/EUI64 address sources.
190
 * The goal here is to get an interface identifier that is
191
 * (1) random enough and (2) does not change across reboot.
192
 * We currently use MD5(hostname) for it.
193
 */
194
static int
195
get_rand_ifid(ifp, in6)
196
        struct ifnet *ifp;
197
        struct in6_addr *in6;   /* upper 64bits are preserved */
198
{
199
        MD5_CTX ctxt;
200
        u_int8_t digest[16];
201
#ifdef __FreeBSD__
202
        int hostnamelen = strlen(hostname);
203
#endif
204
 
205
#if 0
206
        /* we need at least several letters as seed for ifid */
207
        if (hostnamelen < 3)
208
                return -1;
209
#endif
210
 
211
        /* generate 8 bytes of pseudo-random value. */
212
        bzero(&ctxt, sizeof(ctxt));
213
        MD5Init(&ctxt);
214
        MD5Update(&ctxt, hostname, hostnamelen);
215
        MD5Final(digest, &ctxt);
216
 
217
        /* assumes sizeof(digest) > sizeof(ifid) */
218
        bcopy(digest, &in6->s6_addr[8], 8);
219
 
220
        /* make sure to set "u" bit to local, and "g" bit to individual. */
221
        in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
222
        in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
223
 
224
        /* convert EUI64 into IPv6 interface identifier */
225
        EUI64_TO_IFID(in6);
226
 
227
        return 0;
228
}
229
 
230
static int
231
generate_tmp_ifid(seed0, seed1, ret)
232
        u_int8_t *seed0, *ret;
233
        const u_int8_t *seed1;
234
{
235
        MD5_CTX ctxt;
236
        u_int8_t seed[16], digest[16], nullbuf[8];
237
        u_int32_t val32;
238
#ifndef __OpenBSD__
239
        struct timeval tv;
240
#endif
241
        /*
242
         * interface ID for subnet anycast addresses.
243
         * XXX: we assume the unicast address range that requires IDs
244
         * in EUI-64 format.
245
         */
246
        const u_int8_t anycast_id[8] = {0xfd, 0xff, 0xff, 0xff,
247
                                        0xff, 0xff, 0xff, 0x80};
248
        const u_int8_t isatap_id[4] = {0x00, 0x00, 0x5e, 0xfe};
249
        int badid, retry = 0;
250
 
251
        /* If there's no hisotry, start with a random seed. */
252
        bzero(nullbuf, sizeof(nullbuf));
253
        if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
254
                int i;
255
 
256
                for (i = 0; i < 2; i++) {
257
#ifndef __OpenBSD__
258
                        microtime(&tv);
259
                        val32 = random() ^ tv.tv_usec;
260
#else
261
                        val32 = arc4random();
262
#endif
263
                        bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
264
                }
265
        } else {
266
                bcopy(seed0, seed, 8);
267
        }
268
 
269
        /* copy the right-most 64-bits of the given address */
270
        /* XXX assumption on the size of IFID */
271
        bcopy(seed1, &seed[8], 8);
272
 
273
  again:
274
        if (0) {         /* for debugging purposes only */
275
                int i;
276
 
277
                printf("generate_tmp_ifid: new randomized ID from: ");
278
                for (i = 0; i < 16; i++)
279
                        printf("%02x", seed[i]);
280
                printf(" ");
281
        }
282
 
283
        /* generate 16 bytes of pseudo-random value. */
284
        bzero(&ctxt, sizeof(ctxt));
285
        MD5Init(&ctxt);
286
        MD5Update(&ctxt, seed, sizeof(seed));
287
        MD5Final(digest, &ctxt);
288
 
289
        /*
290
         * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (3)
291
         * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
292
         * left-most bit is numbered 0) to zero.
293
         */
294
        bcopy(digest, ret, 8);
295
        ret[0] &= ~EUI64_UBIT;
296
 
297
        /*
298
         * Reject inappropriate identifiers according to
299
         * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (4)
300
         * At this moment, we reject following cases:
301
         * - all 0 identifier
302
         * - identifiers that conflict with reserved subnet anycast addresses,
303
         *   which are defined in RFC 2526.
304
         * - identifiers that conflict with ISATAP addresses
305
         * - identifiers used in our own addresses
306
         */
307
        badid = 0;
308
        if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0)
309
                badid = 1;
310
        else if (bcmp(anycast_id, ret, 7) == 0 &&
311
            (anycast_id[7] & ret[7]) == anycast_id[7]) {
312
                badid = 1;
313
        } else if (bcmp(isatap_id, ret, sizeof(isatap_id)) == 0)
314
                badid = 1;
315
        else {
316
                struct in6_ifaddr *ia;
317
 
318
                for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
319
                        if (bcmp(&ia->ia_addr.sin6_addr.s6_addr[8], ret, 8)
320
                                == 0) {
321
                                badid = 1;
322
                                break;
323
                        }
324
                }
325
        }
326
 
327
        /*
328
         * In the event that an unacceptable identifier has been generated,
329
         * restart the process, using the right-most 64 bits of the MD5 digest
330
         * obtained in place of the history value.
331
         */
332
        if (badid) {
333
                if (0) { /* for debugging purposes only */
334
                        int i;
335
 
336
                        printf("unacceptable random ID: ");
337
                        for (i = 0; i < 16; i++)
338
                                printf("%02x", digest[i]);
339
                        printf("\n");
340
                }
341
 
342
                if (++retry < GEN_TEMPID_RETRY_MAX) {
343
                        bcopy(&digest[8], seed, 8);
344
                        goto again;
345
                } else {
346
                        /*
347
                         * We're so unlucky.  Give up for now, and return
348
                         * all 0 IDs to tell the caller not to make a
349
                         * temporary address.
350
                         */
351
                        nd6log((LOG_NOTICE,
352
                                "generate_tmp_ifid: never found a good ID\n"));
353
                        bzero(ret, 8);
354
                }
355
        }
356
 
357
        /*
358
         * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (6)
359
         * Take the rightmost 64-bits of the MD5 digest and save them in
360
         * stable storage as the history value to be used in the next
361
         * iteration of the algorithm.
362
         */
363
        bcopy(&digest[8], seed0, 8);
364
 
365
        if (0) {         /* for debugging purposes only */
366
                int i;
367
 
368
                printf("to: ");
369
                for (i = 0; i < 16; i++)
370
                        printf("%02x", digest[i]);
371
                printf("\n");
372
        }
373
 
374
        return 0;
375
}
376
 
377
/*
378
 * Get interface identifier for the specified interface.
379
 * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
380
 */
381
static int
382
get_hw_ifid(ifp, in6)
383
        struct ifnet *ifp;
384
        struct in6_addr *in6;   /* upper 64bits are preserved */
385
{
386
        struct ifaddr *ifa;
387
        struct sockaddr_dl *sdl;
388
        u_int8_t *addr;
389
        size_t addrlen;
390
        static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
391
        static u_int8_t allone[8] =
392
                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
393
 
394
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
395
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
396
#else
397
        for (ifa = ifp->if_addrlist.tqh_first;
398
             ifa;
399
             ifa = ifa->ifa_list.tqe_next)
400
#endif
401
        {
402
                if (ifa->ifa_addr->sa_family != AF_LINK)
403
                        continue;
404
                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
405
                if (sdl == NULL)
406
                        continue;
407
                if (sdl->sdl_alen == 0)
408
                        continue;
409
 
410
                goto found;
411
        }
412
 
413
        return -1;
414
 
415
found:
416
        addr = LLADDR(sdl);
417
        addrlen = sdl->sdl_alen;
418
 
419
        switch (ifp->if_type) {
420
        case IFT_IEEE1394:
421
#ifdef IFT_IEEE80211
422
        case IFT_IEEE80211:
423
#endif
424
                /* IEEE1394 uses 16byte length address starting with EUI64 */
425
                if (addrlen > 8)
426
                        addrlen = 8;
427
                break;
428
        default:
429
                break;
430
        }
431
 
432
        /* get EUI64 */
433
        switch (ifp->if_type) {
434
        /* IEEE802/EUI64 cases - what others? */
435
        case IFT_ETHER:
436
        case IFT_FDDI:
437
        case IFT_ATM:
438
        case IFT_IEEE1394:
439
#ifdef IFT_IEEE80211
440
        case IFT_IEEE80211:
441
#endif
442
                /* look at IEEE802/EUI64 only */
443
                if (addrlen != 8 && addrlen != 6)
444
                        return -1;
445
 
446
                /*
447
                 * check for invalid MAC address - on bsdi, we see it a lot
448
                 * since wildboar configures all-zero MAC on pccard before
449
                 * card insertion.
450
                 */
451
                if (bcmp(addr, allzero, addrlen) == 0)
452
                        return -1;
453
                if (bcmp(addr, allone, addrlen) == 0)
454
                        return -1;
455
 
456
                /* make EUI64 address */
457
                if (addrlen == 8)
458
                        bcopy(addr, &in6->s6_addr[8], 8);
459
                else if (addrlen == 6) {
460
                        in6->s6_addr[8] = addr[0];
461
                        in6->s6_addr[9] = addr[1];
462
                        in6->s6_addr[10] = addr[2];
463
                        in6->s6_addr[11] = 0xff;
464
                        in6->s6_addr[12] = 0xfe;
465
                        in6->s6_addr[13] = addr[3];
466
                        in6->s6_addr[14] = addr[4];
467
                        in6->s6_addr[15] = addr[5];
468
                }
469
                break;
470
 
471
        case IFT_ARCNET:
472
                if (addrlen != 1)
473
                        return -1;
474
                if (!addr[0])
475
                        return -1;
476
 
477
                bzero(&in6->s6_addr[8], 8);
478
                in6->s6_addr[15] = addr[0];
479
 
480
                /*
481
                 * due to insufficient bitwidth, we mark it local.
482
                 */
483
                in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
484
                in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
485
                break;
486
 
487
        case IFT_GIF:
488
#ifdef IFT_STF
489
        case IFT_STF:
490
#endif
491
                /*
492
                 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
493
                 * however, IPv4 address is not very suitable as unique
494
                 * identifier source (can be renumbered).
495
                 * we don't do this.
496
                 */
497
                return -1;
498
 
499
        default:
500
                return -1;
501
        }
502
 
503
        /* sanity check: g bit must not indicate "group" */
504
        if (EUI64_GROUP(in6))
505
                return -1;
506
 
507
        /* convert EUI64 into IPv6 interface identifier */
508
        EUI64_TO_IFID(in6);
509
 
510
        /*
511
         * sanity check: ifid must not be all zero, avoid conflict with
512
         * subnet router anycast
513
         */
514
        if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
515
            bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
516
                return -1;
517
        }
518
 
519
        return 0;
520
}
521
 
522
/*
523
 * Get interface identifier for the specified interface.  If it is not
524
 * available on ifp0, borrow interface identifier from other information
525
 * sources.
526
 */
527
#ifdef MIP6
528
int
529
#else /* MIP6 */
530
static int
531
#endif /* MIP6 */
532
get_ifid(ifp0, altifp, in6)
533
        struct ifnet *ifp0;
534
        struct ifnet *altifp;   /* secondary EUI64 source */
535
        struct in6_addr *in6;
536
{
537
        struct ifnet *ifp;
538
 
539
        /* first, try to get it from the interface itself */
540
        if (get_hw_ifid(ifp0, in6) == 0) {
541
                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
542
                    if_name(ifp0)));
543
                goto success;
544
        }
545
 
546
        /* try secondary EUI64 source. this basically is for ATM PVC */
547
        if (altifp && get_hw_ifid(altifp, in6) == 0) {
548
                nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
549
                    if_name(ifp0), if_name(altifp)));
550
                goto success;
551
        }
552
 
553
        /* next, try to get it from some other hardware interface */
554
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
555
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
556
#else
557
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
558
#endif
559
        {
560
                if (ifp == ifp0)
561
                        continue;
562
                if (get_hw_ifid(ifp, in6) != 0)
563
                        continue;
564
 
565
                /*
566
                 * to borrow ifid from other interface, ifid needs to be
567
                 * globally unique
568
                 */
569
                if (IFID_UNIVERSAL(in6)) {
570
                        nd6log((LOG_DEBUG,
571
                            "%s: borrow interface identifier from %s\n",
572
                            if_name(ifp0), if_name(ifp)));
573
                        goto success;
574
                }
575
        }
576
 
577
#if defined(__NetBSD__) || defined(__OpenBSD__)
578
        /* get from hostid - only for certain architectures */
579
        if (0 && get_hostid_ifid(ifp, in6) == 0) {
580
                nd6log((LOG_DEBUG,
581
                    "%s: interface identifier generated by hostid\n",
582
                    if_name(ifp0)));
583
                goto success;
584
        }
585
#endif
586
 
587
        /* last resort: get from random number source */
588
        if (get_rand_ifid(ifp, in6) == 0) {
589
                nd6log((LOG_DEBUG,
590
                    "%s: interface identifier generated by random number\n",
591
                    if_name(ifp0)));
592
                goto success;
593
        }
594
 
595
        printf("%s: failed to get interface identifier\n", if_name(ifp0));
596
        return -1;
597
 
598
success:
599
        nd6log((LOG_INFO, "%s: ifid: "
600
                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
601
                if_name(ifp0),
602
                in6->s6_addr[8], in6->s6_addr[9],
603
                in6->s6_addr[10], in6->s6_addr[11],
604
                in6->s6_addr[12], in6->s6_addr[13],
605
                in6->s6_addr[14], in6->s6_addr[15]));
606
        return 0;
607
}
608
 
609
static int
610
in6_ifattach_linklocal(ifp, altifp)
611
        struct ifnet *ifp;
612
        struct ifnet *altifp;   /* secondary EUI64 source */
613
{
614
        struct in6_ifaddr *ia;
615
        struct in6_aliasreq ifra;
616
        struct nd_prefix pr0;
617
        int i, error;
618
#ifdef SCOPEDROUTING
619
        int64_t zoneid;
620
#endif
621
 
622
        /*
623
         * configure link-local address.
624
         */
625
        bzero(&ifra, sizeof(ifra));
626
 
627
        /*
628
         * in6_update_ifa() does not use ifra_name, but we accurately set it
629
         * for safety.
630
         */
631
        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
632
 
633
        ifra.ifra_addr.sin6_family = AF_INET6;
634
        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
635
        ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
636
#ifdef SCOPEDROUTING
637
        ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
638
#else
639
        ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */
640
#endif
641
        ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
642
        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
643
                ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
644
                ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
645
        } else {
646
                if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
647
                        nd6log((LOG_ERR,
648
                            "%s: no ifid available\n", if_name(ifp)));
649
                        return(-1);
650
                }
651
        }
652
#ifdef SCOPEDROUTING
653
        if ((zoneid = in6_addr2zoneid(ifp, &ifra.ifra_addr.sin6_addr)) < 0)
654
                return(-1);
655
        ifra.ifra_addr.sin6_scope_id = zoneid;
656
#endif
657
 
658
        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
659
        ifra.ifra_prefixmask.sin6_family = AF_INET6;
660
        ifra.ifra_prefixmask.sin6_addr = in6mask64;
661
#ifdef SCOPEDROUTING
662
        /* take into account the sin6_scope_id field for routing */
663
        ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
664
#endif
665
        /* link-local addresses should NEVER expire. */
666
        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
667
        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
668
 
669
        /*
670
         * Do not let in6_update_ifa() do DAD, since we need a random delay
671
         * before sending an NS at the first time the interface becomes up.
672
         * Instead, in6_if_up() will start DAD with a proper random delay.
673
         */
674
        ifra.ifra_flags |= IN6_IFF_NODAD;
675
 
676
        /*
677
         * Now call in6_update_ifa() to do a bunch of procedures to configure
678
         * a link-local address. We can set NULL to the 3rd argument, because
679
         * we know there's no other link-local address on the interface
680
         * and therefore we are adding one (instead of updating one).
681
         */
682
        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
683
                /*
684
                 * XXX: When the interface does not support IPv6, this call
685
                 * would fail in the SIOCSIFADDR ioctl.  I believe the
686
                 * notification is rather confusing in this case, so just
687
                 * suppress it.  (jinmei@kame.net 20010130)
688
                 */
689
                if (error != EAFNOSUPPORT)
690
                        log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
691
                            "configure a link-local address on %s "
692
                            "(errno=%d)\n",
693
                            if_name(ifp), error);
694
                return(-1);
695
        }
696
 
697
        /*
698
         * Adjust ia6_flags so that in6_if_up will perform DAD.
699
         * XXX: Some P2P interfaces seem not to send packets just after
700
         * becoming up, so we skip p2p interfaces for safety.
701
         */
702
        ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
703
#ifdef DIAGNOSTIC
704
        if (!ia) {
705
                panic("ia == NULL in in6_ifattach_linklocal");
706
                /* NOTREACHED */
707
        }
708
#endif
709
        if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
710
                ia->ia6_flags &= ~IN6_IFF_NODAD;
711
                ia->ia6_flags |= IN6_IFF_TENTATIVE;
712
        }
713
 
714
        /*
715
         * Make the link-local prefix (fe80::/64%link) as on-link.
716
         * Since we'd like to manage prefixes separately from addresses,
717
         * we make an ND6 prefix structure for the link-local prefix,
718
         * and add it to the prefix list as a never-expire prefix.
719
         * XXX: this change might affect some existing code base...
720
         */
721
        bzero(&pr0, sizeof(pr0));
722
        pr0.ndpr_ifp = ifp;
723
        /* this should be 64 at this moment. */
724
        pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
725
        pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
726
        pr0.ndpr_prefix = ifra.ifra_addr;
727
        /* apply the mask for safety. (nd6_prelist_add will apply it again) */
728
        for (i = 0; i < 4; i++) {
729
                pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
730
                        in6mask64.s6_addr32[i];
731
        }
732
        /*
733
         * Initialize parameters.  The link-local prefix must always be
734
         * on-link, and its lifetimes never expire.
735
         */
736
        pr0.ndpr_raf_onlink = 1;
737
        pr0.ndpr_raf_auto = 1;  /* probably meaningless */
738
        pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
739
        pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
740
        /*
741
         * Since there is no other link-local addresses, nd6_prefix_lookup()
742
         * probably returns NULL.  However, we cannot always expect the result.
743
         * For example, if we first remove the (only) existing link-local
744
         * address, and then reconfigure another one, the prefix is still
745
         * valid with referring to the old link-local address.
746
         */
747
        if (nd6_prefix_lookup(&pr0) == NULL) {
748
                if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
749
                        return(error);
750
        }
751
 
752
        log_(LOG_ADDR) {
753
            diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
754
            _show_ifp(ifp);
755
        }
756
        return 0;
757
}
758
 
759
static int
760
in6_ifattach_loopback(ifp)
761
        struct ifnet *ifp;      /* must be IFT_LOOP */
762
{
763
        struct in6_aliasreq ifra;
764
        int error;
765
 
766
        bzero(&ifra, sizeof(ifra));
767
 
768
        /*
769
         * in6_update_ifa() does not use ifra_name, but we accurately set it
770
         * for safety.
771
         */
772
        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
773
 
774
        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
775
        ifra.ifra_prefixmask.sin6_family = AF_INET6;
776
        ifra.ifra_prefixmask.sin6_addr = in6mask128;
777
 
778
        /*
779
         * Always initialize ia_dstaddr (= broadcast address) to loopback
780
         * address.  Follows IPv4 practice - see in_ifinit().
781
         */
782
        ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
783
        ifra.ifra_dstaddr.sin6_family = AF_INET6;
784
        ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
785
 
786
        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
787
        ifra.ifra_addr.sin6_family = AF_INET6;
788
        ifra.ifra_addr.sin6_addr = in6addr_loopback;
789
 
790
        /* the loopback  address should NEVER expire. */
791
        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
792
        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
793
 
794
        /* we don't need to perform DAD on loopback interfaces. */
795
        ifra.ifra_flags |= IN6_IFF_NODAD;
796
 
797
        /*
798
         * We are sure that this is a newly assigned address, so we can set
799
         * NULL to the 3rd arg.
800
         */
801
        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
802
                log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
803
                    "the loopback address on %s (errno=%d)\n",
804
                    if_name(ifp), error);
805
                return(-1);
806
        }
807
 
808
        return 0;
809
}
810
 
811
/*
812
 * compute NI group address, based on the current hostname setting.
813
 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
814
 *
815
 * when ifp == NULL, the caller is responsible for filling scopeid.
816
 */
817
int
818
in6_nigroup(ifp, name, namelen, in6)
819
        struct ifnet *ifp;
820
        const char *name;
821
        int namelen;
822
        struct in6_addr *in6;
823
{
824
        const char *p;
825
        u_char *q;
826
        MD5_CTX ctxt;
827
        u_int8_t digest[16];
828
        char l;
829
        char n[64];     /* a single label must not exceed 63 chars */
830
 
831
        if (!namelen || !name)
832
                return -1;
833
 
834
        p = name;
835
        while (p && *p && *p != '.' && p - name < namelen)
836
                p++;
837
        if (p - name > sizeof(n) - 1)
838
                return -1;      /* label too long */
839
        l = p - name;
840
        strncpy(n, name, l);
841
        n[(int)l] = '\0';
842
        for (q = n; *q; q++) {
843
                if ('A' <= *q && *q <= 'Z')
844
                        *q = *q - 'A' + 'a';
845
        }
846
 
847
        /* generate 8 bytes of pseudo-random value. */
848
        bzero(&ctxt, sizeof(ctxt));
849
        MD5Init(&ctxt);
850
        MD5Update(&ctxt, &l, sizeof(l));
851
        MD5Update(&ctxt, n, l);
852
        MD5Final(digest, &ctxt);
853
 
854
        bzero(in6, sizeof(*in6));
855
        in6->s6_addr16[0] = htons(0xff02);
856
        if (ifp)
857
                in6->s6_addr16[1] = htons(ifp->if_index);
858
        in6->s6_addr8[11] = 2;
859
        bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
860
 
861
        return 0;
862
}
863
 
864
#if 0
865
void
866
in6_nigroup_attach(name, namelen)
867
        const char *name;
868
        int namelen;
869
{
870
        struct ifnet *ifp;
871
        struct sockaddr_in6 mltaddr;
872
        struct in6_multi *in6m;
873
        int error;
874
 
875
        bzero(&mltaddr, sizeof(mltaddr));
876
        mltaddr.sin6_family = AF_INET6;
877
        mltaddr.sin6_len = sizeof(struct sockaddr_in6);
878
        if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
879
                return;
880
 
881
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
882
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
883
#else
884
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
885
#endif
886
        {
887
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
888
                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
889
                if (!in6m) {
890
                        if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
891
                                nd6log((LOG_ERR, "%s: failed to join %s "
892
                                    "(errno=%d)\n", if_name(ifp),
893
                                    ip6_sprintf(&mltaddr.sin6_addr),
894
                                    error));
895
                        }
896
                }
897
        }
898
}
899
 
900
void
901
in6_nigroup_detach(name, namelen)
902
        const char *name;
903
        int namelen;
904
{
905
        struct ifnet *ifp;
906
        struct sockaddr_in6 mltaddr;
907
        struct in6_multi *in6m;
908
 
909
        bzero(&mltaddr, sizeof(mltaddr));
910
        mltaddr.sin6_family = AF_INET6;
911
        mltaddr.sin6_len = sizeof(struct sockaddr_in6);
912
        if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
913
                return;
914
 
915
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
916
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
917
#else
918
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
919
#endif
920
        {
921
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
922
                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
923
                if (in6m)
924
                        in6_delmulti(in6m);
925
        }
926
}
927
#endif
928
 
929
/*
930
 * XXX multiple loopback interface needs more care.  for instance,
931
 * nodelocal address needs to be configured onto only one of them.
932
 * XXX multiple link-local address case
933
 */
934
void
935
in6_ifattach(ifp, altifp)
936
        struct ifnet *ifp;
937
        struct ifnet *altifp;   /* secondary EUI64 source */
938
{
939
        static size_t if_indexlim = 8;
940
        struct in6_ifaddr *ia;
941
        struct in6_addr in6;
942
 
943
        /* some of the interfaces are inherently not IPv6 capable */
944
        switch (ifp->if_type) {
945
#ifdef IFT_BRIDGE       /* OpenBSD 2.8 */
946
        case IFT_BRIDGE:
947
                return;
948
#endif
949
#if defined(__OpenBSD__) || defined(__NetBSD__)
950
        case IFT_PROPVIRTUAL:
951
                if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
952
                    '0' <= ifp->if_xname[sizeof("bridge")] &&
953
                    ifp->if_xname[sizeof("bridge")] <= '9')
954
                        return;
955
                break;
956
#endif
957
#ifdef IFT_PFLOG
958
        case IFT_PFLOG:
959
                return;
960
#endif
961
        }
962
 
963
        /*
964
         * We have some arrays that should be indexed by if_index.
965
         * since if_index will grow dynamically, they should grow too.
966
         *      struct in6_ifstat **in6_ifstat
967
         *      struct icmp6_ifstat **icmp6_ifstat
968
         */
969
        if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
970
            if_index >= if_indexlim) {
971
                size_t n;
972
                caddr_t q;
973
                size_t olim;
974
 
975
                olim = if_indexlim;
976
                while (if_index >= if_indexlim)
977
                        if_indexlim <<= 1;
978
 
979
                /* grow in6_ifstat */
980
                n = if_indexlim * sizeof(struct in6_ifstat *);
981
                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
982
                bzero(q, n);
983
                if (in6_ifstat) {
984
                        bcopy((caddr_t)in6_ifstat, q,
985
                                olim * sizeof(struct in6_ifstat *));
986
                        free((caddr_t)in6_ifstat, M_IFADDR);
987
                }
988
                in6_ifstat = (struct in6_ifstat **)q;
989
                in6_ifstatmax = if_indexlim;
990
 
991
                /* grow icmp6_ifstat */
992
                n = if_indexlim * sizeof(struct icmp6_ifstat *);
993
                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
994
                bzero(q, n);
995
                if (icmp6_ifstat) {
996
                        bcopy((caddr_t)icmp6_ifstat, q,
997
                                olim * sizeof(struct icmp6_ifstat *));
998
                        free((caddr_t)icmp6_ifstat, M_IFADDR);
999
                }
1000
                icmp6_ifstat = (struct icmp6_ifstat **)q;
1001
                icmp6_ifstatmax = if_indexlim;
1002
        }
1003
 
1004
        /* initialize scope identifiers */
1005
        scope6_ifattach(ifp);
1006
 
1007
        /* initialize NDP variables */
1008
        nd6_ifattach(ifp);
1009
 
1010
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1011
        /* create a multicast kludge storage (if we have not had one) */
1012
        in6_createmkludge(ifp);
1013
#endif
1014
 
1015
        /*
1016
         * quirks based on interface type
1017
         */
1018
        switch (ifp->if_type) {
1019
#ifdef IFT_STF
1020
        case IFT_STF:
1021
                /*
1022
                 * 6to4 interface is a very special kind of beast.
1023
                 * no multicast, no linklocal.  RFC2529 specifies how to make
1024
                 * linklocals for 6to4 interface, but there's no use and
1025
                 * it is rather harmful to have one.
1026
                 */
1027
                goto statinit;
1028
#endif
1029
        default:
1030
                break;
1031
        }
1032
 
1033
        /*
1034
         * usually, we require multicast capability to the interface
1035
         */
1036
        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1037
                log(LOG_INFO, "in6_ifattach: "
1038
                    "%s is not multicast capable, IPv6 not enabled\n",
1039
                    if_name(ifp));
1040
                return;
1041
        }
1042
 
1043
        /*
1044
         * assign loopback address for loopback interface.
1045
         * XXX multiple loopback interface case.
1046
         */
1047
        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
1048
                in6 = in6addr_loopback;
1049
                if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
1050
                        if (in6_ifattach_loopback(ifp) != 0)
1051
                                return;
1052
                }
1053
        }
1054
 
1055
        /*
1056
         * assign a link-local address, if there's none.
1057
         */
1058
        if (ip6_auto_linklocal) {
1059
            int s = splnet();
1060
                ia = in6ifa_ifpforlinklocal(ifp, 0);
1061
                if (ia == NULL) {
1062
                        if (in6_ifattach_linklocal(ifp, altifp) == 0) {
1063
                                /* linklocal address assigned */
1064
                        } else {
1065
                                /* failed to assign linklocal address. bark? */
1066
                        }
1067
                }
1068
                splx(s);
1069
        }
1070
 
1071
#ifdef IFT_STF                  /* XXX */
1072
statinit:
1073
#endif
1074
 
1075
        /* update dynamically. */
1076
        if (in6_maxmtu < ifp->if_mtu)
1077
                in6_maxmtu = ifp->if_mtu;
1078
 
1079
        if (in6_ifstat[ifp->if_index] == NULL) {
1080
                in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
1081
                        malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
1082
                bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
1083
        }
1084
        if (icmp6_ifstat[ifp->if_index] == NULL) {
1085
                icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
1086
                        malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
1087
                bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
1088
        }
1089
}
1090
 
1091
/*
1092
 * NOTE: in6_ifdetach() does not support loopback if at this moment.
1093
 * We don't need this function in bsdi, because interfaces are never removed
1094
 * from the ifnet list in bsdi.
1095
 */
1096
#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802)
1097
void
1098
in6_ifdetach(ifp)
1099
        struct ifnet *ifp;
1100
{
1101
        struct in6_ifaddr *ia, *oia;
1102
        struct ifaddr *ifa, *next;
1103
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1104
        struct ifaddr *ifaprev = NULL;
1105
#endif
1106
        struct rtentry *rt;
1107
        short rtflags;
1108
        struct sockaddr_in6 sin6;
1109
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1110
        struct in6_multi *in6m, *in6m_next;
1111
#endif
1112
        struct in6_multi_mship *imm;
1113
 
1114
        /* remove neighbor management table */
1115
        nd6_purge(ifp);
1116
 
1117
        /* nuke any of IPv6 addresses we have */
1118
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1119
        for (ifa = ifp->if_addrlist; ifa; ifa = next)
1120
#else
1121
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
1122
#endif
1123
        {
1124
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1125
                next = ifa->ifa_next;
1126
#else
1127
                next = ifa->ifa_list.tqe_next;
1128
#endif
1129
                if (ifa->ifa_addr->sa_family != AF_INET6)
1130
                        continue;
1131
                in6_purgeaddr(ifa);
1132
        }
1133
 
1134
        /* undo everything done by in6_ifattach(), just in case */
1135
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1136
        for (ifa = ifp->if_addrlist; ifa; ifa = next)
1137
#else
1138
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
1139
#endif
1140
        {
1141
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1142
                next = ifa->ifa_next;
1143
#else
1144
                next = ifa->ifa_list.tqe_next;
1145
#endif
1146
 
1147
 
1148
                if (ifa->ifa_addr->sa_family != AF_INET6
1149
                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
1150
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1151
                        ifaprev = ifa;
1152
#endif
1153
                        continue;
1154
                }
1155
 
1156
                ia = (struct in6_ifaddr *)ifa;
1157
 
1158
                /*
1159
                 * leave from multicast groups we have joined for the interface
1160
                 */
1161
                while ((imm = ia->ia6_memberships.lh_first) != NULL) {
1162
                        LIST_REMOVE(imm, i6mm_chain);
1163
                        in6_leavegroup(imm);
1164
                }
1165
 
1166
                /* remove from the routing table */
1167
                if ((ia->ia_flags & IFA_ROUTE)
1168
                 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0
1169
#ifdef __FreeBSD__
1170
                                , 0UL
1171
#endif
1172
                                ))) {
1173
                        rtflags = rt->rt_flags;
1174
                        rtfree(rt);
1175
                        rtrequest(RTM_DELETE,
1176
                                (struct sockaddr *)&ia->ia_addr,
1177
                                (struct sockaddr *)&ia->ia_addr,
1178
                                (struct sockaddr *)&ia->ia_prefixmask,
1179
                                rtflags, (struct rtentry **)0);
1180
                }
1181
 
1182
                /* remove from the linked list */
1183
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1184
                if (ifaprev)
1185
                        ifaprev->ifa_next = ifa->ifa_next;
1186
                else
1187
                        ifp->if_addrlist = ifa->ifa_next;
1188
#else
1189
                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1190
#endif
1191
                IFAFREE(&ia->ia_ifa);
1192
 
1193
                /* also remove from the IPv6 address chain(itojun&jinmei) */
1194
                oia = ia;
1195
                if (oia == (ia = in6_ifaddr))
1196
                        in6_ifaddr = ia->ia_next;
1197
                else {
1198
                        while (ia->ia_next && (ia->ia_next != oia))
1199
                                ia = ia->ia_next;
1200
                        if (ia->ia_next)
1201
                                ia->ia_next = oia->ia_next;
1202
                        else {
1203
                                nd6log((LOG_ERR,
1204
                                    "%s: didn't unlink in6ifaddr from "
1205
                                    "list\n", if_name(ifp)));
1206
                        }
1207
                }
1208
 
1209
                IFAFREE(&oia->ia_ifa);
1210
        }
1211
 
1212
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1213
        /* leave from all multicast groups joined */
1214
 
1215
#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
1216
        in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
1217
        in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
1218
#endif
1219
 
1220
        for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
1221
                in6m_next = LIST_NEXT(in6m, in6m_entry);
1222
                if (in6m->in6m_ifp != ifp)
1223
                        continue;
1224
                in6_delmulti(in6m);
1225
                in6m = NULL;
1226
        }
1227
#endif
1228
 
1229
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1230
        /* cleanup multicast address kludge table, if there is any */
1231
        in6_purgemkludge(ifp);
1232
#endif
1233
 
1234
        /*
1235
         * remove neighbor management table.  we call it twice just to make
1236
         * sure we nuke everything.  maybe we need just one call.
1237
         * XXX: since the first call did not release addresses, some prefixes
1238
         * might remain.  We should call nd6_purge() again to release the
1239
         * prefixes after removing all addresses above.
1240
         * (Or can we just delay calling nd6_purge until at this point?)
1241
         */
1242
        nd6_purge(ifp);
1243
 
1244
        /* remove route to link-local allnodes multicast (ff02::1) */
1245
        bzero(&sin6, sizeof(sin6));
1246
        sin6.sin6_len = sizeof(struct sockaddr_in6);
1247
        sin6.sin6_family = AF_INET6;
1248
        sin6.sin6_addr = in6addr_linklocal_allnodes;
1249
        sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1250
#ifndef __FreeBSD__
1251
        rt = rtalloc1((struct sockaddr *)&sin6, 0);
1252
#else
1253
        rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
1254
#endif
1255
        if (rt && rt->rt_ifp == ifp) {
1256
                rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1257
                        rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1258
                rtfree(rt);
1259
        }
1260
}
1261
#endif
1262
 
1263
int
1264
in6_get_tmpifid(ifp, retbuf, baseid, generate)
1265
        struct ifnet *ifp;
1266
        u_int8_t *retbuf;
1267
        const u_int8_t *baseid;
1268
        int generate;
1269
{
1270
        u_int8_t nullbuf[8];
1271
        struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
1272
 
1273
        bzero(nullbuf, sizeof(nullbuf));
1274
        if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
1275
                /* we've never created a random ID.  Create a new one. */
1276
                generate = 1;
1277
        }
1278
 
1279
        if (generate) {
1280
                bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
1281
 
1282
                /* generate_tmp_ifid will update seedn and buf */
1283
                (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
1284
                                        ndi->randomid);
1285
        }
1286
        bcopy(ndi->randomid, retbuf, 8);
1287
        if (generate && bcmp(retbuf, nullbuf, sizeof(nullbuf)) == 0) {
1288
                /* generate_tmp_ifid could not found a good ID. */
1289
                return(-1);
1290
        }
1291
 
1292
        return(0);
1293
}
1294
 
1295
void
1296
in6_tmpaddrtimer(ignored_arg)
1297
        void *ignored_arg;
1298
{
1299
        int i;
1300
        struct nd_ifinfo *ndi;
1301
        u_int8_t nullbuf[8];
1302
#ifdef __NetBSD__
1303
        int s = splsoftnet();
1304
#else
1305
        int s = splnet();
1306
#endif
1307
 
1308
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1309
        callout_reset(&in6_tmpaddrtimer_ch,
1310
                      (ip6_temp_preferred_lifetime - ip6_desync_factor -
1311
                       ip6_temp_regen_advance) * hz,
1312
                      in6_tmpaddrtimer, NULL);
1313
#elif defined(__OpenBSD__)
1314
        timeout_set(&in6_tmpaddrtimer_ch, in6_tmpaddrtimer, NULL);
1315
        timeout_add(&in6_tmpaddrtimer_ch,
1316
            (ip6_temp_preferred_lifetime - ip6_desync_factor -
1317
            ip6_temp_regen_advance) * hz);
1318
#else
1319
        timeout(in6_tmpaddrtimer, (caddr_t)0,
1320
                (ip6_temp_preferred_lifetime - ip6_desync_factor -
1321
                 ip6_temp_regen_advance) * hz);
1322
#endif
1323
 
1324
        bzero(nullbuf, sizeof(nullbuf));
1325
        for (i = 1; i < if_index + 1; i++) {
1326
                ndi = &nd_ifinfo[i];
1327
                if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
1328
                        /*
1329
                         * We've been generating a random ID on this interface.
1330
                         * Create a new one.
1331
                         */
1332
                        (void)generate_tmp_ifid(ndi->randomseed0,
1333
                                                ndi->randomseed1,
1334
                                                ndi->randomid);
1335
                }
1336
        }
1337
 
1338
        splx(s);
1339
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.