OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [in6.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.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.c,v 1.256 2001/12/24 10:39:29 jinmei 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
/*
54
 * Copyright (c) 1982, 1986, 1991, 1993
55
 *      The Regents of the University of California.  All rights reserved.
56
 *
57
 * Redistribution and use in source and binary forms, with or without
58
 * modification, are permitted provided that the following conditions
59
 * are met:
60
 * 1. Redistributions of source code must retain the above copyright
61
 *    notice, this list of conditions and the following disclaimer.
62
 * 2. Redistributions in binary form must reproduce the above copyright
63
 *    notice, this list of conditions and the following disclaimer in the
64
 *    documentation and/or other materials provided with the distribution.
65
 * 3. All advertising materials mentioning features or use of this software
66
 *    must display the following acknowledgement:
67
 *      This product includes software developed by the University of
68
 *      California, Berkeley and its contributors.
69
 * 4. Neither the name of the University nor the names of its contributors
70
 *    may be used to endorse or promote products derived from this software
71
 *    without specific prior written permission.
72
 *
73
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
74
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
77
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
78
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
79
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83
 * SUCH DAMAGE.
84
 *
85
 *      @(#)in.c        8.2 (Berkeley) 11/15/93
86
 */
87
 
88
#include <sys/param.h>
89
#include <sys/errno.h>
90
#include <sys/malloc.h>
91
#include <sys/socket.h>
92
#include <sys/socketvar.h>
93
#include <sys/sockio.h>
94
 
95
#include <net/if.h>
96
#include <net/if_types.h>
97
#include <net/route.h>
98
#include <net/if_dl.h>
99
 
100
#include <netinet/in.h>
101
#include <netinet/in_var.h>
102
#ifdef __NetBSD__
103
#include <net/if_ether.h>
104
#else
105
#include <netinet/if_ether.h>
106
#endif
107
#ifndef SCOPEDROUTING
108
#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
109
#include <netinet/in_systm.h>
110
#include <netinet/ip.h>
111
#include <netinet/in_pcb.h>
112
#endif
113
#endif
114
 
115
#include <netinet/ip6.h>
116
#include <netinet6/ip6_var.h>
117
#include <netinet6/nd6.h>
118
#include <netinet6/mld6_var.h>
119
#include <netinet6/ip6_mroute.h>
120
#include <netinet6/in6_ifattach.h>
121
#include <netinet6/scope6_var.h>
122
#ifndef SCOPEDROUTING
123
#if defined(__NetBSD__) || (defined(__bsdi__) && _BSDI_VERSION < 199802) || defined(__FreeBSD__)
124
#include <netinet6/in6_pcb.h>
125
#endif
126
#endif
127
 
128
#ifdef MIP6
129
#include <netinet6/mip6.h>
130
#endif /* MIP6 */
131
 
132
/*
133
 * Definitions of some costant IP6 addresses.
134
 */
135
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
136
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
137
const struct in6_addr in6addr_nodelocal_allnodes =
138
        IN6ADDR_NODELOCAL_ALLNODES_INIT;
139
const struct in6_addr in6addr_linklocal_allnodes =
140
        IN6ADDR_LINKLOCAL_ALLNODES_INIT;
141
const struct in6_addr in6addr_linklocal_allrouters =
142
        IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
143
 
144
const struct in6_addr in6mask0 = IN6MASK0;
145
const struct in6_addr in6mask32 = IN6MASK32;
146
const struct in6_addr in6mask64 = IN6MASK64;
147
const struct in6_addr in6mask96 = IN6MASK96;
148
const struct in6_addr in6mask128 = IN6MASK128;
149
 
150
const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
151
                                     0, 0, IN6ADDR_ANY_INIT, 0};
152
 
153
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
154
static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
155
        struct ifnet *, struct proc *));
156
#else
157
static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
158
        struct ifnet *));
159
#endif
160
static int in6_ifinit __P((struct ifnet *, struct in6_ifaddr *,
161
                           struct sockaddr_in6 *, int));
162
static void in6_unlink_ifa __P((struct in6_ifaddr *, struct ifnet *));
163
 
164
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
165
struct in6_multihead in6_multihead;     /* XXX BSS initialization */
166
#else
167
/*
168
 * This structure is used to keep track of in6_multi chains which belong to
169
 * deleted interface addresses.
170
 */
171
static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */
172
 
173
struct multi6_kludge {
174
        LIST_ENTRY(multi6_kludge) mk_entry;
175
        struct ifnet *mk_ifp;
176
        struct in6_multihead mk_head;
177
};
178
#endif
179
 
180
#ifdef MEASURE_PERFORMANCE
181
static void in6h_delifa __P((struct in6_ifaddr *));
182
static void in6h_addhash __P((struct in6hash *));
183
static void in6h_delhash __P((struct in6hash *));
184
#endif
185
 
186
/*
187
 * Subroutine for in6_ifaddloop() and in6_ifremloop().
188
 * This routine does actual work.
189
 */
190
static void
191
in6_ifloop_request(int cmd, struct ifaddr *ifa)
192
{
193
        struct sockaddr_in6 all1_sa;
194
        struct rtentry *nrt = NULL;
195
        int e;
196
 
197
        bzero(&all1_sa, sizeof(all1_sa));
198
        all1_sa.sin6_family = AF_INET6;
199
        all1_sa.sin6_len = sizeof(struct sockaddr_in6);
200
        all1_sa.sin6_addr = in6mask128;
201
 
202
        /*
203
         * We specify the address itself as the gateway, and set the
204
         * RTF_LLINFO flag, so that the corresponding host route would have
205
         * the flag, and thus applications that assume traditional behavior
206
         * would be happy.  Note that we assume the caller of the function
207
         * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
208
         * which changes the outgoing interface to the loopback interface.
209
         */
210
        e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
211
                      (struct sockaddr *)&all1_sa,
212
                      RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
213
        if (e != 0) {
214
                log(LOG_ERR, "in6_ifloop_request: "
215
                    "%s operation failed for %s (errno=%d)\n",
216
                    cmd == RTM_ADD ? "ADD" : "DELETE",
217
                    ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
218
                    e);
219
        }
220
 
221
        /*
222
         * Make sure rt_ifa be equal to IFA, the second argument of the
223
         * function.
224
         * We need this because when we refer to rt_ifa->ia6_flags in
225
         * ip6_input, we assume that the rt_ifa points to the address instead
226
         * of the loopback address.
227
         */
228
        if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
229
                IFAFREE(nrt->rt_ifa);
230
                IFAREF(ifa);
231
                nrt->rt_ifa = ifa;
232
        }
233
 
234
        /*
235
         * Report the addition/removal of the address to the routing socket.
236
         * XXX: since we called rtinit for a p2p interface with a destination,
237
         *      we end up reporting twice in such a case.  Should we rather
238
         *      omit the second report?
239
         */
240
        if (nrt) {
241
                rt_newaddrmsg(cmd, ifa, e, nrt);
242
                if (cmd == RTM_DELETE) {
243
                        if (nrt->rt_refcnt <= 0) {
244
                                /* XXX: we should free the entry ourselves. */
245
                                nrt->rt_refcnt++;
246
                                rtfree(nrt);
247
                        }
248
                } else {
249
                        /* the cmd must be RTM_ADD here */
250
                        nrt->rt_refcnt--;
251
                }
252
        }
253
}
254
 
255
/*
256
 * Add ownaddr as loopback rtentry.  We previously add the route only if
257
 * necessary (ex. on a p2p link).  However, since we now manage addresses
258
 * separately from prefixes, we should always add the route.  We can't
259
 * rely on the cloning mechanism from the corresponding interface route
260
 * any more.
261
 */
262
static void
263
in6_ifaddloop(struct ifaddr *ifa)
264
{
265
        struct rtentry *rt;
266
 
267
        /* If there is no loopback entry, allocate one. */
268
        rt = rtalloc1(ifa->ifa_addr, 0
269
#ifdef __FreeBSD__
270
                      , 0
271
#endif /* __FreeBSD__ */
272
                );
273
        if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
274
            (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
275
                in6_ifloop_request(RTM_ADD, ifa);
276
        if (rt)
277
                rt->rt_refcnt--;
278
}
279
 
280
/*
281
 * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
282
 * if it exists.
283
 */
284
static void
285
in6_ifremloop(struct ifaddr *ifa)
286
{
287
        struct in6_ifaddr *ia;
288
        struct rtentry *rt;
289
        int ia_count = 0;
290
 
291
        /*
292
         * Some of BSD variants do not remove cloned routes
293
         * from an interface direct route, when removing the direct route
294
         * (see comments in net/net_osdep.h).  Even for variants that do remove
295
         * cloned routes, they could fail to remove the cloned routes when
296
         * we handle multple addresses that share a common prefix.
297
         * So, we should remove the route corresponding to the deleted address
298
         * regardless of the result of in6_is_ifloop_auto().
299
         */
300
 
301
        /*
302
         * Delete the entry only if exact one ifa exists.  More than one ifa
303
         * can exist if we assign a same single address to multiple
304
         * (probably p2p) interfaces.
305
         * XXX: we should avoid such a configuration in IPv6...
306
         */
307
        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
308
                if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) {
309
                        ia_count++;
310
                        if (ia_count > 1)
311
                                break;
312
                }
313
        }
314
 
315
        if (ia_count == 1) {
316
                /*
317
                 * Before deleting, check if a corresponding loopbacked host
318
                 * route surely exists.  With this check, we can avoid to
319
                 * delete an interface direct route whose destination is same
320
                 * as the address being removed.  This can happen when remofing
321
                 * a subnet-router anycast address on an interface attahced
322
                 * to a shared medium.
323
                 */
324
                rt = rtalloc1(ifa->ifa_addr, 0
325
#ifdef __FreeBSD__
326
                              , 0
327
#endif /* __FreeBSD__ */
328
                        );
329
                if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
330
                    (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
331
                        rt->rt_refcnt--;
332
                        in6_ifloop_request(RTM_DELETE, ifa);
333
                }
334
        }
335
}
336
 
337
int
338
in6_ifindex2scopeid(idx)
339
        int idx;
340
{
341
        struct ifnet *ifp;
342
        struct ifaddr *ifa;
343
        struct sockaddr_in6 *sin6;
344
 
345
        if (idx < 0 || if_index < idx)
346
                return -1;
347
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
348
        ifp = ifnet_byindex(idx);
349
#else
350
        ifp = ifindex2ifnet[idx];
351
#endif
352
        if (!ifp)
353
                return -1;
354
 
355
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
356
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
357
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
358
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
359
#else
360
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
361
#endif
362
        {
363
                if (ifa->ifa_addr->sa_family != AF_INET6)
364
                        continue;
365
                sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
366
                if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
367
                        return sin6->sin6_scope_id & 0xffff;
368
        }
369
 
370
        return -1;
371
}
372
 
373
int
374
in6_mask2len(mask, lim0)
375
        struct in6_addr *mask;
376
        u_char *lim0;
377
{
378
        int x = 0, y;
379
        u_char *lim = lim0, *p;
380
 
381
        if (lim0 == NULL ||
382
            lim0 - (u_char *)mask > sizeof(*mask)) /* ignore the scope_id part */
383
                lim = (u_char *)mask + sizeof(*mask);
384
        for (p = (u_char *)mask; p < lim; x++, p++) {
385
                if (*p != 0xff)
386
                        break;
387
        }
388
        y = 0;
389
        if (p < lim) {
390
                for (y = 0; y < 8; y++) {
391
                        if ((*p & (0x80 >> y)) == 0)
392
                                break;
393
                }
394
        }
395
 
396
        /*
397
         * when the limit pointer is given, do a stricter check on the
398
         * remaining bits.
399
         */
400
        if (p < lim) {
401
                if (y != 0 && (*p & (0x00ff >> y)) != 0)
402
                        return(-1);
403
                for (p = p + 1; p < lim; p++)
404
                        if (*p != 0)
405
                                return(-1);
406
        }
407
 
408
        return x * 8 + y;
409
}
410
 
411
#define ifa2ia6(ifa)    ((struct in6_ifaddr *)(ifa))
412
#define ia62ifa(ia6)    (&((ia6)->ia_ifa))
413
 
414
int
415
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
416
in6_control(so, cmd, data, ifp, p)
417
        struct  socket *so;
418
        u_long cmd;
419
        caddr_t data;
420
        struct ifnet *ifp;
421
        struct proc *p;
422
#else
423
in6_control(so, cmd, data, ifp)
424
        struct  socket *so;
425
        u_long cmd;
426
        caddr_t data;
427
        struct ifnet *ifp;
428
#endif
429
{
430
        struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
431
        struct  in6_ifaddr *ia = NULL;
432
        struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
433
        struct sockaddr_in6 *sa6;
434
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
435
        time_t time_second = (time_t)time.tv_sec;
436
#endif
437
 
438
        switch (cmd) {
439
        case SIOCGETSGCNT_IN6:
440
        case SIOCGETMIFCNT_IN6:
441
                return (mrt6_ioctl(cmd, data));
442
        }
443
 
444
        switch(cmd) {
445
        case SIOCAADDRCTL_POLICY:
446
        case SIOCDADDRCTL_POLICY:
447
                return(in6_src_ioctl(cmd, data));
448
        }
449
 
450
#ifdef MIP6
451
        switch (cmd) {
452
        case SIOCENABLEMN:
453
        case SIOCENABLEHA:
454
                return(mip6_ioctl(cmd, data));
455
        case SIOCGBC:
456
                return(mip6_ioctl(cmd, data));
457
        }
458
#endif /* MIP6 */
459
 
460
        if (ifp == NULL)
461
                return(EOPNOTSUPP);
462
 
463
        switch (cmd) {
464
        case SIOCSNDFLUSH_IN6:
465
        case SIOCSPFXFLUSH_IN6:
466
        case SIOCSRTRFLUSH_IN6:
467
        case SIOCSDEFIFACE_IN6:
468
        case SIOCSIFINFO_FLAGS:
469
                /* fall through */
470
        case OSIOCGIFINFO_IN6:
471
        case SIOCGIFINFO_IN6:
472
        case SIOCGDRLST_IN6:
473
        case SIOCGPRLST_IN6:
474
        case SIOCGNBRINFO_IN6:
475
        case SIOCGDEFIFACE_IN6:
476
                return(nd6_ioctl(cmd, data, ifp));
477
        }
478
 
479
        switch (cmd) {
480
        case SIOCSIFPREFIX_IN6:
481
        case SIOCDIFPREFIX_IN6:
482
        case SIOCAIFPREFIX_IN6:
483
        case SIOCCIFPREFIX_IN6:
484
        case SIOCSGIFPREFIX_IN6:
485
        case SIOCGIFPREFIX_IN6:
486
                log(LOG_NOTICE,
487
                    "prefix ioctls are now invalidated. "
488
                    "please use ifconfig.\n");
489
                return(EOPNOTSUPP);
490
        }
491
 
492
        switch (cmd) {
493
        case SIOCSSCOPE6:
494
                return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id));
495
        case SIOCGSCOPE6:
496
                return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id));
497
        case SIOCGSCOPE6DEF:
498
                return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id));
499
        }
500
 
501
        switch (cmd) {
502
        case SIOCALIFADDR:
503
        case SIOCDLIFADDR:
504
                /* fall through */
505
        case SIOCGLIFADDR:
506
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
507
                return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
508
#else
509
                return in6_lifaddr_ioctl(so, cmd, data, ifp);
510
#endif
511
        }
512
 
513
        /*
514
         * Find address for this interface, if it exists.
515
         *
516
         * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
517
         * only, and used the first interface address as the target of other
518
         * operations (without checking ifra_addr).  This was because netinet
519
         * code/API assumed at most 1 interface address per interface.
520
         * Since IPv6 allows a node to assign multiple addresses
521
         * on a single interface, we almost always look and check the
522
         * presence of ifra_addr, and reject invalid ones here.
523
         * It also decreases duplicated code among SIOC*_IN6 operations.
524
         */
525
        switch (cmd) {
526
        case SIOCAIFADDR_IN6:
527
        case SIOCSIFPHYADDR_IN6:
528
                sa6 = &ifra->ifra_addr;
529
                break;
530
        case SIOCSIFADDR_IN6:
531
        case SIOCGIFADDR_IN6:
532
        case SIOCSIFDSTADDR_IN6:
533
        case SIOCSIFNETMASK_IN6:
534
        case SIOCGIFDSTADDR_IN6:
535
        case SIOCGIFNETMASK_IN6:
536
        case SIOCDIFADDR_IN6:
537
        case SIOCGIFPSRCADDR_IN6:
538
        case SIOCGIFPDSTADDR_IN6:
539
        case SIOCGIFAFLAG_IN6:
540
        case SIOCSNDFLUSH_IN6:
541
        case SIOCSPFXFLUSH_IN6:
542
        case SIOCSRTRFLUSH_IN6:
543
        case SIOCGIFALIFETIME_IN6:
544
        case SIOCSIFALIFETIME_IN6:
545
        case SIOCGIFSTAT_IN6:
546
        case SIOCGIFSTAT_ICMP6:
547
                sa6 = &ifr->ifr_addr;
548
                break;
549
        default:
550
                sa6 = NULL;
551
                break;
552
        }
553
        if (sa6 && sa6->sin6_family == AF_INET6) {
554
                if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
555
                        if (sa6->sin6_addr.s6_addr16[1] == 0) {
556
                                /* link ID is not embedded by the user */
557
                                sa6->sin6_addr.s6_addr16[1] =
558
                                        htons(ifp->if_index);
559
                        } else if (sa6->sin6_addr.s6_addr16[1] !=
560
                                    htons(ifp->if_index)) {
561
                                return(EINVAL); /* link ID contradicts */
562
                        }
563
                        if (sa6->sin6_scope_id) {
564
                                if (sa6->sin6_scope_id !=
565
                                    (u_int32_t)ifp->if_index)
566
                                        return(EINVAL);
567
                                sa6->sin6_scope_id = 0; /* XXX: good way? */
568
                        }
569
                }
570
                ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
571
        } else
572
                ia = NULL;
573
 
574
        switch (cmd) {
575
        case SIOCSIFADDR_IN6:
576
        case SIOCSIFDSTADDR_IN6:
577
        case SIOCSIFNETMASK_IN6:
578
                /*
579
                 * Since IPv6 allows a node to assign multiple addresses
580
                 * on a single interface, SIOCSIFxxx ioctls are deprecated.
581
                 */
582
                return(EINVAL);
583
 
584
        case SIOCDIFADDR_IN6:
585
                /*
586
                 * for IPv4, we look for existing in_ifaddr here to allow
587
                 * "ifconfig if0 delete" to remove the first IPv4 address on
588
                 * the interface.  For IPv6, as the spec allows multiple
589
                 * interface address from the day one, we consider "remove the
590
                 * first one" semantics to be not preferable.
591
                 */
592
                if (ia == NULL)
593
                        return(EADDRNOTAVAIL);
594
                /* FALLTHROUGH */
595
        case SIOCAIFADDR_IN6:
596
                /*
597
                 * We always require users to specify a valid IPv6 address for
598
                 * the corresponding operation.
599
                 */
600
                if (ifra->ifra_addr.sin6_family != AF_INET6 ||
601
                    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
602
                        return(EAFNOSUPPORT);
603
 
604
                break;
605
 
606
        case SIOCGIFADDR_IN6:
607
                /* This interface is basically deprecated. use SIOCGIFCONF. */
608
                /* fall through */
609
        case SIOCGIFAFLAG_IN6:
610
        case SIOCGIFNETMASK_IN6:
611
        case SIOCGIFDSTADDR_IN6:
612
        case SIOCGIFALIFETIME_IN6:
613
                /* must think again about its semantics */
614
                if (ia == NULL)
615
                        return(EADDRNOTAVAIL);
616
                break;
617
        case SIOCSIFALIFETIME_IN6:
618
            {
619
                struct in6_addrlifetime *lt;
620
 
621
                if (ia == NULL)
622
                        return(EADDRNOTAVAIL);
623
                /* sanity for overflow - beware unsigned */
624
                lt = &ifr->ifr_ifru.ifru_lifetime;
625
                if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
626
                 && lt->ia6t_vltime + time_second < time_second) {
627
                        return EINVAL;
628
                }
629
                if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
630
                 && lt->ia6t_pltime + time_second < time_second) {
631
                        return EINVAL;
632
                }
633
                break;
634
            }
635
        }
636
 
637
        switch (cmd) {
638
 
639
        case SIOCGIFADDR_IN6:
640
                ifr->ifr_addr = ia->ia_addr;
641
                break;
642
 
643
        case SIOCGIFDSTADDR_IN6:
644
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
645
                        return(EINVAL);
646
                /*
647
                 * XXX: should we check if ifa_dstaddr is NULL and return
648
                 * an error?
649
                 */
650
                ifr->ifr_dstaddr = ia->ia_dstaddr;
651
                break;
652
 
653
        case SIOCGIFNETMASK_IN6:
654
                ifr->ifr_addr = ia->ia_prefixmask;
655
                break;
656
 
657
        case SIOCGIFAFLAG_IN6:
658
                ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
659
                break;
660
 
661
        case SIOCGIFSTAT_IN6:
662
                if (ifp == NULL)
663
                        return EINVAL;
664
                if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax
665
                 || in6_ifstat[ifp->if_index] == NULL) {
666
                        /* return EAFNOSUPPORT? */
667
                        bzero(&ifr->ifr_ifru.ifru_stat,
668
                                sizeof(ifr->ifr_ifru.ifru_stat));
669
                } else
670
                        ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];
671
                break;
672
 
673
        case SIOCGIFSTAT_ICMP6:
674
                if (ifp == NULL)
675
                        return EINVAL;
676
                if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||
677
                    icmp6_ifstat[ifp->if_index] == NULL) {
678
                        /* return EAFNOSUPPORT? */
679
                        bzero(&ifr->ifr_ifru.ifru_stat,
680
                                sizeof(ifr->ifr_ifru.ifru_icmp6stat));
681
                } else
682
                        ifr->ifr_ifru.ifru_icmp6stat =
683
                                *icmp6_ifstat[ifp->if_index];
684
                break;
685
 
686
        case SIOCGIFALIFETIME_IN6:
687
                ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
688
                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
689
                        time_t maxexpire;
690
                        struct in6_addrlifetime *retlt = &ifr->ifr_ifru.ifru_lifetime;
691
 
692
                        /*
693
                         * XXX: adjust expiration time assuming time_t is
694
                         * signed.
695
                         */
696
                        maxexpire = (-1) &
697
                                ~(1 << ((sizeof(maxexpire) * 8) - 1));
698
                        if (ia->ia6_lifetime.ia6t_vltime <
699
                            maxexpire - ia->ia6_updatetime) {
700
                                retlt->ia6t_expire = ia->ia6_updatetime +
701
                                        ia->ia6_lifetime.ia6t_vltime;
702
                        } else
703
                                retlt->ia6t_expire = maxexpire;
704
                }
705
                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
706
                        time_t maxexpire;
707
                        struct in6_addrlifetime *retlt = &ifr->ifr_ifru.ifru_lifetime;
708
 
709
                        /*
710
                         * XXX: adjust expiration time assuming time_t is
711
                         * signed.
712
                         */
713
                        maxexpire = (-1) &
714
                                ~(1 << ((sizeof(maxexpire) * 8) - 1));
715
                        if (ia->ia6_lifetime.ia6t_pltime <
716
                            maxexpire - ia->ia6_updatetime) {
717
                                retlt->ia6t_preferred = ia->ia6_updatetime +
718
                                        ia->ia6_lifetime.ia6t_pltime;
719
                        } else
720
                                retlt->ia6t_preferred = maxexpire;
721
                }
722
                break;
723
 
724
        case SIOCSIFALIFETIME_IN6:
725
                ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
726
                /* for sanity */
727
                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
728
                        ia->ia6_lifetime.ia6t_expire =
729
                                time_second + ia->ia6_lifetime.ia6t_vltime;
730
                } else
731
                        ia->ia6_lifetime.ia6t_expire = 0;
732
                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
733
                        ia->ia6_lifetime.ia6t_preferred =
734
                                time_second + ia->ia6_lifetime.ia6t_pltime;
735
                } else
736
                        ia->ia6_lifetime.ia6t_preferred = 0;
737
                break;
738
 
739
        case SIOCAIFADDR_IN6:
740
        {
741
                int i, error = 0;
742
                struct nd_prefix pr0, *pr;
743
 
744
                /*
745
                 * first, make or update the interface address structure,
746
                 * and link it to the list.
747
                 */
748
                if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)
749
                        return(error);
750
                if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
751
                    == NULL) {
752
                        /*
753
                         * this can happen when the user specify the 0 valid
754
                         * lifetime.
755
                         */
756
                        break;
757
                }
758
 
759
                /*
760
                 * then, make the prefix on-link on the interface.
761
                 * XXX: we'd rather create the prefix before the address, but
762
                 * we need at least one address to install the corresponding
763
                 * interface route, so we configure the address first.
764
                 */
765
 
766
                /*
767
                 * convert mask to prefix length (prefixmask has already
768
                 * been validated in in6_update_ifa().
769
                 */
770
                bzero(&pr0, sizeof(pr0));
771
                pr0.ndpr_ifp = ifp;
772
                pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
773
                                             NULL);
774
                if (pr0.ndpr_plen == 128)
775
                        break;  /* we don't need to install a host route. */
776
                pr0.ndpr_prefix = ifra->ifra_addr;
777
                pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;
778
                /* apply the mask for safety. */
779
                for (i = 0; i < 4; i++) {
780
                        pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
781
                                ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
782
                }
783
                /*
784
                 * XXX: since we don't have an API to set prefix (not address)
785
                 * lifetimes, we just use the same lifetimes as addresses.
786
                 * The (temporarily) installed lifetimes can be overridden by
787
                 * later advertised RAs (when accept_rtadv is non 0), which is
788
                 * an intended behavior.
789
                 */
790
                pr0.ndpr_raf_onlink = 1; /* should be configurable? */
791
                pr0.ndpr_raf_auto =
792
                        ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
793
                pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
794
                pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
795
 
796
                /* add the prefix if there's one. */
797
                if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
798
                        /*
799
                         * nd6_prelist_add will install the corresponding
800
                         * interface route.
801
                         */
802
                        if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
803
                                return(error);
804
                        if (pr == NULL) {
805
                                log(LOG_ERR, "nd6_prelist_add succeeded but "
806
                                    "no prefix\n");
807
                                return(EINVAL); /* XXX panic here? */
808
                        }
809
                }
810
                if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
811
                    ia->ia6_ndpr == NULL) { /* new autoconfed addr */
812
                        ia->ia6_ndpr = pr;
813
                        pr->ndpr_refcnt++;
814
 
815
                        /*
816
                         * If this is the first autoconf address from
817
                         * the prefix, create a temporary address
818
                         * as well (when specified).
819
                         */
820
                        if (ip6_use_tempaddr && pr->ndpr_refcnt == 1) {
821
                                int e;
822
                                if ((e = in6_tmpifadd(ia, 1)) != 0) {
823
                                        log(LOG_NOTICE, "in6_control: failed "
824
                                            "to create a temporary address, "
825
                                            "errno=%d\n",
826
                                            e);
827
                                }
828
                        }
829
                }
830
 
831
                /*
832
                 * this might affect the status of autoconfigured addresses,
833
                 * that is, this address might make other addresses detached.
834
                 */
835
                pfxlist_onlink_check();
836
 
837
                break;
838
        }
839
 
840
        case SIOCDIFADDR_IN6:
841
        {
842
                int i = 0, purgeprefix = 0;
843
                struct nd_prefix pr0, *pr = NULL;
844
 
845
                /*
846
                 * If the address being deleted is the only one that owns
847
                 * the corresponding prefix, expire the prefix as well.
848
                 * XXX: theoretically, we don't have to worry about such
849
                 * relationship, since we separate the address management
850
                 * and the prefix management.  We do this, however, to provide
851
                 * as much backward compatibility as possible in terms of
852
                 * the ioctl operation.
853
                 */
854
                bzero(&pr0, sizeof(pr0));
855
                pr0.ndpr_ifp = ifp;
856
                pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr,
857
                                             NULL);
858
                if (pr0.ndpr_plen == 128)
859
                        goto purgeaddr;
860
                pr0.ndpr_prefix = ia->ia_addr;
861
                pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;
862
                for (i = 0; i < 4; i++) {
863
                        pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
864
                                ia->ia_prefixmask.sin6_addr.s6_addr32[i];
865
                }
866
                /*
867
                 * The logic of the following condition is a bit complicated.
868
                 * We expire the prefix when
869
                 * 1. the address obeys autoconfiguration and it is the
870
                 *    only owner of the associated prefix, or
871
                 * 2. the address does not obey autoconf and there is no
872
                 *    other owner of the prefix.
873
                 */
874
                if ((pr = nd6_prefix_lookup(&pr0)) != NULL &&
875
                    (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 &&
876
                      pr->ndpr_refcnt == 1) ||
877
                     ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 &&
878
                      pr->ndpr_refcnt == 0)))
879
                        purgeprefix = 1;
880
 
881
          purgeaddr:
882
                in6_purgeaddr(&ia->ia_ifa);
883
                if (pr && purgeprefix)
884
                        prelist_remove(pr);
885
                break;
886
        }
887
 
888
        default:
889
                if (ifp == NULL || ifp->if_ioctl == 0)
890
                        return(EOPNOTSUPP);
891
                return((*ifp->if_ioctl)(ifp, cmd, data));
892
        }
893
 
894
        return(0);
895
}
896
 
897
/*
898
 * Update parameters of an IPv6 interface address.
899
 * If necessary, a new entry is created and linked into address chains.
900
 * This function is separated from in6_control().
901
 * XXX: should this be performed under splnet()?
902
 */
903
static int
904
_in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
905
                struct in6_ifaddr *ia)
906
{
907
        int error = 0, hostIsNew = 0, plen = -1;
908
        struct in6_ifaddr *oia;
909
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
910
        struct ifaddr *ifa;
911
#endif
912
        struct sockaddr_in6 dst6;
913
        struct in6_addrlifetime *lt;
914
        struct in6_multi_mship *imm;
915
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
916
        time_t time_second = (time_t)time.tv_sec;
917
#endif
918
#ifdef MEASURE_PERFORMANCE
919
        int new_ifa = 0;
920
#endif
921
        struct rtentry *rt;
922
 
923
        /* Validate parameters */
924
        if (ifp == NULL || ifra == NULL) /* this maybe redundant */
925
                return(EINVAL);
926
 
927
        /*
928
         * The destination address for a p2p link must have a family
929
         * of AF_UNSPEC or AF_INET6.
930
         */
931
        if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
932
            ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
933
            ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
934
                return(EAFNOSUPPORT);
935
        /*
936
         * validate ifra_prefixmask.  don't check sin6_family, netmask
937
         * does not carry fields other than sin6_len.
938
         */
939
        if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
940
                return(EINVAL);
941
        /*
942
         * Because the IPv6 address architecture is classless, we require
943
         * users to specify a (non 0) prefix length (mask) for a new address.
944
         * We also require the prefix (when specified) mask is valid, and thus
945
         * reject a non-consecutive mask.
946
         */
947
        if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
948
                return(EINVAL);
949
        if (ifra->ifra_prefixmask.sin6_len != 0) {
950
                plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
951
                                    (u_char *)&ifra->ifra_prefixmask +
952
                                    ifra->ifra_prefixmask.sin6_len);
953
                if (plen <= 0)
954
                        return(EINVAL);
955
        }
956
        else {
957
                /*
958
                 * In this case, ia must not be NULL.  We just use its prefix
959
                 * length.
960
                 */
961
                plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
962
        }
963
        /*
964
         * If the destination address on a p2p interface is specified,
965
         * and the address is a scoped one, validate/set the scope
966
         * zone identifier.
967
         */
968
        dst6 = ifra->ifra_dstaddr;
969
        if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) &&
970
            (dst6.sin6_family == AF_INET6)) {
971
                int64_t zoneid;
972
 
973
#ifndef SCOPEDROUTING
974
                if ((error = in6_recoverscope(&dst6,
975
                                              &ifra->ifra_dstaddr.sin6_addr,
976
                                              ifp)) != 0)
977
                        return(error);
978
#endif
979
                if ((zoneid = in6_addr2zoneid(ifp, &dst6.sin6_addr)) < 0)
980
                        return(EINVAL);
981
                if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */
982
                        dst6.sin6_scope_id = zoneid;
983
                else if (dst6.sin6_scope_id != zoneid)
984
                        return(EINVAL); /* scope ID mismatch. */
985
                if ((error = in6_embedscope(&dst6.sin6_addr, &dst6)) != 0)
986
                        return(error);
987
#ifndef SCOPEDROUTING
988
                dst6.sin6_scope_id = 0; /* XXX */
989
#endif
990
        }
991
        /*
992
         * The destination address can be specified only for a p2p or a
993
         * loopback interface.  If specified, the corresponding prefix length
994
         * must be 128.
995
         */
996
        if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
997
#ifdef FORCE_P2PPLEN
998
                int i;
999
#endif
1000
 
1001
                if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
1002
                        /* XXX: noisy message */
1003
                        log(LOG_INFO, "in6_update_ifa: a destination can be "
1004
                            "specified for a p2p or a loopback IF only\n");
1005
                        return(EINVAL);
1006
                }
1007
                if (plen != 128) {
1008
                        log(LOG_INFO, "in6_update_ifa: prefixlen should be "
1009
                            "128 when dstaddr is specified\n");
1010
#ifdef FORCE_P2PPLEN
1011
                        /*
1012
                         * To be compatible with old configurations,
1013
                         * such as ifconfig gif0 inet6 2001::1 2001::2
1014
                         * prefixlen 126, we override the specified
1015
                         * prefixmask as if the prefix length was 128.
1016
                         */
1017
                        ifra->ifra_prefixmask.sin6_len
1018
                                = sizeof(struct sockaddr_in6);
1019
                        for (i = 0; i < 4; i++)
1020
                                ifra->ifra_prefixmask.sin6_addr.s6_addr32[i] =
1021
                                        0xffffffff;
1022
                        plen = 128;
1023
#else
1024
                        return(EINVAL);
1025
#endif
1026
                }
1027
        }
1028
        /* lifetime consistency check */
1029
        lt = &ifra->ifra_lifetime;
1030
        if (lt->ia6t_pltime > lt->ia6t_vltime)
1031
                return(EINVAL);
1032
        if (lt->ia6t_vltime == 0) {
1033
                /*
1034
                 * the following log might be noisy, but this is a typical
1035
                 * configuration mistake or a tool's bug.
1036
                 */
1037
                log(LOG_INFO,
1038
                    "in6_update_ifa: valid lifetime is 0 for %s\n",
1039
                    ip6_sprintf(&ifra->ifra_addr.sin6_addr));
1040
 
1041
                if (ia == NULL)
1042
                        return(0); /* there's nothing to do */
1043
        }
1044
 
1045
        /*
1046
         * If this is a new address, allocate a new ifaddr and link it
1047
         * into chains.
1048
         */
1049
        if (ia == NULL) {
1050
                hostIsNew = 1;
1051
                /*
1052
                 * When in6_update_ifa() is called in a process of a received
1053
                 * RA, it is called under an interrupt context.  So, we should
1054
                 * call malloc with M_NOWAIT.
1055
                 */
1056
                ia = (struct in6_ifaddr *)
1057
                        malloc(sizeof(*ia), M_IFADDR, M_NOWAIT);
1058
                if (ia == NULL)
1059
                        return (ENOBUFS);
1060
                bzero((caddr_t)ia, sizeof(*ia));
1061
                LIST_INIT(&ia->ia6_memberships);
1062
                /* Initialize the address and masks, and put time stamp */
1063
                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
1064
                ia->ia_addr.sin6_family = AF_INET6;
1065
                ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
1066
                ia->ia6_createtime = ia->ia6_updatetime = time_second;
1067
                if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
1068
                        /*
1069
                         * XXX: some functions expect that ifa_dstaddr is not
1070
                         * NULL for p2p interfaces.
1071
                         */
1072
                        ia->ia_ifa.ifa_dstaddr
1073
                                = (struct sockaddr *)&ia->ia_dstaddr;
1074
                } else {
1075
                        ia->ia_ifa.ifa_dstaddr = NULL;
1076
                }
1077
                ia->ia_ifa.ifa_netmask
1078
                        = (struct sockaddr *)&ia->ia_prefixmask;
1079
 
1080
                ia->ia_ifp = ifp;
1081
                if ((oia = in6_ifaddr) != NULL) {
1082
                        for ( ; oia->ia_next; oia = oia->ia_next)
1083
                                continue;
1084
                        oia->ia_next = ia;
1085
                } else
1086
                        in6_ifaddr = ia;
1087
#ifdef __NetBSD__
1088
                /* gain a refcnt for the link from in6_ifaddr */
1089
                IFAREF(&ia->ia_ifa);
1090
#endif
1091
 
1092
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1093
                if ((ifa = ifp->if_addrlist) != NULL) {
1094
                        for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
1095
                                continue;
1096
                        ifa->ifa_next = ia62ifa(ia);
1097
                } else
1098
                        ifp->if_addrlist = ia62ifa(ia);
1099
#else
1100
                TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
1101
                                  ifa_list);
1102
                log_(LOG_ADDR) {
1103
                    diag_printf("%s.%d - After inserting %p into list %p\n",
1104
                                __FUNCTION__, __LINE__,
1105
                                &ia->ia_ifa, &ifp->if_addrlist);
1106
                    _show_ifp(ifp);
1107
                }
1108
#endif
1109
#ifdef __NetBSD__
1110
                /* gain another refcnt for the link from if_addrlist */
1111
                IFAREF(&ia->ia_ifa);
1112
#endif
1113
 
1114
#ifdef MEASURE_PERFORMANCE
1115
                new_ifa = 1;
1116
#endif
1117
        }
1118
 
1119
        /* set prefix mask */
1120
        if (ifra->ifra_prefixmask.sin6_len) {
1121
                /*
1122
                 * We prohibit changing the prefix length of an existing
1123
                 * address, because
1124
                 * + such an operation should be rare in IPv6, and
1125
                 * + the operation would confuse prefix management.
1126
                 */
1127
                if (ia->ia_prefixmask.sin6_len &&
1128
                    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
1129
                        log(LOG_INFO, "in6_update_ifa: the prefix length of an"
1130
                            " existing (%s) address should not be changed\n",
1131
                            ip6_sprintf(&ia->ia_addr.sin6_addr));
1132
                        error = EINVAL;
1133
                        goto unlink;
1134
                }
1135
                ia->ia_prefixmask = ifra->ifra_prefixmask;
1136
        }
1137
 
1138
        /*
1139
         * If a new destination address is specified, scrub the old one and
1140
         * install the new destination.  Note that the interface must be
1141
         * p2p or loopback (see the check above.)
1142
         */
1143
        if (dst6.sin6_family == AF_INET6 &&
1144
            !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr,
1145
                                &ia->ia_dstaddr.sin6_addr)) {
1146
                int e;
1147
 
1148
                if ((ia->ia_flags & IFA_ROUTE) != 0 &&
1149
                    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
1150
                    != 0) {
1151
                        log(LOG_ERR, "in6_update_ifa: failed to remove "
1152
                            "a route to the old destination: %s\n",
1153
                            ip6_sprintf(&ia->ia_addr.sin6_addr));
1154
                        /* proceed anyway... */
1155
                }
1156
                else
1157
                        ia->ia_flags &= ~IFA_ROUTE;
1158
                ia->ia_dstaddr = dst6;
1159
        }
1160
 
1161
        /*
1162
         * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
1163
         * to see if the address is deprecated or invalidated, but initialize
1164
         * these members for applications.
1165
         */
1166
        ia->ia6_lifetime = ifra->ifra_lifetime;
1167
        if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
1168
                ia->ia6_lifetime.ia6t_expire =
1169
                        time_second + ia->ia6_lifetime.ia6t_vltime;
1170
        } else
1171
                ia->ia6_lifetime.ia6t_expire = 0;
1172
        if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
1173
                ia->ia6_lifetime.ia6t_preferred =
1174
                        time_second + ia->ia6_lifetime.ia6t_pltime;
1175
        } else
1176
                ia->ia6_lifetime.ia6t_preferred = 0;
1177
 
1178
        /* reset the interface and routing table appropriately. */
1179
        if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
1180
                goto unlink;
1181
 
1182
        /*
1183
         * Make the address tentative before joining multicast addresses,
1184
         * so that corresponding MLD responses would not have a tentative
1185
         * source address.
1186
         */
1187
        ia->ia6_flags = ifra->ifra_flags;
1188
        ia->ia6_flags &= ~IN6_IFF_DUPLICATED;   /* safety */
1189
#ifdef MIP6
1190
        if (hostIsNew && in6if_do_dad(ifp) && mip6_ifa_need_dad(ia))
1191
#else /* MIP6 */
1192
        if (hostIsNew && in6if_do_dad(ifp))
1193
#endif /* MIP6 */
1194
                ia->ia6_flags |= IN6_IFF_TENTATIVE;
1195
 
1196
        /*
1197
         * Beyond this point, we should call in6_purgeaddr upon an error,
1198
         * not just go to unlink.
1199
         */
1200
 
1201
        if ((ifp->if_flags & IFF_MULTICAST) != 0) {
1202
                struct sockaddr_in6 mltaddr, mltmask;
1203
 
1204
                if (hostIsNew) {
1205
                        /*
1206
                         * join solicited multicast addr for new host id
1207
                         */
1208
                        struct in6_addr llsol;
1209
                        bzero(&llsol, sizeof(struct in6_addr));
1210
                        llsol.s6_addr16[0] = htons(0xff02);
1211
                        llsol.s6_addr16[1] = htons(ifp->if_index);
1212
                        llsol.s6_addr32[1] = 0;
1213
                        llsol.s6_addr32[2] = htonl(1);
1214
                        llsol.s6_addr32[3] =
1215
                                ifra->ifra_addr.sin6_addr.s6_addr32[3];
1216
                        llsol.s6_addr8[12] = 0xff;
1217
                        imm = in6_joingroup(ifp, &llsol, &error);
1218
                        if (imm) {
1219
                                LIST_INSERT_HEAD(&ia->ia6_memberships, imm,
1220
                                    i6mm_chain);
1221
                        } else {
1222
                                log(LOG_ERR,
1223
                                    "in6_update_ifa: addmulti failed for "
1224
                                    "%s on %s (errno=%d)\n",
1225
                                    ip6_sprintf(&llsol),
1226
                                    if_name(ifp), error);
1227
                                goto cleanup;
1228
                        }
1229
                }
1230
 
1231
                bzero(&mltmask, sizeof(mltmask));
1232
                mltmask.sin6_len = sizeof(struct sockaddr_in6);
1233
                mltmask.sin6_family = AF_INET6;
1234
                mltmask.sin6_addr = in6mask32;
1235
 
1236
                /*
1237
                 * join link-local all-nodes address
1238
                 */
1239
                bzero(&mltaddr, sizeof(mltaddr));
1240
                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
1241
                mltaddr.sin6_family = AF_INET6;
1242
                mltaddr.sin6_addr = in6addr_linklocal_allnodes;
1243
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1244
 
1245
#ifdef __FreeBSD__
1246
                rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1247
#else
1248
                rt = rtalloc1((struct sockaddr *)&mltaddr, 0);
1249
#endif
1250
                if (rt) {
1251
                        /* 32bit came from "mltmask" */
1252
                        if (memcmp(&mltaddr.sin6_addr,
1253
                            &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1254
                            32 / 8)) {
1255
                                RTFREE(rt);
1256
                                rt = NULL;
1257
                        }
1258
                }
1259
                if (!rt) {
1260
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
1261
                        struct rt_addrinfo info;
1262
 
1263
                        bzero(&info, sizeof(info));
1264
                        info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
1265
                        info.rti_info[RTAX_GATEWAY] =
1266
                                (struct sockaddr *)&ia->ia_addr;
1267
                        info.rti_info[RTAX_NETMASK] =
1268
                                (struct sockaddr *)&mltmask;
1269
                        info.rti_info[RTAX_IFA] =
1270
                                (struct sockaddr *)&ia->ia_addr;
1271
                        /* XXX: we need RTF_CLONING to fake nd6_rtrequest */
1272
                        info.rti_flags = RTF_UP | RTF_CLONING;
1273
                        error = rtrequest1(RTM_ADD, &info, NULL);
1274
#else
1275
                        error = rtrequest(RTM_ADD,
1276
                                          (struct sockaddr *)&mltaddr,
1277
                                          (struct sockaddr *)&ia->ia_addr,
1278
                                          (struct sockaddr *)&mltmask,
1279
                                          RTF_UP | RTF_CLONING,
1280
                                          (struct rtentry **)0);
1281
#endif
1282
                        if (error)
1283
                                goto cleanup;
1284
                } else {
1285
                        RTFREE(rt);
1286
                }
1287
                imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
1288
                if (imm) {
1289
                        LIST_INSERT_HEAD(&ia->ia6_memberships, imm,
1290
                            i6mm_chain);
1291
                } else {
1292
                        log(LOG_WARNING,
1293
                            "in6_update_ifa: addmulti failed for "
1294
                            "%s on %s (errno=%d)\n",
1295
                            ip6_sprintf(&mltaddr.sin6_addr),
1296
                            if_name(ifp), error);
1297
                        goto cleanup;
1298
                }
1299
 
1300
                /*
1301
                 * join node information group address
1302
                 */
1303
#ifdef __FreeBSD__
1304
#define hostnamelen     strlen(hostname)
1305
#endif
1306
                if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)
1307
                    == 0) {
1308
                        imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
1309
                        if (imm) {
1310
                                LIST_INSERT_HEAD(&ia->ia6_memberships, imm,
1311
                                    i6mm_chain);
1312
                        } else {
1313
                                log(LOG_WARNING, "in6_update_ifa: "
1314
                                    "addmulti failed for "
1315
                                    "%s on %s (errno=%d)\n",
1316
                                    ip6_sprintf(&mltaddr.sin6_addr),
1317
                                    if_name(ifp), error);
1318
                                /* XXX not very fatal, go on... */
1319
                        }
1320
                }
1321
#ifdef __FreeBSD__
1322
#undef hostnamelen
1323
#endif
1324
 
1325
                /*
1326
                 * join interface-local all-nodes address, on loopback.
1327
                 * (ff01::1%ifN, and ff01::%ifN/32)
1328
                 */
1329
                mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
1330
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1331
#ifdef __FreeBSD__
1332
                rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
1333
#else
1334
                rt = rtalloc1((struct sockaddr *)&mltaddr, 0);
1335
#endif
1336
                if (rt) {
1337
                        /* 32bit came from "mltmask" */
1338
                        if (memcmp(&mltaddr.sin6_addr,
1339
                            &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
1340
                            32 / 8)) {
1341
                                RTFREE(rt);
1342
                                rt = NULL;
1343
                        }
1344
                }
1345
                if (!rt) {
1346
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
1347
                        struct rt_addrinfo info;
1348
 
1349
                        bzero(&info, sizeof(info));
1350
                        info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
1351
                        info.rti_info[RTAX_GATEWAY] =
1352
                                (struct sockaddr *)&ia->ia_addr;
1353
                        info.rti_info[RTAX_NETMASK] =
1354
                                (struct sockaddr *)&mltmask;
1355
                        info.rti_info[RTAX_IFA] =
1356
                                (struct sockaddr *)&ia->ia_addr;
1357
                        info.rti_flags = RTF_UP | RTF_CLONING;
1358
                        error = rtrequest1(RTM_ADD, &info, NULL);
1359
#else
1360
                        error = rtrequest(RTM_ADD,
1361
                                          (struct sockaddr *)&mltaddr,
1362
                                          (struct sockaddr *)&ia->ia_addr,
1363
                                          (struct sockaddr *)&mltmask,
1364
                                          RTF_UP | RTF_CLONING,
1365
                                          (struct rtentry **)0);
1366
#endif
1367
                        if (error)
1368
                                goto cleanup;
1369
                } else {
1370
                        RTFREE(rt);
1371
                }
1372
 
1373
                imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
1374
                if (imm) {
1375
                        LIST_INSERT_HEAD(&ia->ia6_memberships, imm,
1376
                            i6mm_chain);
1377
                } else {
1378
                        log(LOG_WARNING, "in6_update_ifa: "
1379
                            "addmulti failed for %s on %s "
1380
                            "(errno=%d)\n",
1381
                            ip6_sprintf(&mltaddr.sin6_addr),
1382
                            if_name(ifp), error);
1383
                        goto cleanup;
1384
                }
1385
        }
1386
 
1387
#ifdef MEASURE_PERFORMANCE
1388
        {
1389
                int s = splnet();
1390
                if (new_ifa)
1391
                        in6h_addifa(ia);
1392
                else
1393
                        in6h_rebuild(0);
1394
                splx(s);
1395
        }
1396
#endif
1397
 
1398
        /*
1399
         * make sure to initialize ND6 information.  this is to workaround
1400
         * issues with interfaces with IPv6 addresses, which have never brought
1401
         * up.  We are assuming that it is safe to nd6_ifattach multiple times.
1402
         */
1403
        nd6_ifattach(ifp);
1404
 
1405
        /*
1406
         * Perform DAD, if needed.
1407
         * XXX It may be of use, if we can administratively
1408
         * disable DAD.
1409
         */
1410
#ifdef MIP6
1411
        if (hostIsNew && in6if_do_dad(ifp) && mip6_ifa_need_dad(ia) &&
1412
            (ifra->ifra_flags & IN6_IFF_NODAD) == 0)
1413
#else /* MIP6 */
1414
        if (hostIsNew && in6if_do_dad(ifp) &&
1415
            (ifra->ifra_flags & IN6_IFF_NODAD) == 0)
1416
#endif /* MIP6 */
1417
        {
1418
                nd6_dad_start((struct ifaddr *)ia, NULL);
1419
        }
1420
 
1421
        return(error);
1422
 
1423
  unlink:
1424
        /*
1425
         * XXX: if a change of an existing address failed, keep the entry
1426
         * anyway.
1427
         */
1428
        if (hostIsNew)
1429
                in6_unlink_ifa(ia, ifp);
1430
        return(error);
1431
 
1432
  cleanup:
1433
        in6_purgeaddr(&ia->ia_ifa);
1434
        return error;
1435
}
1436
 
1437
void
1438
in6_purgeaddr(ifa)
1439
        struct ifaddr *ifa;
1440
{
1441
        struct ifnet *ifp = ifa->ifa_ifp;
1442
        struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
1443
        struct in6_multi_mship *imm;
1444
 
1445
        /* stop DAD processing */
1446
        nd6_dad_stop(ifa);
1447
 
1448
        /*
1449
         * delete route to the destination of the address being purged.
1450
         * The interface must be p2p or loopback in this case.
1451
         */
1452
        if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) {
1453
                int e;
1454
 
1455
                if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
1456
                    != 0) {
1457
                        log(LOG_ERR, "in6_purgeaddr: failed to remove "
1458
                            "a route to the p2p destination: %s on %s, "
1459
                            "errno=%d\n",
1460
                            ip6_sprintf(&ia->ia_addr.sin6_addr), if_name(ifp),
1461
                            e);
1462
                        /* proceed anyway... */
1463
                }
1464
                else
1465
                        ia->ia_flags &= ~IFA_ROUTE;
1466
        }
1467
 
1468
        /* Remove ownaddr's loopback rtentry, if it exists. */
1469
        in6_ifremloop(&(ia->ia_ifa));
1470
 
1471
        /*
1472
         * leave from multicast groups we have joined for the interface
1473
         */
1474
        while ((imm = ia->ia6_memberships.lh_first) != NULL) {
1475
                LIST_REMOVE(imm, i6mm_chain);
1476
                in6_leavegroup(imm);
1477
        }
1478
 
1479
        in6_unlink_ifa(ia, ifp);
1480
}
1481
 
1482
int
1483
in6_update_ifa(ifp, ifra, ia)
1484
        struct ifnet *ifp;
1485
        struct in6_aliasreq *ifra;
1486
        struct in6_ifaddr *ia;
1487
{
1488
    int res;
1489
    int s = splnet();
1490
//    extern int irq_level;
1491
//    if (irq_level) {
1492
//        diag_printf("%s - called from IRQ!\n", __FUNCTION__);
1493
//    }
1494
    res = _in6_update_ifa(ifp, ifra, ia);
1495
    splx(s);
1496
    return res;
1497
}
1498
 
1499
static void
1500
in6_unlink_ifa(ia, ifp)
1501
        struct in6_ifaddr *ia;
1502
        struct ifnet *ifp;
1503
{
1504
        struct in6_ifaddr *oia;
1505
#ifdef __NetBSD__
1506
        int     s = splsoftnet();
1507
#else
1508
        int     s = splnet();
1509
#endif
1510
 
1511
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1512
        struct ifaddr *ifa;
1513
#endif
1514
 
1515
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1516
        if ((ifa = ifp->if_addrlist) == ia62ifa(ia))
1517
                ifp->if_addrlist = ifa->ifa_next;
1518
        else {
1519
                while (ifa->ifa_next &&
1520
                       (ifa->ifa_next != ia62ifa(ia)))
1521
                        ifa = ifa->ifa_next;
1522
                if (ifa->ifa_next)
1523
                        ifa->ifa_next = ia62ifa(ia)->ifa_next;
1524
                else {
1525
                        /* search failed */
1526
                        printf("Couldn't unlink in6_ifaddr from ifp\n");
1527
                }
1528
        }
1529
#else
1530
        TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
1531
        log_(LOG_ADDR) {
1532
            diag_printf("%s.%d - After removing %p into list %p\n",
1533
                        __FUNCTION__, __LINE__,
1534
                        &ia->ia_ifa, &ifp->if_addrlist);
1535
            _show_ifp(ifp);
1536
        }
1537
#endif
1538
#ifdef __NetBSD__
1539
        /* release a refcnt for the link from if_addrlist */
1540
        IFAFREE(&ia->ia_ifa);
1541
#endif
1542
 
1543
        oia = ia;
1544
        if (oia == (ia = in6_ifaddr))
1545
                in6_ifaddr = ia->ia_next;
1546
        else {
1547
                while (ia->ia_next && (ia->ia_next != oia))
1548
                        ia = ia->ia_next;
1549
                if (ia->ia_next)
1550
                        ia->ia_next = oia->ia_next;
1551
                else {
1552
                        /* search failed */
1553
                        printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n");
1554
                }
1555
        }
1556
 
1557
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1558
        if (oia->ia6_multiaddrs.lh_first != NULL) {
1559
#ifdef __NetBSD__
1560
                /*
1561
                 * XXX thorpej@netbsd.org -- if the interface is going
1562
                 * XXX away, don't save the multicast entries, delete them!
1563
                 */
1564
                if (oia->ia_ifa.ifa_ifp->if_output == if_nulloutput) {
1565
                        struct in6_multi *in6m;
1566
 
1567
                        while ((in6m =
1568
                            LIST_FIRST(&oia->ia6_multiaddrs)) != NULL)
1569
                                in6_delmulti(in6m);
1570
                } else
1571
                        in6_savemkludge(oia);
1572
#else
1573
                in6_savemkludge(oia);
1574
#endif
1575
        }
1576
#endif
1577
 
1578
#ifdef MEASURE_PERFORMANCE
1579
        in6h_delifa(oia);
1580
#endif
1581
 
1582
        /*
1583
         * When an autoconfigured address is being removed, release the
1584
         * reference to the base prefix.  Also, since the release might
1585
         * affect the status of other (detached) addresses, call
1586
         * pfxlist_onlink_check().
1587
         */
1588
        if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) {
1589
                if (oia->ia6_ndpr == NULL) {
1590
                        log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address "
1591
                            "%p has no prefix\n", oia);
1592
                } else {
1593
                        oia->ia6_ndpr->ndpr_refcnt--;
1594
                        oia->ia6_flags &= ~IN6_IFF_AUTOCONF;
1595
                        oia->ia6_ndpr = NULL;
1596
                }
1597
 
1598
                pfxlist_onlink_check();
1599
        }
1600
 
1601
        /*
1602
         * release another refcnt for the link from in6_ifaddr.
1603
         * Note that we should decrement the refcnt at least once for all *BSD.
1604
         */
1605
        IFAFREE(&oia->ia_ifa);
1606
 
1607
        splx(s);
1608
}
1609
 
1610
void
1611
in6_purgeif(ifp)
1612
        struct ifnet *ifp;
1613
{
1614
        struct ifaddr *ifa, *nifa;
1615
 
1616
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1617
        for (ifa = ifp->if_addrlist; ifa; ifa = nifa)
1618
#else
1619
        for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa)
1620
#endif
1621
        {
1622
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1623
                nifa = ifa->ifa_next;
1624
#else
1625
                nifa = TAILQ_NEXT(ifa, ifa_list);
1626
#endif
1627
                if (ifa->ifa_addr->sa_family != AF_INET6)
1628
                        continue;
1629
                in6_purgeaddr(ifa);
1630
        }
1631
 
1632
#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802)
1633
        in6_ifdetach(ifp);
1634
#endif
1635
}
1636
 
1637
/*
1638
 * SIOC[GAD]LIFADDR.
1639
 *      SIOCGLIFADDR: get first address. (?)
1640
 *      SIOCGLIFADDR with IFLR_PREFIX:
1641
 *              get first address that matches the specified prefix.
1642
 *      SIOCALIFADDR: add the specified address.
1643
 *      SIOCALIFADDR with IFLR_PREFIX:
1644
 *              add the specified prefix, filling hostid part from
1645
 *              the first link-local address.  prefixlen must be <= 64.
1646
 *      SIOCDLIFADDR: delete the specified address.
1647
 *      SIOCDLIFADDR with IFLR_PREFIX:
1648
 *              delete the first address that matches the specified prefix.
1649
 * return values:
1650
 *      EINVAL on invalid parameters
1651
 *      EADDRNOTAVAIL on prefix match failed/specified address not found
1652
 *      other values may be returned from in6_ioctl()
1653
 *
1654
 * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
1655
 * this is to accomodate address naming scheme other than RFC2374,
1656
 * in the future.
1657
 * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
1658
 * address encoding scheme. (see figure on page 8)
1659
 */
1660
static int
1661
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
1662
in6_lifaddr_ioctl(so, cmd, data, ifp, p)
1663
        struct socket *so;
1664
        u_long cmd;
1665
        caddr_t data;
1666
        struct ifnet *ifp;
1667
        struct proc *p;
1668
#else
1669
in6_lifaddr_ioctl(so, cmd, data, ifp)
1670
        struct socket *so;
1671
        u_long cmd;
1672
        caddr_t data;
1673
        struct ifnet *ifp;
1674
#endif
1675
{
1676
        struct if_laddrreq *iflr = (struct if_laddrreq *)data;
1677
        struct ifaddr *ifa;
1678
        struct sockaddr *sa;
1679
        int64_t zoneid;
1680
 
1681
        /* sanity checks */
1682
        if (!data || !ifp) {
1683
                panic("invalid argument to in6_lifaddr_ioctl");
1684
                /* NOTREACHED */
1685
        }
1686
 
1687
        switch (cmd) {
1688
        case SIOCGLIFADDR:
1689
                /* address must be specified on GET with IFLR_PREFIX */
1690
                if ((iflr->flags & IFLR_PREFIX) == 0)
1691
                        break;
1692
                /* FALLTHROUGH */
1693
        case SIOCALIFADDR:
1694
        case SIOCDLIFADDR:
1695
                /* address must be specified on ADD and DELETE */
1696
                sa = (struct sockaddr *)&iflr->addr;
1697
                if (sa->sa_family != AF_INET6)
1698
                        return EINVAL;
1699
                if (sa->sa_len != sizeof(struct sockaddr_in6))
1700
                        return EINVAL;
1701
                /* XXX need improvement */
1702
                sa = (struct sockaddr *)&iflr->dstaddr;
1703
                if (sa->sa_family && sa->sa_family != AF_INET6)
1704
                        return EINVAL;
1705
                if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
1706
                        return EINVAL;
1707
                break;
1708
        default: /* shouldn't happen */
1709
#if 0
1710
                panic("invalid cmd to in6_lifaddr_ioctl");
1711
                /* NOTREACHED */
1712
#else
1713
                return EOPNOTSUPP;
1714
#endif
1715
        }
1716
        if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
1717
                return EINVAL;
1718
 
1719
        switch (cmd) {
1720
        case SIOCALIFADDR:
1721
            {
1722
                struct in6_aliasreq ifra;
1723
                struct in6_addr *hostid = NULL;
1724
                int prefixlen;
1725
 
1726
                if ((iflr->flags & IFLR_PREFIX) != 0) {
1727
                        struct sockaddr_in6 *sin6;
1728
 
1729
                        /*
1730
                         * hostid is to fill in the hostid part of the
1731
                         * address.  hostid points to the first link-local
1732
                         * address attached to the interface.
1733
                         */
1734
                        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
1735
                        if (!ifa)
1736
                                return EADDRNOTAVAIL;
1737
                        hostid = IFA_IN6(ifa);
1738
 
1739
                        /* prefixlen must be <= 64. */
1740
                        if (64 < iflr->prefixlen)
1741
                                return EINVAL;
1742
                        prefixlen = iflr->prefixlen;
1743
 
1744
                        /* hostid part must be zero. */
1745
                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
1746
                        if (sin6->sin6_addr.s6_addr32[2] != 0
1747
                         || sin6->sin6_addr.s6_addr32[3] != 0) {
1748
                                return EINVAL;
1749
                        }
1750
                } else
1751
                        prefixlen = iflr->prefixlen;
1752
 
1753
                /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
1754
                bzero(&ifra, sizeof(ifra));
1755
                bcopy(iflr->iflr_name, ifra.ifra_name,
1756
                        sizeof(ifra.ifra_name));
1757
 
1758
                bcopy(&iflr->addr, &ifra.ifra_addr,
1759
                        ((struct sockaddr *)&iflr->addr)->sa_len);
1760
                if (hostid) {
1761
                        /* fill in hostid part */
1762
                        ifra.ifra_addr.sin6_addr.s6_addr32[2] =
1763
                                hostid->s6_addr32[2];
1764
                        ifra.ifra_addr.sin6_addr.s6_addr32[3] =
1765
                                hostid->s6_addr32[3];
1766
                }
1767
 
1768
                if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */
1769
                        bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1770
                                ((struct sockaddr *)&iflr->dstaddr)->sa_len);
1771
                        if (hostid) {
1772
                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
1773
                                        hostid->s6_addr32[2];
1774
                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
1775
                                        hostid->s6_addr32[3];
1776
                        }
1777
                }
1778
 
1779
                ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1780
                in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
1781
 
1782
                ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
1783
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
1784
                return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
1785
#else
1786
                return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp);
1787
#endif
1788
            }
1789
        case SIOCGLIFADDR:
1790
        case SIOCDLIFADDR:
1791
            {
1792
                struct in6_ifaddr *ia;
1793
                struct in6_addr mask, candidate, match;
1794
                struct sockaddr_in6 *sin6;
1795
                int cmp;
1796
 
1797
                bzero(&mask, sizeof(mask));
1798
                if (iflr->flags & IFLR_PREFIX) {
1799
                        /* lookup a prefix rather than address. */
1800
                        in6_prefixlen2mask(&mask, iflr->prefixlen);
1801
 
1802
                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
1803
                        bcopy(&sin6->sin6_addr, &match, sizeof(match));
1804
                        match.s6_addr32[0] &= mask.s6_addr32[0];
1805
                        match.s6_addr32[1] &= mask.s6_addr32[1];
1806
                        match.s6_addr32[2] &= mask.s6_addr32[2];
1807
                        match.s6_addr32[3] &= mask.s6_addr32[3];
1808
 
1809
                        /* if you set extra bits, that's wrong */
1810
                        if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
1811
                                return EINVAL;
1812
 
1813
                        cmp = 1;
1814
                } else {
1815
                        if (cmd == SIOCGLIFADDR) {
1816
                                /* on getting an address, take the 1st match */
1817
                                cmp = 0; /* XXX */
1818
                        } else {
1819
                                /* on deleting an address, do exact match */
1820
                                in6_prefixlen2mask(&mask, 128);
1821
                                sin6 = (struct sockaddr_in6 *)&iflr->addr;
1822
                                bcopy(&sin6->sin6_addr, &match, sizeof(match));
1823
 
1824
                                cmp = 1;
1825
                        }
1826
                }
1827
 
1828
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1829
                for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
1830
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
1831
                TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1832
#else
1833
                for (ifa = ifp->if_addrlist.tqh_first;
1834
                     ifa;
1835
                     ifa = ifa->ifa_list.tqe_next)
1836
#endif
1837
                {
1838
                        if (ifa->ifa_addr->sa_family != AF_INET6)
1839
                                continue;
1840
                        if (!cmp)
1841
                                break;
1842
 
1843
                        bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
1844
#ifndef SCOPEDROUTING
1845
                        /*
1846
                         * XXX: this is adhoc, but is necessary to allow
1847
                         * a user to specify fe80::/64 (not /10) for a
1848
                         * link-local address.
1849
                         */
1850
                        if (IN6_IS_ADDR_LINKLOCAL(&candidate))
1851
                                candidate.s6_addr16[1] = 0;
1852
#endif
1853
                        candidate.s6_addr32[0] &= mask.s6_addr32[0];
1854
                        candidate.s6_addr32[1] &= mask.s6_addr32[1];
1855
                        candidate.s6_addr32[2] &= mask.s6_addr32[2];
1856
                        candidate.s6_addr32[3] &= mask.s6_addr32[3];
1857
                        if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
1858
                                break;
1859
                }
1860
                if (!ifa)
1861
                        return EADDRNOTAVAIL;
1862
                ia = ifa2ia6(ifa);
1863
 
1864
                if (cmd == SIOCGLIFADDR) {
1865
#ifndef SCOPEDROUTING
1866
                        struct sockaddr_in6 *s6;
1867
#endif
1868
 
1869
                        /* fill in the if_laddrreq structure */
1870
                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
1871
#ifndef SCOPEDROUTING           /* XXX see above */
1872
                        s6 = (struct sockaddr_in6 *)&iflr->addr;
1873
                        if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
1874
                                s6->sin6_addr.s6_addr16[1] = 0;
1875
                                zoneid = in6_addr2zoneid(ifp, &s6->sin6_addr);
1876
                                if (zoneid < 0) /* XXX: should not happen */
1877
                                        return(EINVAL);
1878
                                s6->sin6_scope_id = zoneid;
1879
                        }
1880
#endif
1881
                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
1882
                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
1883
                                        ia->ia_dstaddr.sin6_len);
1884
#ifndef SCOPEDROUTING           /* XXX see above */
1885
                                s6 = (struct sockaddr_in6 *)&iflr->dstaddr;
1886
                                if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
1887
                                        s6->sin6_addr.s6_addr16[1] = 0;
1888
                                        zoneid = in6_addr2zoneid(ifp,
1889
                                                                 &s6->sin6_addr);
1890
                                        if (zoneid < 0) /* XXX */
1891
                                                return(EINVAL);
1892
                                        s6->sin6_scope_id = zoneid;
1893
                                }
1894
#endif
1895
                        } else
1896
                                bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
1897
 
1898
                        iflr->prefixlen =
1899
                                in6_mask2len(&ia->ia_prefixmask.sin6_addr,
1900
                                             NULL);
1901
 
1902
                        iflr->flags = ia->ia6_flags;    /* XXX */
1903
 
1904
                        return 0;
1905
                } else {
1906
                        struct in6_aliasreq ifra;
1907
 
1908
                        /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
1909
                        bzero(&ifra, sizeof(ifra));
1910
                        bcopy(iflr->iflr_name, ifra.ifra_name,
1911
                                sizeof(ifra.ifra_name));
1912
 
1913
                        bcopy(&ia->ia_addr, &ifra.ifra_addr,
1914
                                ia->ia_addr.sin6_len);
1915
                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
1916
                                bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
1917
                                        ia->ia_dstaddr.sin6_len);
1918
                        } else {
1919
                                bzero(&ifra.ifra_dstaddr,
1920
                                    sizeof(ifra.ifra_dstaddr));
1921
                        }
1922
                        bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
1923
                                ia->ia_prefixmask.sin6_len);
1924
 
1925
                        ifra.ifra_flags = ia->ia6_flags;
1926
#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
1927
                        return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
1928
                                ifp, p);
1929
#else
1930
                        return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
1931
                                ifp);
1932
#endif
1933
                }
1934
            }
1935
        }
1936
 
1937
        return EOPNOTSUPP;      /* just for safety */
1938
}
1939
 
1940
/*
1941
 * Initialize an interface's intetnet6 address
1942
 * and routing table entry.
1943
 */
1944
static int
1945
in6_ifinit(ifp, ia, sin6, newhost)
1946
        struct ifnet *ifp;
1947
        struct in6_ifaddr *ia;
1948
        struct sockaddr_in6 *sin6;
1949
        int newhost;
1950
{
1951
        int     error = 0, plen, ifacount = 0;
1952
        int     s = splimp();
1953
        struct ifaddr *ifa;
1954
 
1955
        /*
1956
         * Give the interface a chance to initialize
1957
         * if this is its first address,
1958
         * and to validate the address if necessary.
1959
         */
1960
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
1961
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
1962
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
1963
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1964
#else
1965
        for (ifa = ifp->if_addrlist.tqh_first; ifa;
1966
             ifa = ifa->ifa_list.tqe_next)
1967
#endif
1968
        {
1969
                if (ifa->ifa_addr == NULL)
1970
                        continue;       /* just for safety */
1971
                if (ifa->ifa_addr->sa_family != AF_INET6)
1972
                        continue;
1973
                ifacount++;
1974
        }
1975
 
1976
        ia->ia_addr = *sin6;
1977
 
1978
        if (ifacount <= 1 && ifp->if_ioctl &&
1979
            (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
1980
                splx(s);
1981
                return(error);
1982
        }
1983
        splx(s);
1984
 
1985
        ia->ia_ifa.ifa_metric = ifp->if_metric;
1986
 
1987
        /* we could do in(6)_socktrim here, but just omit it at this moment. */
1988
 
1989
        /*
1990
         * Special case:
1991
         * If the destination address is specified for a point-to-point
1992
         * interface, install a route to the destination as an interface
1993
         * direct route.
1994
         */
1995
        plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
1996
        if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) {
1997
                if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
1998
                                    RTF_UP | RTF_HOST)) != 0)
1999
                        return(error);
2000
                ia->ia_flags |= IFA_ROUTE;
2001
        }
2002
        if (plen < 128) {
2003
                /*
2004
                 * The RTF_CLONING flag is necessary for in6_is_ifloop_auto().
2005
                 */
2006
                ia->ia_ifa.ifa_flags |= RTF_CLONING;
2007
        }
2008
 
2009
        /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
2010
        if (newhost) {
2011
                /* set the rtrequest function to create llinfo */
2012
                ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
2013
                in6_ifaddloop(&(ia->ia_ifa));
2014
        }
2015
 
2016
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2017
        if (ifp->if_flags & IFF_MULTICAST)
2018
                in6_restoremkludge(ia, ifp);
2019
#endif
2020
 
2021
        return(error);
2022
}
2023
 
2024
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2025
/*
2026
 * Multicast address kludge:
2027
 * If there were any multicast addresses attached to this interface address,
2028
 * either move them to another address on this interface, or save them until
2029
 * such time as this interface is reconfigured for IPv6.
2030
 */
2031
void
2032
in6_savemkludge(oia)
2033
        struct in6_ifaddr *oia;
2034
{
2035
        struct in6_ifaddr *ia;
2036
        struct in6_multi *in6m, *next;
2037
 
2038
        IFP_TO_IA6(oia->ia_ifp, ia);
2039
        if (ia) {       /* there is another address */
2040
                for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){
2041
                        next = in6m->in6m_entry.le_next;
2042
                        IFAFREE(&in6m->in6m_ia->ia_ifa);
2043
                        IFAREF(&ia->ia_ifa);
2044
                        in6m->in6m_ia = ia;
2045
                        LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
2046
                }
2047
        } else {        /* last address on this if deleted, save */
2048
                struct multi6_kludge *mk;
2049
 
2050
                for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
2051
                        if (mk->mk_ifp == oia->ia_ifp)
2052
                                break;
2053
                }
2054
                if (mk == NULL) /* this should not happen! */
2055
                        panic("in6_savemkludge: no kludge space");
2056
 
2057
                for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){
2058
                        next = in6m->in6m_entry.le_next;
2059
                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
2060
                        in6m->in6m_ia = NULL;
2061
                        LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
2062
                }
2063
        }
2064
}
2065
 
2066
/*
2067
 * Continuation of multicast address hack:
2068
 * If there was a multicast group list previously saved for this interface,
2069
 * then we re-attach it to the first address configured on the i/f.
2070
 */
2071
void
2072
in6_restoremkludge(ia, ifp)
2073
        struct in6_ifaddr *ia;
2074
        struct ifnet *ifp;
2075
{
2076
        struct multi6_kludge *mk;
2077
 
2078
        for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
2079
                if (mk->mk_ifp == ifp) {
2080
                        struct in6_multi *in6m, *next;
2081
 
2082
                        for (in6m = mk->mk_head.lh_first; in6m; in6m = next) {
2083
                                next = in6m->in6m_entry.le_next;
2084
                                in6m->in6m_ia = ia;
2085
                                IFAREF(&ia->ia_ifa);
2086
                                LIST_INSERT_HEAD(&ia->ia6_multiaddrs,
2087
                                                 in6m, in6m_entry);
2088
                        }
2089
                        LIST_INIT(&mk->mk_head);
2090
                        break;
2091
                }
2092
        }
2093
}
2094
 
2095
/*
2096
 * Allocate space for the kludge at interface initialization time.
2097
 * Formerly, we dynamically allocated the space in in6_savemkludge() with
2098
 * malloc(M_WAITOK).  However, it was wrong since the function could be called
2099
 * under an interrupt context (software timer on address lifetime expiration).
2100
 * Also, we cannot just give up allocating the strucutre, since the group
2101
 * membership structure is very complex and we need to keep it anyway.
2102
 * Of course, this function MUST NOT be called under an interrupt context.
2103
 * Specifically, it is expected to be called only from in6_ifattach(), though
2104
 * it is a global function.
2105
 */
2106
void
2107
in6_createmkludge(ifp)
2108
        struct ifnet *ifp;
2109
{
2110
        struct multi6_kludge *mk;
2111
 
2112
        for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
2113
                /* If we've already had one, do not allocate. */
2114
                if (mk->mk_ifp == ifp)
2115
                        return;
2116
        }
2117
 
2118
        mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK);
2119
 
2120
        bzero(mk, sizeof(*mk));
2121
        LIST_INIT(&mk->mk_head);
2122
        mk->mk_ifp = ifp;
2123
        LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);
2124
}
2125
 
2126
void
2127
in6_purgemkludge(ifp)
2128
        struct ifnet *ifp;
2129
{
2130
        struct multi6_kludge *mk;
2131
        struct in6_multi *in6m;
2132
 
2133
        for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
2134
                if (mk->mk_ifp != ifp)
2135
                        continue;
2136
 
2137
                /* leave from all multicast groups joined */
2138
                while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL)
2139
                        in6_delmulti(in6m);
2140
                LIST_REMOVE(mk, mk_entry);
2141
                free(mk, M_IPMADDR);
2142
                break;
2143
        }
2144
}
2145
 
2146
/*
2147
 * Add an address to the list of IP6 multicast addresses for a
2148
 * given interface.
2149
 */
2150
struct  in6_multi *
2151
in6_addmulti(maddr6, ifp, errorp)
2152
        struct in6_addr *maddr6;
2153
        struct ifnet *ifp;
2154
        int *errorp;
2155
{
2156
        struct  in6_ifaddr *ia;
2157
        struct  in6_ifreq ifr;
2158
        struct  in6_multi *in6m;
2159
#ifdef __NetBSD__
2160
        int     s = splsoftnet();
2161
#else
2162
        int     s = splnet();
2163
#endif
2164
 
2165
        *errorp = 0;
2166
        /*
2167
         * See if address already in list.
2168
         */
2169
        IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
2170
        if (in6m != NULL) {
2171
                /*
2172
                 * Found it; just increment the refrence count.
2173
                 */
2174
                in6m->in6m_refcount++;
2175
        } else {
2176
                /*
2177
                 * New address; allocate a new multicast record
2178
                 * and link it into the interface's multicast list.
2179
                 */
2180
                in6m = (struct in6_multi *)
2181
                        malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
2182
                if (in6m == NULL) {
2183
                        splx(s);
2184
                        *errorp = ENOBUFS;
2185
                        return(NULL);
2186
                }
2187
                in6m->in6m_addr = *maddr6;
2188
                in6m->in6m_ifp = ifp;
2189
                in6m->in6m_refcount = 1;
2190
                IFP_TO_IA6(ifp, ia);
2191
                if (ia == NULL) {
2192
                        free(in6m, M_IPMADDR);
2193
                        splx(s);
2194
                        *errorp = EADDRNOTAVAIL; /* appropriate? */
2195
                        return(NULL);
2196
                }
2197
                in6m->in6m_ia = ia;
2198
                IFAREF(&ia->ia_ifa); /* gain a reference */
2199
                LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
2200
 
2201
                /*
2202
                 * Ask the network driver to update its multicast reception
2203
                 * filter appropriately for the new address.
2204
                 */
2205
                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
2206
                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
2207
                ifr.ifr_addr.sin6_family = AF_INET6;
2208
                ifr.ifr_addr.sin6_addr = *maddr6;
2209
                if (ifp->if_ioctl == NULL)
2210
                        *errorp = ENXIO; /* XXX: appropriate? */
2211
                else
2212
                        *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,
2213
                                                    (caddr_t)&ifr);
2214
                if (*errorp) {
2215
                        LIST_REMOVE(in6m, in6m_entry);
2216
                        free(in6m, M_IPMADDR);
2217
                        IFAFREE(&ia->ia_ifa);
2218
                        splx(s);
2219
                        return(NULL);
2220
                }
2221
                /*
2222
                 * Let MLD6 know that we have joined a new IP6 multicast
2223
                 * group.
2224
                 */
2225
                mld6_start_listening(in6m);
2226
        }
2227
        splx(s);
2228
        return(in6m);
2229
}
2230
 
2231
/*
2232
 * Delete a multicast address record.
2233
 */
2234
void
2235
in6_delmulti(in6m)
2236
        struct in6_multi *in6m;
2237
{
2238
        struct  in6_ifreq ifr;
2239
#ifdef __NetBSD__
2240
        int     s = splsoftnet();
2241
#else
2242
        int     s = splnet();
2243
#endif
2244
 
2245
        if (--in6m->in6m_refcount == 0) {
2246
                /*
2247
                 * No remaining claims to this record; let MLD6 know
2248
                 * that we are leaving the multicast group.
2249
                 */
2250
                mld6_stop_listening(in6m);
2251
 
2252
                /*
2253
                 * Unlink from list.
2254
                 */
2255
                LIST_REMOVE(in6m, in6m_entry);
2256
                if (in6m->in6m_ia) {
2257
                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
2258
                }
2259
 
2260
                /*
2261
                 * Notify the network driver to update its multicast
2262
                 * reception filter.
2263
                 */
2264
                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
2265
                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
2266
                ifr.ifr_addr.sin6_family = AF_INET6;
2267
                ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
2268
                (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp,
2269
                                            SIOCDELMULTI, (caddr_t)&ifr);
2270
                free(in6m, M_IPMADDR);
2271
        }
2272
        splx(s);
2273
}
2274
#else /* not FreeBSD3 */
2275
/*
2276
 * Add an address to the list of IP6 multicast addresses for a
2277
 * given interface.
2278
 */
2279
struct  in6_multi *
2280
in6_addmulti(maddr6, ifp, errorp)
2281
        struct in6_addr *maddr6;
2282
        struct ifnet *ifp;
2283
        int *errorp;
2284
{
2285
        struct  in6_multi *in6m;
2286
        struct sockaddr_in6 sin6;
2287
        struct ifmultiaddr *ifma;
2288
        int     s = splnet();
2289
 
2290
        *errorp = 0;
2291
 
2292
        /*
2293
         * Call generic routine to add membership or increment
2294
         * refcount.  It wants addresses in the form of a sockaddr,
2295
         * so we build one here (being careful to zero the unused bytes).
2296
         */
2297
        bzero(&sin6, sizeof sin6);
2298
        sin6.sin6_family = AF_INET6;
2299
        sin6.sin6_len = sizeof sin6;
2300
        sin6.sin6_addr = *maddr6;
2301
        *errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma);
2302
        if (*errorp) {
2303
                splx(s);
2304
                return 0;
2305
        }
2306
 
2307
        /*
2308
         * If ifma->ifma_protospec is null, then if_addmulti() created
2309
         * a new record.  Otherwise, we are done.
2310
         */
2311
        if (ifma->ifma_protospec != 0)
2312
                return ifma->ifma_protospec;
2313
 
2314
        /* XXX - if_addmulti uses M_WAITOK.  Can this really be called
2315
           at interrupt time?  If so, need to fix if_addmulti. XXX */
2316
        in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
2317
        if (in6m == NULL) {
2318
                splx(s);
2319
                return (NULL);
2320
        }
2321
 
2322
        bzero(in6m, sizeof *in6m);
2323
        in6m->in6m_addr = *maddr6;
2324
        in6m->in6m_ifp = ifp;
2325
        in6m->in6m_ifma = ifma;
2326
        ifma->ifma_protospec = in6m;
2327
        LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry);
2328
 
2329
        /*
2330
         * Let MLD6 know that we have joined a new IP6 multicast
2331
         * group.
2332
         */
2333
        mld6_start_listening(in6m);
2334
        splx(s);
2335
        return(in6m);
2336
}
2337
 
2338
/*
2339
 * Delete a multicast address record.
2340
 */
2341
void
2342
in6_delmulti(in6m)
2343
        struct in6_multi *in6m;
2344
{
2345
        struct ifmultiaddr *ifma = in6m->in6m_ifma;
2346
        int     s = splnet();
2347
 
2348
        if (ifma->ifma_refcount == 1) {
2349
                /*
2350
                 * No remaining claims to this record; let MLD6 know
2351
                 * that we are leaving the multicast group.
2352
                 */
2353
                mld6_stop_listening(in6m);
2354
                ifma->ifma_protospec = 0;
2355
                LIST_REMOVE(in6m, in6m_entry);
2356
                free(in6m, M_IPMADDR);
2357
        }
2358
        /* XXX - should be separate API for when we have an ifma? */
2359
        if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
2360
        splx(s);
2361
}
2362
#endif /* not FreeBSD3 */
2363
 
2364
struct in6_multi_mship *
2365
in6_joingroup(ifp, addr, errorp)
2366
        struct ifnet *ifp;
2367
        struct in6_addr *addr;
2368
        int *errorp;
2369
{
2370
        struct in6_multi_mship *imm;
2371
 
2372
        imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
2373
        if (!imm) {
2374
                *errorp = ENOBUFS;
2375
                return NULL;
2376
        }
2377
        imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
2378
        if (!imm->i6mm_maddr) {
2379
                /* *errorp is alrady set */
2380
                free(imm, M_IPMADDR);
2381
                return NULL;
2382
        }
2383
        return imm;
2384
}
2385
 
2386
int
2387
in6_leavegroup(imm)
2388
        struct in6_multi_mship *imm;
2389
{
2390
 
2391
        if (imm->i6mm_maddr)
2392
                in6_delmulti(imm->i6mm_maddr);
2393
        free(imm,  M_IPMADDR);
2394
        return 0;
2395
}
2396
 
2397
/*
2398
 * Find an IPv6 interface link-local address specific to an interface.
2399
 */
2400
struct in6_ifaddr *
2401
in6ifa_ifpforlinklocal(ifp, ignoreflags)
2402
        struct ifnet *ifp;
2403
        int ignoreflags;
2404
{
2405
        struct ifaddr *ifa;
2406
 
2407
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2408
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
2409
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
2410
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2411
#else
2412
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
2413
#endif
2414
        {
2415
                if (ifa->ifa_addr == NULL)
2416
                        continue;       /* just for safety */
2417
                if (ifa->ifa_addr->sa_family != AF_INET6)
2418
                        continue;
2419
                if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
2420
                        if ((((struct in6_ifaddr *)ifa)->ia6_flags &
2421
                             ignoreflags) != 0)
2422
                                continue;
2423
                        break;
2424
                }
2425
        }
2426
 
2427
        return((struct in6_ifaddr *)ifa);
2428
}
2429
 
2430
 
2431
/*
2432
 * find the internet address corresponding to a given interface and address.
2433
 */
2434
static struct in6_ifaddr *
2435
_in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
2436
{
2437
        struct ifaddr *ifa;
2438
 
2439
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2440
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
2441
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
2442
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2443
#else
2444
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
2445
#endif
2446
        {
2447
                if (ifa->ifa_addr == NULL)
2448
                        continue;       /* just for safety */
2449
                if (ifa->ifa_addr->sa_family != AF_INET6)
2450
                        continue;
2451
                if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
2452
                        break;
2453
        }
2454
 
2455
        return((struct in6_ifaddr *)ifa);
2456
}
2457
 
2458
struct in6_ifaddr *
2459
in6ifa_ifpwithaddr(ifp, addr)
2460
        struct ifnet *ifp;
2461
        struct in6_addr *addr;
2462
{
2463
    struct in6_ifaddr *_ifa = _in6ifa_ifpwithaddr(ifp, addr);
2464
#if 0
2465
    if (!_ifa) {
2466
        struct ifaddr *ifa;
2467
 
2468
        diag_printf("%s\n", __FUNCTION__);
2469
        diag_dump_buf(addr, 16);
2470
        diag_printf("==============================================================\n");
2471
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2472
        {
2473
                if (ifa->ifa_addr == NULL)
2474
                        continue;       /* just for safety */
2475
                if (ifa->ifa_addr->sa_family != AF_INET6)
2476
                        continue;
2477
                diag_dump_buf(IFA_IN6(ifa), 16);
2478
                diag_printf("--------------------------------------------------------------\n");
2479
        }
2480
    }
2481
#endif
2482
    return(_ifa);
2483
}
2484
 
2485
/*
2486
 * Convert IP6 address to printable (loggable) representation.
2487
 */
2488
static char digits[] = "0123456789abcdef";
2489
static int ip6round = 0;
2490
char *
2491
ip6_sprintf(addr)
2492
        const struct in6_addr *addr;
2493
{
2494
        static char ip6buf[8][48];
2495
        int i;
2496
        char *cp;
2497
        const u_short *a = (const u_short *)addr;
2498
        const u_char *d;
2499
        int dcolon = 0;
2500
 
2501
        ip6round = (ip6round + 1) & 7;
2502
        cp = ip6buf[ip6round];
2503
 
2504
        for (i = 0; i < 8; i++) {
2505
                if (dcolon == 1) {
2506
                        if (*a == 0) {
2507
                                if (i == 7)
2508
                                        *cp++ = ':';
2509
                                a++;
2510
                                continue;
2511
                        } else
2512
                                dcolon = 2;
2513
                }
2514
                if (*a == 0) {
2515
                        if (dcolon == 0 && *(a + 1) == 0) {
2516
                                if (i == 0)
2517
                                        *cp++ = ':';
2518
                                *cp++ = ':';
2519
                                dcolon = 1;
2520
                        } else {
2521
                                *cp++ = '0';
2522
                                *cp++ = ':';
2523
                        }
2524
                        a++;
2525
                        continue;
2526
                }
2527
                d = (const u_char *)a;
2528
                *cp++ = digits[*d >> 4];
2529
                *cp++ = digits[*d++ & 0xf];
2530
                *cp++ = digits[*d >> 4];
2531
                *cp++ = digits[*d & 0xf];
2532
                *cp++ = ':';
2533
                a++;
2534
        }
2535
        *--cp = 0;
2536
        return(ip6buf[ip6round]);
2537
}
2538
 
2539
int
2540
in6_localaddr(in6)
2541
        struct in6_addr *in6;
2542
{
2543
        struct in6_ifaddr *ia;
2544
 
2545
        if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
2546
                return 1;
2547
 
2548
        for (ia = in6_ifaddr; ia; ia = ia->ia_next)
2549
                if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
2550
                                              &ia->ia_prefixmask.sin6_addr))
2551
                        return 1;
2552
 
2553
        return (0);
2554
}
2555
 
2556
int
2557
in6_is_addr_deprecated(sa6)
2558
        struct sockaddr_in6 *sa6;
2559
{
2560
        struct in6_ifaddr *ia;
2561
 
2562
        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
2563
                if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
2564
                                       &sa6->sin6_addr) &&
2565
#ifdef SCOPEDROUTING
2566
                    ia->ia_addr.sin6_scope_id == sa6->sin6_scope_id &&
2567
#endif
2568
                    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
2569
                        return(1); /* true */
2570
 
2571
                /* XXX: do we still have to go thru the rest of the list? */
2572
        }
2573
 
2574
        return(0);               /* false */
2575
}
2576
 
2577
/*
2578
 * return length of part which dst and src are equal
2579
 * hard coding...
2580
 */
2581
int
2582
in6_matchlen(src, dst)
2583
struct in6_addr *src, *dst;
2584
{
2585
        int match = 0;
2586
        u_char *s = (u_char *)src, *d = (u_char *)dst;
2587
        u_char *lim = s + 16, r;
2588
 
2589
        while (s < lim)
2590
                if ((r = (*d++ ^ *s++)) != 0) {
2591
                        while (r < 128) {
2592
                                match++;
2593
                                r <<= 1;
2594
                        }
2595
                        break;
2596
                } else
2597
                        match += 8;
2598
        return match;
2599
}
2600
 
2601
/* XXX: to be scope conscious */
2602
int
2603
in6_are_prefix_equal(p1, p2, len)
2604
        struct in6_addr *p1, *p2;
2605
        int len;
2606
{
2607
        int bytelen, bitlen;
2608
 
2609
        /* sanity check */
2610
        if (0 > len || len > 128) {
2611
                log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
2612
                    len);
2613
                return(0);
2614
        }
2615
 
2616
        bytelen = len / 8;
2617
        bitlen = len % 8;
2618
 
2619
        if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
2620
                return(0);
2621
        if (p1->s6_addr[bytelen] >> (8 - bitlen) !=
2622
            p2->s6_addr[bytelen] >> (8 - bitlen))
2623
                return(0);
2624
 
2625
        return(1);
2626
}
2627
 
2628
void
2629
in6_prefixlen2mask(maskp, len)
2630
        struct in6_addr *maskp;
2631
        int len;
2632
{
2633
        u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
2634
        int bytelen, bitlen, i;
2635
 
2636
        /* sanity check */
2637
        if (0 > len || len > 128) {
2638
                log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
2639
                    len);
2640
                return;
2641
        }
2642
 
2643
        bzero(maskp, sizeof(*maskp));
2644
        bytelen = len / 8;
2645
        bitlen = len % 8;
2646
        for (i = 0; i < bytelen; i++)
2647
                maskp->s6_addr[i] = 0xff;
2648
        if (bitlen)
2649
                maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
2650
}
2651
 
2652
/*
2653
 * return the best address out of the same scope. if no address was
2654
 * found, return the first valid address from designated IF.
2655
 */
2656
struct in6_ifaddr *
2657
in6_ifawithifp(ifp, dst)
2658
        struct ifnet *ifp;
2659
        struct in6_addr *dst;
2660
{
2661
        int dst_scope = in6_addrscope(dst), blen = -1, tlen;
2662
        struct ifaddr *ifa;
2663
        struct in6_ifaddr *besta = 0;
2664
        struct in6_ifaddr *dep[2];      /* last-resort: deprecated */
2665
 
2666
        dep[0] = dep[1] = NULL;
2667
 
2668
        /*
2669
         * We first look for addresses in the same scope.
2670
         * If there is one, return it.
2671
         * If two or more, return one which matches the dst longest.
2672
         * If none, return one of global addresses assigned other ifs.
2673
         */
2674
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2675
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
2676
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
2677
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2678
#else
2679
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
2680
#endif
2681
        {
2682
                if (ifa->ifa_addr->sa_family != AF_INET6)
2683
                        continue;
2684
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
2685
                        continue; /* XXX: is there any case to allow anycast? */
2686
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
2687
                        continue; /* don't use this interface */
2688
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
2689
                        continue;
2690
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2691
                        if (ip6_use_deprecated)
2692
                                dep[0] = (struct in6_ifaddr *)ifa;
2693
                        continue;
2694
                }
2695
 
2696
                if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
2697
                        /*
2698
                         * call in6_matchlen() as few as possible
2699
                         */
2700
                        if (besta) {
2701
                                if (blen == -1)
2702
                                        blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
2703
                                tlen = in6_matchlen(IFA_IN6(ifa), dst);
2704
                                if (tlen > blen) {
2705
                                        blen = tlen;
2706
                                        besta = (struct in6_ifaddr *)ifa;
2707
                                }
2708
                        } else
2709
                                besta = (struct in6_ifaddr *)ifa;
2710
                }
2711
        }
2712
        if (besta)
2713
                return(besta);
2714
 
2715
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2716
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
2717
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
2718
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2719
#else
2720
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
2721
#endif
2722
        {
2723
                if (ifa->ifa_addr->sa_family != AF_INET6)
2724
                        continue;
2725
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
2726
                        continue; /* XXX: is there any case to allow anycast? */
2727
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
2728
                        continue; /* don't use this interface */
2729
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
2730
                        continue;
2731
                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
2732
                        if (ip6_use_deprecated)
2733
                                dep[1] = (struct in6_ifaddr *)ifa;
2734
                        continue;
2735
                }
2736
 
2737
                return (struct in6_ifaddr *)ifa;
2738
        }
2739
 
2740
        /* use the last-resort values, that are, deprecated addresses */
2741
        if (dep[0])
2742
                return dep[0];
2743
        if (dep[1])
2744
                return dep[1];
2745
 
2746
        return NULL;
2747
}
2748
 
2749
/*
2750
 * perform DAD when interface becomes IFF_UP.
2751
 */
2752
void
2753
in6_if_up(ifp)
2754
        struct ifnet *ifp;
2755
{
2756
        struct ifaddr *ifa;
2757
        struct in6_ifaddr *ia;
2758
        int dad_delay;          /* delay ticks before DAD output */
2759
 
2760
        /*
2761
         * special cases, like 6to4, are handled in in6_ifattach
2762
         */
2763
        in6_ifattach(ifp, NULL);
2764
 
2765
        dad_delay = 0;
2766
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2767
        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
2768
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
2769
        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
2770
#else
2771
        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
2772
#endif
2773
        {
2774
                if (ifa->ifa_addr->sa_family != AF_INET6)
2775
                        continue;
2776
                ia = (struct in6_ifaddr *)ifa;
2777
                if (ia->ia6_flags & IN6_IFF_TENTATIVE)
2778
                        nd6_dad_start(ifa, &dad_delay);
2779
        }
2780
}
2781
 
2782
int
2783
in6if_do_dad(ifp)
2784
        struct ifnet *ifp;
2785
{
2786
        if ((ifp->if_flags & IFF_LOOPBACK) != 0)
2787
                return(0);
2788
 
2789
        switch (ifp->if_type) {
2790
#ifdef IFT_DUMMY
2791
        case IFT_DUMMY:
2792
#endif
2793
        case IFT_FAITH:
2794
                /*
2795
                 * These interfaces do not have the IFF_LOOPBACK flag,
2796
                 * but loop packets back.  We do not have to do DAD on such
2797
                 * interfaces.  We should even omit it, because loop-backed
2798
                 * NS would confuse the DAD procedure.
2799
                 */
2800
                return(0);
2801
        default:
2802
                /*
2803
                 * Our DAD routine requires the interface up and running.
2804
                 * However, some interfaces can be up before the RUNNING
2805
                 * status.  Additionaly, users may try to assign addresses
2806
                 * before the interface becomes up (or running).
2807
                 * We simply skip DAD in such a case as a work around.
2808
                 * XXX: we should rather mark "tentative" on such addresses,
2809
                 * and do DAD after the interface becomes ready.
2810
                 */
2811
                if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) !=
2812
                    (IFF_UP|IFF_RUNNING))
2813
                        return(0);
2814
 
2815
                return(1);
2816
        }
2817
}
2818
 
2819
/*
2820
 * Calculate max IPv6 MTU through all the interfaces and store it
2821
 * to in6_maxmtu.
2822
 */
2823
void
2824
in6_setmaxmtu()
2825
{
2826
        unsigned long maxmtu = 0;
2827
        struct ifnet *ifp;
2828
 
2829
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
2830
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
2831
#else
2832
        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
2833
#endif
2834
        {
2835
                if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
2836
                    nd_ifinfo[ifp->if_index].linkmtu > maxmtu)
2837
                        maxmtu =  nd_ifinfo[ifp->if_index].linkmtu;
2838
        }
2839
        if (maxmtu)     /* update only when maxmtu is positive */
2840
                in6_maxmtu = maxmtu;
2841
}
2842
 
2843
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2844
/*
2845
 * Convert sockaddr_in6 to sockaddr_in.  Original sockaddr_in6 must be
2846
 * v4 mapped addr or v4 compat addr
2847
 */
2848
void
2849
in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
2850
{
2851
        bzero(sin, sizeof(*sin));
2852
        sin->sin_len = sizeof(struct sockaddr_in);
2853
        sin->sin_family = AF_INET;
2854
        sin->sin_port = sin6->sin6_port;
2855
        sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
2856
}
2857
 
2858
/* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */
2859
void
2860
in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
2861
{
2862
        bzero(sin6, sizeof(*sin6));
2863
        sin6->sin6_len = sizeof(struct sockaddr_in6);
2864
        sin6->sin6_family = AF_INET6;
2865
        sin6->sin6_port = sin->sin_port;
2866
        sin6->sin6_addr.s6_addr32[0] = 0;
2867
        sin6->sin6_addr.s6_addr32[1] = 0;
2868
        sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP;
2869
        sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
2870
}
2871
 
2872
/* Convert sockaddr_in6 into sockaddr_in. */
2873
void
2874
in6_sin6_2_sin_in_sock(struct sockaddr *nam)
2875
{
2876
        struct sockaddr_in *sin_p;
2877
        struct sockaddr_in6 sin6;
2878
 
2879
        /*
2880
         * Save original sockaddr_in6 addr and convert it
2881
         * to sockaddr_in.
2882
         */
2883
        sin6 = *(struct sockaddr_in6 *)nam;
2884
        sin_p = (struct sockaddr_in *)nam;
2885
        in6_sin6_2_sin(sin_p, &sin6);
2886
}
2887
 
2888
/* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */
2889
void
2890
in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam)
2891
{
2892
        struct sockaddr_in *sin_p;
2893
        struct sockaddr_in6 *sin6_p;
2894
 
2895
        MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
2896
               M_WAITOK);
2897
        sin_p = (struct sockaddr_in *)*nam;
2898
        in6_sin_2_v4mapsin6(sin_p, sin6_p);
2899
        FREE(*nam, M_SONAME);
2900
        *nam = (struct sockaddr *)sin6_p;
2901
}
2902
#endif /* freebsd3 */
2903
 
2904
#ifdef MEASURE_PERFORMANCE
2905
#define IN6_MAXADDRHASH 1000
2906
#ifndef IN6_ADDRHASH
2907
#ifndef INET6_SERVER
2908
#define IN6_ADDRHASH    23
2909
#else
2910
#define IN6_ADDRHASH    997
2911
#endif
2912
#endif
2913
 
2914
static struct in6hash in6h_hash_any = { NULL, IN6ADDR_ANY_INIT, NULL, 0 };
2915
struct in6hash *in6hash[IN6_MAXADDRHASH];/* hash buckets for local IPv6 addrs */
2916
int in6_nhash = IN6_ADDRHASH;           /* number of hash buckets for addrs */
2917
int in6_hash_nullhit;
2918
 
2919
#define HASH6(in6) ((in6)->s6_addr32[0]^(in6)->s6_addr32[1]^\
2920
        (in6)->s6_addr32[2]^(in6)->s6_addr32[3])
2921
 
2922
/*
2923
 * Initialize the hash by adding entries for IN6ADDR_ANY
2924
 */
2925
struct in6hash *ih_cache = NULL;
2926
 
2927
void
2928
in6h_hashinit()
2929
{
2930
        in6h_addhash(&in6h_hash_any);
2931
}
2932
 
2933
void
2934
in6h_addifa(ia)
2935
        struct in6_ifaddr *ia;
2936
{
2937
        if (ia->ia6_hash.in6h_ifa == NULL)
2938
                ia->ia6_hash.in6h_ifa = ia;
2939
 
2940
        ia->ia6_hash.in6h_addr = IA6_SIN6(ia)->sin6_addr; /* scope? */
2941
        if (IN6_IS_ADDR_UNSPECIFIED(&ia->ia6_hash.in6h_addr))
2942
                return;
2943
        in6h_addhash(&ia->ia6_hash);
2944
}
2945
 
2946
/*
2947
 * Rebuild the hash when any interface addresses have been changed.
2948
 * Since this should happen infrequently we remove all the interfaces
2949
 * from the hash and add them all back.  This insures that the order
2950
 * of addresses in the hash is consistent.
2951
 */
2952
void
2953
in6h_rebuild(newhashsiz)
2954
        int newhashsiz;         /* can be 0, meaning unchange the size */
2955
{
2956
        struct in6_ifaddr *ia;
2957
 
2958
        if (newhashsiz > IN6_MAXADDRHASH)
2959
                return;         /* XXX invalid */
2960
 
2961
        for (ia = in6_ifaddr; ia != NULL; ia = ia->ia_next)
2962
                in6h_delifa(ia);
2963
 
2964
        if (newhashsiz)
2965
                in6_nhash = newhashsiz;
2966
 
2967
        for (ia = in6_ifaddr; ia != NULL; ia = ia->ia_next)
2968
                in6h_addifa(ia);
2969
}
2970
 
2971
/* Remove hash entries for local address on an in6_ifaddr. */
2972
void
2973
in6h_delifa(ia)
2974
        struct in6_ifaddr *ia;
2975
{
2976
        if (IN6_IS_ADDR_UNSPECIFIED(&ia->ia6_hash.in6h_addr))
2977
                return;
2978
        in6h_delhash(&ia->ia6_hash);
2979
        ia->ia6_hash.in6h_addr = in6addr_any;
2980
}
2981
 
2982
static void
2983
in6h_addhash(ih)
2984
        struct in6hash *ih;
2985
{
2986
        struct in6hash **prev;
2987
 
2988
        /* Add to tail of hash list, as address is at end of address list */
2989
        for (prev = &in6hash[HASH6(&ih->in6h_addr) % in6_nhash]; *prev;
2990
             prev = &((*prev)->in6h_next)) {
2991
                /* however, we always prefer non-global addresses */
2992
                if (IN6_IS_ADDR_LINKLOCAL(&(*prev)->in6h_addr))
2993
                        break;
2994
        }
2995
        ih->in6h_next = *prev;
2996
        *prev = ih;
2997
}
2998
 
2999
static void
3000
in6h_delhash(ih)
3001
        struct in6hash *ih;
3002
{
3003
        struct in6hash **prev;
3004
 
3005
        ih_cache = NULL;
3006
 
3007
        for (prev = &in6hash[HASH6(&ih->in6h_addr) % in6_nhash];
3008
             *prev != ih; prev = &((*prev)->in6h_next)) {
3009
#ifdef DEBUG
3010
                if (*prev == NULL)
3011
                        panic("in6h_delhash: lost entry");
3012
#endif
3013
        }
3014
        *prev = (*prev)->in6h_next;
3015
}
3016
 
3017
/*
3018
 * Look up hash structure for specified IP address
3019
 * and (optional) interface; matches any interface
3020
 * if ifp is null, or this address is not associated
3021
 * with the specified interface.
3022
 */
3023
struct in6hash *
3024
in6h_lookup(addr, ifp)
3025
        const struct in6_addr *addr;
3026
        struct ifnet *ifp;
3027
{
3028
        struct in6hash *ih, *maybe_ih = NULL;
3029
 
3030
        /* just for measurement */
3031
        if ((ih = in6hash[HASH6(addr) % in6_nhash]) == NULL)
3032
                in6_hash_nullhit++;
3033
 
3034
        for (; ih; ih = ih->in6h_next) {
3035
                if (IN6_ARE_ADDR_EQUAL(&ih->in6h_addr, addr)) {
3036
                        ih->in6h_hit++;
3037
 
3038
                        if (ih->in6h_ifa == NULL ||
3039
                            ih->in6h_ifa->ia_ifp == ifp || ifp == NULL) {
3040
                                ih_cache = ih;
3041
                                return (ih);
3042
                        }
3043
                        if (maybe_ih == NULL)
3044
                                maybe_ih = ih;
3045
                }
3046
                else
3047
                        ih->in6h_miss++;
3048
        }
3049
        if (maybe_ih)
3050
                ih_cache = maybe_ih;
3051
        return (maybe_ih);
3052
}
3053
#endif /* MEASURE_PERFORMANCE */

powered by: WebSVN 2.1.0

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