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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [netinet6/] [in6_src.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/sys/netinet6/in6_src.c
4
//
5
//==========================================================================
6
// ####BSDCOPYRIGHTBEGIN####                                    
7
// -------------------------------------------                  
8
// This file is part of eCos, the Embedded Configurable Operating System.
9
//
10
// Portions of this software may have been derived from FreeBSD 
11
// or other sources, and if so are covered by the appropriate copyright
12
// and license included herein.                                 
13
//
14
// Portions created by the Free Software Foundation are         
15
// Copyright (C) 2002 Free Software Foundation, Inc.            
16
// -------------------------------------------                  
17
// ####BSDCOPYRIGHTEND####                                      
18
//==========================================================================
19
 
20
/*      $KAME: in6_src.c,v 1.96 2001/12/24 10:39:29 jinmei Exp $        */
21
 
22
/*
23
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
24
 * All rights reserved.
25
 *
26
 * Redistribution and use in source and binary forms, with or without
27
 * modification, are permitted provided that the following conditions
28
 * are met:
29
 * 1. Redistributions of source code must retain the above copyright
30
 *    notice, this list of conditions and the following disclaimer.
31
 * 2. Redistributions in binary form must reproduce the above copyright
32
 *    notice, this list of conditions and the following disclaimer in the
33
 *    documentation and/or other materials provided with the distribution.
34
 * 3. Neither the name of the project nor the names of its contributors
35
 *    may be used to endorse or promote products derived from this software
36
 *    without specific prior written permission.
37
 *
38
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
39
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
42
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
 * SUCH DAMAGE.
49
 */
50
 
51
/*
52
 * Copyright (c) 1982, 1986, 1991, 1993
53
 *      The Regents of the University of California.  All rights reserved.
54
 *
55
 * Redistribution and use in source and binary forms, with or without
56
 * modification, are permitted provided that the following conditions
57
 * are met:
58
 * 1. Redistributions of source code must retain the above copyright
59
 *    notice, this list of conditions and the following disclaimer.
60
 * 2. Redistributions in binary form must reproduce the above copyright
61
 *    notice, this list of conditions and the following disclaimer in the
62
 *    documentation and/or other materials provided with the distribution.
63
 * 3. All advertising materials mentioning features or use of this software
64
 *    must display the following acknowledgement:
65
 *      This product includes software developed by the University of
66
 *      California, Berkeley and its contributors.
67
 * 4. Neither the name of the University nor the names of its contributors
68
 *    may be used to endorse or promote products derived from this software
69
 *    without specific prior written permission.
70
 *
71
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
72
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
74
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
75
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
76
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
77
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
78
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
79
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
80
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
81
 * SUCH DAMAGE.
82
 *
83
 *      @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
84
 */
85
 
86
#include <sys/param.h>
87
#include <sys/malloc.h>
88
#include <sys/mbuf.h>
89
#include <sys/protosw.h>
90
#include <sys/socket.h>
91
#include <sys/socketvar.h>
92
#include <sys/sockio.h>
93
#include <sys/errno.h>
94
 
95
#include <net/if.h>
96
#include <net/route.h>
97
 
98
#include <netinet/in.h>
99
#include <netinet/in_var.h>
100
#include <netinet/in_systm.h>
101
#include <netinet/ip.h>
102
#include <netinet/in_pcb.h>
103
#include <netinet6/in6_var.h>
104
#include <netinet/ip6.h>
105
#include <netinet6/ip6_var.h>
106
#include <netinet6/in6_pcb.h>
107
#include <netinet6/nd6.h>
108
#include <netinet6/scope6_var.h> 
109
 
110
#ifdef MIP6
111
#include <netinet6/mip6.h>
112
#endif /* MIP6 */
113
 
114
#if defined(__NetBSD__)
115
extern struct ifnet loif[NLOOP];
116
#endif
117
 
118
#define ADDR_LABEL_NOTAPP (-1)
119
struct in6_addrpolicy defaultaddrpolicy;
120
 
121
int ip6_prefer_tempaddr = 0;
122
 
123
#ifdef NEW_STRUCT_ROUTE
124
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
125
                             struct ip6_moptions *,
126
                             struct route *ro,
127
                             struct ifnet **));
128
#else
129
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
130
                             struct ip6_moptions *,
131
                             struct route_in6 *ro,
132
                             struct ifnet **));
133
#endif
134
 
135
static struct in6_addrpolicy *lookup_addrsel_policy __P((struct sockaddr_in6 *));
136
 
137
static void init_policy_queue __P((void));
138
static int add_addrsel_policyent __P((struct in6_addrpolicy *));
139
static int delete_addrsel_policyent __P((struct in6_addrpolicy *));
140
static struct in6_addrpolicy *match_addrsel_policy __P((struct sockaddr_in6 *));
141
 
142
/*
143
 * Return an IPv6 address, which is the most appropriate for a given
144
 * destination and user specified options.
145
 * If necessary, this function lookups the routing table and returns
146
 * an entry to the caller for later use.
147
 */
148
#define REPLACE(r) do {\
149
        if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
150
                sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
151
                ip6stat.ip6s_sources_rule[(r)]++; \
152
        /* printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \
153
        goto replace; \
154
} while(0)
155
#define NEXT(r) do {\
156
        if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
157
                sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
158
                ip6stat.ip6s_sources_rule[(r)]++; \
159
        /* printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \
160
        goto next;              /* XXX: we can't use 'continue' here */ \
161
} while(0)
162
#define BREAK(r) do { \
163
        if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
164
                sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
165
                ip6stat.ip6s_sources_rule[(r)]++; \
166
        goto out;               /* XXX: we can't use 'break' here */ \
167
} while(0)
168
 
169
struct in6_addr *
170
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
171
              struct ip6_moptions *mopts, struct route *ro,
172
              struct ifnet **ifpp, struct in6_addr *laddr,
173
              int *errorp)
174
{
175
        struct in6_addr *dst;
176
        struct ifnet *ifp = NULL;
177
        struct in6_ifaddr *ia = NULL, *ia_best = NULL;
178
        struct in6_pktinfo *pi = NULL;
179
        int dst_scope = -1, best_scope = -1, best_matchlen = -1;
180
        struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
181
#ifdef MIP6
182
        struct hif_softc *sc;
183
#ifdef MIP6_ALLOW_COA_FALLBACK
184
        struct mip6_bu *mbu_dst;
185
        u_int8_t coafallback = 0;
186
#endif
187
#endif
188
 
189
        dst = &dstsock->sin6_addr;
190
        *errorp = 0;
191
        if (ifpp)
192
                *ifpp = NULL;
193
 
194
        /*
195
         * If the source address is explicitly specified by the caller,
196
         * check if the requested source address is indeed a unicast address
197
         * assigned to the node, and can be used as the packet's source
198
         * address.  If everything is okay, use the address as source.
199
         */
200
        if (opts && (pi = opts->ip6po_pktinfo) &&
201
            !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
202
                struct sockaddr_in6 srcsock;
203
                struct in6_ifaddr *ia6;
204
 
205
                /* get the outgoing interface */
206
                if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))
207
                    != 0) {
208
                        return(NULL);
209
                }
210
 
211
                /*
212
                 * determine the appropriate zone id of the source based on
213
                 * the zone of the destination and the outgoing interface.
214
                 */
215
                bzero(&srcsock, sizeof(srcsock));
216
                srcsock.sin6_family = AF_INET6;
217
                srcsock.sin6_len = sizeof(srcsock);
218
                srcsock.sin6_addr = pi->ipi6_addr;
219
                if (ifp) {
220
                        int64_t zone;
221
 
222
                        zone = in6_addr2zoneid(ifp, &pi->ipi6_addr);
223
                        if (zone < 0) { /* XXX: this should not happen */
224
                                *errorp = EINVAL;
225
                                return(NULL);
226
                        }
227
                        srcsock.sin6_scope_id = zone;
228
                }
229
                if ((*errorp = in6_embedscope(&srcsock.sin6_addr, &srcsock))
230
                    != 0) {
231
                        return(NULL);
232
                }
233
#ifndef SCOPEDROUTING
234
                srcsock.sin6_scope_id = 0; /* XXX: ifa_ifwithaddr expects 0 */
235
#endif
236
                ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
237
                if (ia6 == NULL ||
238
                    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
239
                        *errorp = EADDRNOTAVAIL;
240
                        return(NULL);
241
                }
242
                pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
243
                if (*ifpp)
244
                        *ifpp = ifp;
245
                return(&pi->ipi6_addr);
246
        }
247
 
248
        /*
249
         * Otherwise, if the socket has already bound the source, just use it.
250
         */
251
        if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
252
                return(laddr);
253
 
254
        /*
255
         * If the address is not specified, choose the best one based on
256
         * the outgoing interface and the destination address.
257
         */
258
        /* get the outgoing interface */
259
        if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
260
                return(NULL);
261
 
262
#ifdef MIP6
263
#ifdef MIP6_ALLOW_COA_FALLBACK
264
        for (sc = TAILQ_FIRST(&hif_softc_list);
265
             sc;
266
             sc = TAILQ_NEXT(sc, hif_entry)) {
267
                mbu_dst = mip6_bu_list_find_withpaddr(&sc->hif_bu_list, dst);
268
                if (mbu_dst != NULL)
269
                        coafallback = mbu_dst->mbu_coafallback;
270
        }
271
#endif /* MIP6_ALLOW_COA_FALLBACK */
272
#endif /* MIP6 */
273
 
274
#ifdef DIAGNOSTIC
275
        if (ifp == NULL)        /* this should not happen */
276
                panic("in6_selectsrc: NULL ifp");
277
#endif
278
        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
279
                int new_scope = -1, new_matchlen = -1;
280
                struct in6_addrpolicy *new_policy = NULL;
281
                int64_t srczone, dstzone;
282
                struct ifnet *ifp1 = ia->ia_ifp;
283
 
284
                /*
285
                 * We'll never take an address that breaks the scope zone
286
                 * of the destination.  We also skip an address if its zone
287
                 * does not contain the outgoing interface.
288
                 * XXX: we should probably use sin6_scope_id here.
289
                 */
290
                if ((dstzone = in6_addr2zoneid(ifp1, dst)) < 0 ||
291
                    dstzone != in6_addr2zoneid(ifp, dst)) {
292
                        continue;
293
                }
294
                if ((srczone = in6_addr2zoneid(ifp1, &ia->ia_addr.sin6_addr))
295
                    < 0 ||
296
                    srczone != in6_addr2zoneid(ifp, &ia->ia_addr.sin6_addr)) {
297
                        continue;
298
                }
299
 
300
                /* avoid unusable addresses */
301
                if ((ia->ia6_flags &
302
                     (IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) {
303
                                continue;
304
                }
305
                if (!ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
306
                        continue;
307
 
308
                /* Rule 1: Prefer same address */
309
                if (IN6_ARE_ADDR_EQUAL(dst, &ia->ia_addr.sin6_addr)) {
310
                        ia_best = ia;
311
                        BREAK(1); /* there should be no better candidate */
312
                }
313
 
314
                if (ia_best == NULL)
315
                        REPLACE(0);
316
 
317
                /* Rule 2: Prefer appropriate scope */
318
                if (dst_scope < 0)
319
                        dst_scope = in6_addrscope(dst);
320
                new_scope = in6_addrscope(&ia->ia_addr.sin6_addr);
321
                if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) {
322
                        if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0)
323
                                REPLACE(2);
324
                        NEXT(2);
325
                } else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) {
326
                        if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0)
327
                                NEXT(2);
328
                        REPLACE(2);
329
                }
330
 
331
                /*
332
                 * Rule 3: Avoid deprecated addresses.  Note that the case of
333
                 * !ip6_use_deprecated is already rejected above.
334
                 */
335
                if (!IFA6_IS_DEPRECATED(ia_best) && IFA6_IS_DEPRECATED(ia))
336
                        NEXT(3);
337
                if (IFA6_IS_DEPRECATED(ia_best) && !IFA6_IS_DEPRECATED(ia))
338
                        REPLACE(3);
339
 
340
                /* Rule 4: Prefer home addresses */
341
                /*
342
                 * XXX: This is a TODO.  We should probably merge the MIP6
343
                 * case above.
344
                 */
345
#ifdef MIP6
346
                /*
347
                 * If SA is simultaneously a home address and care-of address
348
                 * and SB is not, then prefer SA. Similarly, if SB is
349
                 * simultaneously a home address and care-of address and SA is
350
                 * not, then prefer SB.
351
                 */
352
                {
353
                        struct mip6_bu *mbu_ia_best = NULL, *mbu_ia = NULL;
354
 
355
                        if (ia_best->ia6_flags & IN6_IFF_HOME) {
356
                                /*
357
                                 * find a binding update entry for ia_best.
358
                                 */
359
                                for (sc = TAILQ_FIRST(&hif_softc_list);
360
                                     sc;
361
                                     sc = TAILQ_NEXT(sc, hif_entry)) {
362
                                        mbu_ia_best = mip6_bu_list_find_home_registration(
363
                                                &sc->hif_bu_list,
364
                                                &ia->ia_addr.sin6_addr);
365
                                        if (mbu_ia_best)
366
                                                break;
367
                                }
368
                        }
369
                        if (ia->ia6_flags & IN6_IFF_HOME) {
370
                                /*
371
                                 * find a binding update entry for ia.
372
                                 */
373
                                for (sc = TAILQ_FIRST(&hif_softc_list);
374
                                     sc;
375
                                     sc = TAILQ_NEXT(sc, hif_entry)) {
376
                                        mbu_ia = mip6_bu_list_find_home_registration(
377
                                                &sc->hif_bu_list,
378
                                                &ia->ia_addr.sin6_addr);
379
                                        if (mbu_ia)
380
                                                break;
381
                                }
382
                        }
383
                        /*
384
                         * if the binding update entry for a certain address
385
                         * exists and its registration status is
386
                         * MIP6_BU_REG_STATE_NOTREG, the address is a home
387
                         * address and a care of addres simultaneously.
388
                         */
389
                        if ((mbu_ia_best &&
390
                             (mbu_ia_best->mbu_reg_state
391
                              == MIP6_BU_REG_STATE_NOTREG))
392
                            &&
393
                            !(mbu_ia &&
394
                              (mbu_ia->mbu_reg_state
395
                               == MIP6_BU_REG_STATE_NOTREG))) {
396
                                NEXT(4);
397
                        }
398
                        if (!(mbu_ia_best &&
399
                              (mbu_ia_best->mbu_reg_state
400
                               == MIP6_BU_REG_STATE_NOTREG))
401
                            &&
402
                            (mbu_ia &&
403
                             (mbu_ia->mbu_reg_state
404
                              == MIP6_BU_REG_STATE_NOTREG))) {
405
                                REPLACE(4);
406
                        }
407
                }
408
#ifdef MIP6_ALLOW_COA_FALLBACK
409
                if (coafallback) {
410
                        /*
411
                         * if the peer doesn't recognize a home
412
                         * address destination option, we will use a
413
                         * CoA as a source address instead of a home
414
                         * address we have registered before.  Though
415
                         * this behavior may arouse a mip6 beleiver's
416
                         * anger, is very useful in the current
417
                         * transition period that many hosts don't
418
                         * recognize a home address destination
419
                         * option...
420
                         */
421
                        if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
422
                            (ia->ia6_flags & IN6_IFF_HOME) != 0) {
423
                                /* XXX will break stat! */
424
                                NEXT(0);
425
                        }
426
                        if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
427
                            (ia->ia6_flags & IN6_IFF_HOME) == 0) {
428
                                /* XXX will break stat! */
429
                                REPLACE(0);
430
                        }
431
                } else
432
#endif
433
                {
434
                        /*
435
                         * If SA is just a home address and SB is just
436
                         * a care-of address, then prefer
437
                         * SA. Similarly, if SB is just a home address
438
                         * and SA is just a care-of address, then
439
                         * prefer SB.
440
                         */
441
                        if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
442
                            (ia->ia6_flags & IN6_IFF_HOME) == 0) {
443
                                NEXT(4);
444
                        }
445
                        if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
446
                            (ia->ia6_flags & IN6_IFF_HOME) != 0) {
447
                                REPLACE(4);
448
                        }
449
                }
450
#endif /* MIP6 */
451
 
452
                /* Rule 5: Prefer outgoing interface */
453
                if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
454
                        NEXT(5);
455
                if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
456
                        REPLACE(5);
457
 
458
                /*
459
                 * Rule 6: Prefer matching label
460
                 * Note that best_policy should be non-NULL here.
461
                 */
462
                if (dst_policy == NULL)
463
                        dst_policy = lookup_addrsel_policy(dstsock);
464
                if (dst_policy->label != ADDR_LABEL_NOTAPP) {
465
                        new_policy = lookup_addrsel_policy(&ia->ia_addr);
466
                        if (dst_policy->label == best_policy->label &&
467
                            dst_policy->label != new_policy->label)
468
                                NEXT(6);
469
                        if (dst_policy->label != best_policy->label &&
470
                            dst_policy->label == new_policy->label)
471
                                REPLACE(6);
472
                }
473
 
474
                /*
475
                 * Rule 7: Prefer public addresses.
476
                 * We allow users to reverse the logic by configuring
477
                 * a sysctl variable, so that privacy conscious users can
478
                 * always prefer temporary addresses.
479
                 */
480
                if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
481
                    (ia->ia6_flags & IN6_IFF_TEMPORARY)) {
482
                        if (ip6_prefer_tempaddr)
483
                                REPLACE(7);
484
                        else
485
                                NEXT(7);
486
                }
487
                if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
488
                    !(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
489
                        if (ip6_prefer_tempaddr)
490
                                NEXT(7);
491
                        else
492
                                REPLACE(7);
493
                }
494
 
495
                /*
496
                 * Rule 8: prefer addresses on alive interfaces.
497
                 * This is a KAME specific rule.
498
                 */
499
                if ((ia_best->ia_ifp->if_flags & IFF_UP) &&
500
                    !(ia->ia_ifp->if_flags & IFF_UP))
501
                        NEXT(8);
502
                if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&
503
                    (ia->ia_ifp->if_flags & IFF_UP))
504
                        REPLACE(8);
505
 
506
                /*
507
                 * Rule 9: prefer addresses on "preferred" interfaces.
508
                 * This is a KAME specific rule.
509
                 */
510
#define NDI_BEST (nd_ifinfo[ia_best->ia_ifp->if_index])
511
#define NDI_NEW  (nd_ifinfo[ia->ia_ifp->if_index])
512
                if ((NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
513
                    !(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
514
                        NEXT(9);
515
                if (!(NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
516
                    (NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
517
                        REPLACE(9);
518
#undef NDI_BEST
519
#undef NDI_NEW
520
 
521
                /*
522
                 * Rule 14: Use longest matching prefix.
523
                 * Note: in the address selection draft, this rule is
524
                 * documented as "Rule 8".  However, since it is also
525
                 * documented that this rule can be overridden, we assign
526
                 * a large number so that it is easy to assign smaller numbers
527
                 * to more preferred rules.
528
                 */
529
                new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, dst);
530
                if (best_matchlen < new_matchlen)
531
                        REPLACE(14);
532
                if (new_matchlen < best_matchlen)
533
                        NEXT(14);
534
 
535
                /* Rule 15 is reserved. */
536
 
537
                /*
538
                 * Last resort: just keep the current candidate.
539
                 * Or, do we need more rules?
540
                 */
541
                continue;
542
 
543
          replace:
544
                ia_best = ia;
545
                best_scope = (new_scope >= 0 ? new_scope :
546
                              in6_addrscope(&ia_best->ia_addr.sin6_addr));
547
                best_policy = (new_policy ? new_policy :
548
                               lookup_addrsel_policy(&ia_best->ia_addr));
549
                best_matchlen = (new_matchlen >= 0 ? new_matchlen :
550
                                 in6_matchlen(&ia_best->ia_addr.sin6_addr,
551
                                              dst));
552
 
553
          next:
554
                continue;
555
 
556
          out:
557
                break;
558
        }
559
 
560
        if ((ia = ia_best) == NULL) {
561
                *errorp = EADDRNOTAVAIL;
562
                return(NULL);
563
        }
564
 
565
        if (ifpp)
566
                *ifpp = ifp;
567
        return(&ia->ia_addr.sin6_addr);
568
}
569
#undef REPLACE
570
#undef BREAK
571
#undef NEXT
572
 
573
static int
574
in6_selectif(dstsock, opts, mopts, ro, retifp)
575
        struct sockaddr_in6 *dstsock;
576
        struct ip6_pktopts *opts;
577
        struct ip6_moptions *mopts;
578
#ifdef NEW_STRUCT_ROUTE
579
        struct route *ro;
580
#else
581
        struct route_in6 *ro;
582
#endif
583
        struct ifnet **retifp;
584
{
585
        int error, clone;
586
        struct rtentry *rt = NULL;
587
 
588
        clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
589
        if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp,
590
                                     &rt, clone)) != 0) {
591
                return(error);
592
        }
593
        /*
594
         * Adjust the "outgoing" interface.  If we're going to loop the packet
595
         * back to ourselves, the ifp would be the loopback interface.
596
         * However, we'd rather know the interface associated to the
597
         * destination address (which should probably be one of our own
598
         * addresses.)
599
         */
600
        if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)
601
                *retifp = rt->rt_ifa->ifa_ifp;
602
 
603
        return(0);
604
}
605
 
606
int
607
in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone)
608
        struct sockaddr_in6 *dstsock;
609
        struct ip6_pktopts *opts;
610
        struct ip6_moptions *mopts;
611
#ifdef NEW_STRUCT_ROUTE
612
        struct route *ro;
613
#else
614
        struct route_in6 *ro;
615
#endif
616
        struct ifnet **retifp;
617
        struct rtentry **retrt;
618
        int clone;              /* meaningful only for bsdi and freebsd. */
619
{
620
        int error = 0;
621
        struct ifnet *ifp = NULL;
622
        struct rtentry *rt = NULL;
623
        struct sockaddr_in6 *sin6_next;
624
        struct in6_pktinfo *pi = NULL;
625
        struct in6_addr *dst = &dstsock->sin6_addr;
626
 
627
        /* If the caller specify the outgoing interface explicitly, use it. */
628
        if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
629
                /* XXX boundary check is assumed to be already done. */
630
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
631
                ifp = ifnet_byindex(pi->ipi6_ifindex);
632
#else
633
                ifp = ifindex2ifnet[pi->ipi6_ifindex];
634
#endif
635
                if (ifp != NULL &&
636
                    (retrt == NULL || IN6_IS_ADDR_MULTICAST(dst))) {
637
                        /*
638
                         * we do not have to check nor get the route for
639
                         * multicast.
640
                         */
641
                        goto done;
642
                } else
643
                        goto getroute;
644
        }
645
 
646
        /*
647
         * If the destination address is a multicast address and the outgoing
648
         * interface for the address is specified by the caller, use it.
649
         */
650
        if (IN6_IS_ADDR_MULTICAST(dst) &&
651
            mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
652
                goto done; /* we do not need a route for multicast. */
653
        }
654
 
655
  getroute:
656
        /*
657
         * If the next hop address for the packet is specified by the caller,
658
         * use it as the gateway.
659
         */
660
        if (opts && opts->ip6po_nexthop) {
661
#ifdef NEW_STRUCT_ROUTE
662
                struct route *ron;
663
#else
664
                struct route_in6 *ron;
665
#endif
666
 
667
                sin6_next = satosin6(opts->ip6po_nexthop);
668
 
669
                /* at this moment, we only support AF_INET6 next hops */
670
                if (sin6_next->sin6_family != AF_INET6) {
671
                        error = EAFNOSUPPORT; /* or should we proceed? */
672
                        goto done;
673
                }
674
 
675
                /*
676
                 * If the next hop is an IPv6 address, then the node identified
677
                 * by that address must be a neighbor of the sending host.
678
                 */
679
                ron = &opts->ip6po_nextroute;
680
                if ((ron->ro_rt &&
681
                     (ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=
682
                     (RTF_UP | RTF_LLINFO)) ||
683
                    !SA6_ARE_ADDR_EQUAL(satosin6(&ron->ro_dst), sin6_next)) {
684
                        if (ron->ro_rt) {
685
                                RTFREE(ron->ro_rt);
686
                                ron->ro_rt = NULL;
687
                        }
688
                        *satosin6(&ron->ro_dst) = *sin6_next;
689
                }
690
                if (ron->ro_rt == NULL) {
691
                        rtalloc((struct route *)ron); /* multi path case? */
692
                        if (ron->ro_rt == NULL ||
693
                            !(ron->ro_rt->rt_flags & RTF_LLINFO)) {
694
                                if (ron->ro_rt) {
695
                                        RTFREE(ron->ro_rt);
696
                                        ron->ro_rt = NULL;
697
                                }
698
                                error = EHOSTUNREACH;
699
                                goto done;
700
                        }
701
                }
702
                rt = ron->ro_rt;
703
                ifp = rt->rt_ifp;
704
 
705
                /*
706
                 * When cloning is required, try to allocate a route to the
707
                 * destination so that the caller can store path MTU
708
                 * information.
709
                 */
710
                if (!clone)
711
                        goto done;
712
        }
713
 
714
        /*
715
         * Use a cached route if it exists and is valid, else try to allocate
716
         * a new one.
717
         */
718
        if (ro) {
719
                if (ro->ro_rt &&
720
                    (!(ro->ro_rt->rt_flags & RTF_UP) ||
721
                     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
722
                                        dst))) {
723
                        RTFREE(ro->ro_rt);
724
                        ro->ro_rt = (struct rtentry *)NULL;
725
                }
726
                if (ro->ro_rt == (struct rtentry *)NULL) {
727
                        struct sockaddr_in6 *sa6;
728
 
729
                        /* No route yet, so try to acquire one */
730
                        bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
731
                        sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
732
                        sa6->sin6_family = AF_INET6;
733
                        sa6->sin6_len = sizeof(struct sockaddr_in6);
734
                        sa6->sin6_addr = *dst;
735
#ifdef SCOPEDROUTING
736
                        sa6->sin6_scope_id = dstsock->sin6_scope_id;
737
#endif
738
                        if (clone) {
739
#ifdef __bsdi__
740
                                rtcalloc((struct route *)ro);
741
#else  /* !bsdi */
742
#ifdef RADIX_MPATH
743
                                rtalloc_mpath((struct route *)ro,
744
                                    ntohl(dstsock->sin6_addr.s6_addr32[3]));
745
#else
746
                                rtalloc((struct route *)ro);
747
#endif /* RADIX_MPATH */
748
#endif /* bsdi */
749
                        } else {
750
#ifdef __FreeBSD__
751
                                ro->ro_rt = rtalloc1(&((struct route *)ro)
752
                                                     ->ro_dst, (int)NULL, 0UL);
753
#else
754
#ifdef RADIX_MPATH
755
                                rtalloc_mpath((struct route *)ro,
756
                                    ntohl(dstsock->sin6_addr.s6_addr32[3]));
757
#else
758
                                ro->ro_rt = rtalloc1(&((struct route *)ro)
759
                                                     ->ro_dst, NULL);
760
#endif /* RADIX_MPATH */
761
#endif /* __FreeBSD__ */
762
                        }
763
                }
764
 
765
                /*
766
                 * do not care about the result if we have the nexthop
767
                 * explicitly specified.
768
                 */
769
                if (opts && opts->ip6po_nexthop)
770
                        goto done;
771
 
772
                if (ro->ro_rt) {
773
                        ifp = ro->ro_rt->rt_ifp;
774
 
775
                        if (ifp == NULL) { /* can this really happen? */
776
                                RTFREE(ro->ro_rt);
777
                                ro->ro_rt = NULL;
778
                        }
779
                }
780
                if (ro->ro_rt == NULL)
781
                        error = EHOSTUNREACH;
782
                rt = ro->ro_rt;
783
 
784
                /*
785
                 * Check if the outgoing interface conflicts with
786
                 * the interface specified by ipi6_ifindex (if specified).
787
                 * Note that loopback interface is always okay.
788
                 * (this may happen when we are sending a packet to one of
789
                 *  our own addresses.)
790
                 */
791
                if (opts && opts->ip6po_pktinfo
792
                    && opts->ip6po_pktinfo->ipi6_ifindex) {
793
                        if (!(ifp->if_flags & IFF_LOOPBACK) &&
794
                            ifp->if_index !=
795
                            opts->ip6po_pktinfo->ipi6_ifindex) {
796
                                error = EHOSTUNREACH;
797
                                goto done;
798
                        }
799
                }
800
        }
801
 
802
  done:
803
        if (error == EHOSTUNREACH)
804
                ip6stat.ip6s_noroute++;
805
 
806
        if (retifp != NULL)
807
                *retifp = ifp;
808
        if (retrt != NULL)
809
                *retrt = rt;    /* rt may be NULL */
810
 
811
        return(error);
812
}
813
 
814
/*
815
 * Default hop limit selection. The precedence is as follows:
816
 * 1. Hoplimit value specified via ioctl.
817
 * 2. (If the outgoing interface is detected) the current
818
 *     hop limit of the interface specified by router advertisement.
819
 * 3. The system default hoplimit.
820
*/
821
#ifdef HAVE_NRL_INPCB
822
#define in6pcb          inpcb
823
#define in6p_hops       inp_hops        
824
#endif
825
int
826
in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp)
827
{
828
        if (in6p && in6p->in6p_hops >= 0)
829
                return(in6p->in6p_hops);
830
        else if (ifp)
831
                return(nd_ifinfo[ifp->if_index].chlim);
832
        else
833
                return(ip6_defhlim);
834
}
835
#ifdef HAVE_NRL_INPCB
836
#undef in6pcb
837
#undef in6p_hops
838
#endif
839
 
840
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
841
/*
842
 * Find an empty port and set it to the specified PCB.
843
 */
844
#ifdef HAVE_NRL_INPCB   /* XXX: I really hate such ugly macros...(jinmei) */
845
#define in6pcb          inpcb
846
#define in6p_socket     inp_socket
847
#define in6p_lport      inp_lport
848
#define in6p_head       inp_head
849
#define in6p_flags      inp_flags
850
#define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD
851
#endif
852
int
853
in6_pcbsetport(struct in6_addr *laddr, struct in6pcb *in6p)
854
{
855
        struct socket *so = in6p->in6p_socket;
856
        struct in6pcb *head = in6p->in6p_head;
857
        u_int16_t last_port, lport = 0;
858
        int wild = 0;
859
        void *t;
860
        u_int16_t min, max;
861
 
862
        /* XXX: this is redundant when called from in6_pcbbind */
863
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
864
           ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
865
            (so->so_options & SO_ACCEPTCONN) == 0))
866
                wild = IN6PLOOKUP_WILDCARD;
867
 
868
        if (in6p->in6p_flags & IN6P_LOWPORT) {
869
                min = ip6_lowportmin;
870
                max = ip6_lowportmax;
871
        } else {
872
                min = ip6_anonportmin;
873
                max = ip6_anonportmax;
874
        }
875
 
876
        /* value out of range */
877
        if (head->in6p_lport < min)
878
                head->in6p_lport = min;
879
        else if (head->in6p_lport > max)
880
                head->in6p_lport = min;
881
        last_port = head->in6p_lport;
882
        goto startover; /*to randomize*/
883
        for (;;) {
884
                lport = htons(head->in6p_lport);
885
                if (IN6_IS_ADDR_V4MAPPED(laddr)) {
886
#ifdef HAVE_NRL_INPCB
887
#ifdef INPLOOKUP_WILDCARD6
888
                        wild &= ~INPLOOKUP_WILDCARD6;
889
#endif
890
#endif
891
#if 0
892
                        t = in_pcblookup_bind(&tcbtable,
893
                                              (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
894
                                              lport);
895
#else
896
                        t = NULL;
897
#endif
898
                } else {
899
#ifdef HAVE_NRL_INPCB
900
#ifdef INPLOOKUP_WILDCARD4
901
                        wild &= ~INPLOOKUP_WILDCARD4;
902
#endif
903
                        /* XXX: ugly cast... */
904
                        t = in_pcblookup(head, (struct in_addr *)&zeroin6_addr,
905
                                         0, (struct in_addr *)laddr,
906
                                         lport, wild | INPLOOKUP_IPV6);
907
#else
908
                        t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
909
                                          lport, wild);
910
#endif
911
                }
912
                if (t == 0)
913
                        break;
914
          startover:
915
                if (head->in6p_lport >= max)
916
                        head->in6p_lport = min;
917
                else
918
                        head->in6p_lport++;
919
                if (head->in6p_lport == last_port)
920
                        return (EADDRINUSE);
921
        }
922
 
923
        in6p->in6p_lport = lport;
924
        return(0);               /* success */
925
}
926
#ifdef HAVE_NRL_INPCB
927
#undef in6pcb
928
#undef in6p_socket
929
#undef in6p_lport
930
#undef in6p_head
931
#undef in6p_flags
932
#undef IN6PLOOKUP_WILDCARD
933
#endif
934
#endif /* !FreeBSD3 && !OpenBSD*/
935
 
936
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
937
/*
938
 * XXX: this is borrowed from in6_pcbbind(). If possible, we should
939
 * share this function by all *bsd*...
940
 */
941
int
942
in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct proc *p)
943
{
944
        struct socket *so = inp->inp_socket;
945
        u_int16_t lport = 0, first, last, *lastport;
946
        int count, wild = 0;
947
        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
948
 
949
        /* XXX: this is redundant when called from in6_pcbbind */
950
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
951
                wild = INPLOOKUP_WILDCARD;
952
 
953
        inp->inp_flags |= INP_ANONPORT;
954
 
955
        if (inp->inp_flags & INP_HIGHPORT) {
956
                first = ipport_hifirstauto;     /* sysctl */
957
                last  = ipport_hilastauto;
958
                lastport = &pcbinfo->lasthi;
959
        } else if (inp->inp_flags & INP_LOWPORT) {
960
                first = ipport_lowfirstauto;    /* 1023 */
961
                last  = ipport_lowlastauto;     /* 600 */
962
                lastport = &pcbinfo->lastlow;
963
        } else {
964
                first = ipport_firstauto;       /* sysctl */
965
                last  = ipport_lastauto;
966
                lastport = &pcbinfo->lastport;
967
        }
968
        /*
969
         * Simple check to ensure all ports are not used up causing
970
         * a deadlock here.
971
         *
972
         * We split the two cases (up and down) so that the direction
973
         * is not being tested on each round of the loop.
974
         */
975
        if (first > last) {
976
                /*
977
                 * counting down
978
                 */
979
                count = first - last;
980
 
981
                do {
982
                        if (count-- < 0) {       /* completely used? */
983
                                /*
984
                                 * Undo any address bind that may have
985
                                 * occurred above.
986
                                 */
987
                                inp->in6p_laddr = in6addr_any;
988
                                return (EAGAIN);
989
                        }
990
                        --*lastport;
991
                        if (*lastport > first || *lastport < last)
992
                                *lastport = first;
993
                        lport = htons(*lastport);
994
                } while (in6_pcblookup_local(pcbinfo,
995
                                             &inp->in6p_laddr, lport, wild));
996
        } else {
997
                /*
998
                         * counting up
999
                         */
1000
                count = last - first;
1001
 
1002
                do {
1003
                        if (count-- < 0) {       /* completely used? */
1004
                                /*
1005
                                 * Undo any address bind that may have
1006
                                 * occurred above.
1007
                                 */
1008
                                inp->in6p_laddr = in6addr_any;
1009
                                return (EAGAIN);
1010
                        }
1011
                        ++*lastport;
1012
                        if (*lastport < first || *lastport > last)
1013
                                *lastport = first;
1014
                        lport = htons(*lastport);
1015
                } while (in6_pcblookup_local(pcbinfo,
1016
                                             &inp->in6p_laddr, lport, wild));
1017
        }
1018
 
1019
        inp->inp_lport = lport;
1020
        if (in_pcbinshash(inp) != 0) {
1021
                inp->in6p_laddr = in6addr_any;
1022
                inp->inp_lport = 0;
1023
                return (EAGAIN);
1024
        }
1025
 
1026
        return(0);
1027
}
1028
#endif
1029
 
1030
/*
1031
 * Generate kernel-internal form (scopeid embedded into s6_addr16[1]).
1032
 * If the address scope of is interface-local or link-local, embed the
1033
 * interface index in the address.
1034
 *
1035
 * This function should be nuked in the future, when we get rid of embedded
1036
 * scopeid thing.
1037
 */
1038
int
1039
in6_embedscope(in6, sin6)
1040
        struct in6_addr *in6;
1041
        const struct sockaddr_in6 *sin6;
1042
{
1043
#ifdef SCOPEDROUTING
1044
        /*
1045
         * XXX: the SCOPEDROUTING code path is NOT expected to work at this
1046
         * moment (20011112).  We added this just in case.
1047
         */
1048
        return(0);               /* do nothing */
1049
#else
1050
        struct ifnet *ifp;
1051
        u_int32_t zoneid = sin6->sin6_scope_id;
1052
 
1053
        *in6 = sin6->sin6_addr;
1054
 
1055
        /*
1056
         * don't try to read sin6->sin6_addr beyond here, since the caller may
1057
         * ask us to overwrite existing sockaddr_in6
1058
         */
1059
 
1060
        if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
1061
                /* KAME assumption: link id == interface id */
1062
                if (zoneid) {
1063
                        if (if_index < zoneid)
1064
                                return(ENXIO);  /* XXX EINVAL? */
1065
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
1066
                        ifp = ifnet_byindex(zoneid);
1067
#else
1068
                        ifp = ifindex2ifnet[zoneid];
1069
#endif
1070
                        if (ifp == NULL) /* XXX: this can happen for some OS */
1071
                                return(ENXIO);
1072
 
1073
                        /* XXX assignment to 16bit from 32bit variable */
1074
                        in6->s6_addr16[1] = htons(zoneid & 0xffff);
1075
                }
1076
        }
1077
 
1078
        return 0;
1079
#endif
1080
}
1081
 
1082
/*
1083
 * generate standard sockaddr_in6 from embedded form.
1084
 * touches sin6_addr and sin6_scope_id only.
1085
 *
1086
 * this function should be nuked in the future, when we get rid of
1087
 * embedded scopeid thing.
1088
 */
1089
int
1090
in6_recoverscope(sin6, in6, ifp)
1091
        struct sockaddr_in6 *sin6;
1092
        const struct in6_addr *in6;
1093
        struct ifnet *ifp;
1094
{
1095
        u_int32_t zoneid;
1096
 
1097
        sin6->sin6_addr = *in6;
1098
 
1099
        /*
1100
         * don't try to read *in6 beyond here, since the caller may
1101
         * ask us to overwrite existing sockaddr_in6
1102
         */
1103
 
1104
        sin6->sin6_scope_id = 0;
1105
        if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
1106
                /*
1107
                 * KAME assumption: link id == interface id
1108
                 */
1109
                zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
1110
                if (zoneid) {
1111
                        /* sanity check */
1112
                        if (zoneid < 0 || if_index < zoneid)
1113
                                return ENXIO;
1114
                        if (ifp && ifp->if_index != zoneid)
1115
                                return ENXIO;
1116
                        sin6->sin6_addr.s6_addr16[1] = 0;
1117
                        sin6->sin6_scope_id = zoneid;
1118
                }
1119
        }
1120
 
1121
        return 0;
1122
}
1123
 
1124
/*
1125
 * just clear the embedded scope identifer.
1126
 * XXX: currently used for bsdi4 only as a supplement function.
1127
 */
1128
void
1129
in6_clearscope(addr)
1130
        struct in6_addr *addr;
1131
{
1132
        if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
1133
                addr->s6_addr16[1] = 0;
1134
}
1135
 
1136
void
1137
addrsel_policy_init()
1138
{
1139
        init_policy_queue();
1140
 
1141
        /* initialize the "last resort" policy */
1142
        bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
1143
        defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
1144
}
1145
 
1146
static struct in6_addrpolicy *
1147
lookup_addrsel_policy(key)
1148
        struct sockaddr_in6 *key;
1149
{
1150
        struct in6_addrpolicy *match = NULL;
1151
 
1152
        match = match_addrsel_policy(key);
1153
 
1154
        if (match == NULL)
1155
                match = &defaultaddrpolicy;
1156
        else
1157
                match->use++;
1158
 
1159
        return(match);
1160
}
1161
 
1162
 
1163
int
1164
in6_src_ioctl(cmd, data)
1165
        u_long cmd;
1166
        caddr_t data;
1167
{
1168
        int i;
1169
        struct in6_addrpolicy ent0;
1170
 
1171
        if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY)
1172
                return(EOPNOTSUPP); /* check for safety */
1173
 
1174
        ent0 = *(struct in6_addrpolicy *)data;
1175
 
1176
        if (ent0.label == ADDR_LABEL_NOTAPP)
1177
                return(EINVAL);
1178
        /* check if the prefix mask is consecutive. */
1179
        if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0)
1180
                return(EINVAL);
1181
        /* clear trailing garbages (if any) of the prefix address. */
1182
        for (i = 0; i < 4; i++) {
1183
                ent0.addr.sin6_addr.s6_addr32[i] &=
1184
                        ent0.addrmask.sin6_addr.s6_addr32[i];
1185
        }
1186
        ent0.use = 0;
1187
 
1188
        switch (cmd) {
1189
        case SIOCAADDRCTL_POLICY:
1190
                return(add_addrsel_policyent(&ent0));
1191
        case SIOCDADDRCTL_POLICY:
1192
                return(delete_addrsel_policyent(&ent0));
1193
        }
1194
 
1195
        return(0);               /* XXX: compromise compilers */
1196
}
1197
 
1198
/*
1199
 * The followings are implementation of the policy table using a
1200
 * simple tail queue.
1201
 * XXX such details should be hidden.
1202
 * XXX implementation using binary tree should be more efficient.
1203
 */
1204
struct addrsel_policyent {
1205
        TAILQ_ENTRY(addrsel_policyent) ape_entry;
1206
        struct in6_addrpolicy ape_policy;
1207
};
1208
 
1209
TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
1210
 
1211
struct addrsel_policyhead addrsel_policytab;
1212
 
1213
static void
1214
init_policy_queue()
1215
{
1216
        TAILQ_INIT(&addrsel_policytab);
1217
}
1218
 
1219
static int
1220
add_addrsel_policyent(newpolicy)
1221
        struct in6_addrpolicy *newpolicy;
1222
{
1223
        struct addrsel_policyent *new, *pol;
1224
 
1225
        /* duplication check */
1226
        for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
1227
             pol = TAILQ_NEXT(pol, ape_entry)) {
1228
                if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr,
1229
                                       &pol->ape_policy.addr) &&
1230
                    SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask,
1231
                                       &pol->ape_policy.addrmask)) {
1232
                        return(EEXIST); /* or override it? */
1233
                }
1234
        }
1235
 
1236
        MALLOC(new, struct addrsel_policyent *, sizeof(*new), M_IFADDR,
1237
               M_WAITOK);
1238
        bzero(new, sizeof(*new));
1239
 
1240
        /* XXX: should validate entry */
1241
        new->ape_policy = *newpolicy;
1242
 
1243
        TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
1244
 
1245
        return(0);
1246
}
1247
 
1248
static int
1249
delete_addrsel_policyent(key)
1250
        struct in6_addrpolicy *key;
1251
{
1252
        struct addrsel_policyent *pol;
1253
 
1254
        /* search for the entry in the table */
1255
        for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
1256
             pol = TAILQ_NEXT(pol, ape_entry)) {
1257
                if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) &&
1258
                    SA6_ARE_ADDR_EQUAL(&key->addrmask,
1259
                                       &pol->ape_policy.addrmask)) {
1260
                        break;
1261
                }
1262
        }
1263
        if (pol == NULL)
1264
                return(ESRCH);
1265
 
1266
        TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry);
1267
 
1268
        return(0);
1269
}
1270
 
1271
void
1272
_show_addrsel_policy(void)
1273
{
1274
        struct addrsel_policyent *pol;
1275
 
1276
        log(LOG_ADDR, "IPv6 address policy table\n");
1277
        for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
1278
             pol = TAILQ_NEXT(pol, ape_entry)) {
1279
            log(LOG_ADDR, "Addr: \n");
1280
            log_dump(LOG_ADDR, &pol->ape_policy.addr, 16);
1281
            log(LOG_ADDR, "Mask:\n");
1282
            log_dump(LOG_ADDR, &pol->ape_policy.addrmask, 16);
1283
        }
1284
}
1285
 
1286
static struct in6_addrpolicy *
1287
match_addrsel_policy(key)
1288
        struct sockaddr_in6 *key;
1289
{
1290
        struct addrsel_policyent *pent;
1291
        struct in6_addrpolicy *bestpol = NULL, *pol;
1292
        int matchlen, bestmatchlen = -1;
1293
        u_char *mp, *ep, *k, *p, m;
1294
 
1295
        for (pent = TAILQ_FIRST(&addrsel_policytab); pent;
1296
             pent = TAILQ_NEXT(pent, ape_entry)) {
1297
                matchlen = 0;
1298
 
1299
                pol = &pent->ape_policy;
1300
                mp = (u_char *)&pol->addrmask.sin6_addr;
1301
                ep = mp + 16;   /* XXX: scope field? */
1302
                k = (u_char *)&key->sin6_addr;
1303
                p = (u_char *)&pol->addr.sin6_addr;
1304
                for (; mp < ep && *mp; mp++, k++, p++) {
1305
                        m = *mp;
1306
                        if ((*k & m) != *p)
1307
                                goto next; /* not match */
1308
                        if (m == 0xff) /* short cut for a typical case */
1309
                                matchlen += 8;
1310
                        else {
1311
                                while(m >= 0x80) {
1312
                                        matchlen++;
1313
                                        m <<= 1;
1314
                                }
1315
                        }
1316
                }
1317
 
1318
                /* matched.  check if this is better than the current best. */
1319
                if (bestpol == NULL ||
1320
                    matchlen > bestmatchlen) {
1321
                        bestpol = pol;
1322
                        bestmatchlen = matchlen;
1323
                }
1324
 
1325
          next:
1326
                continue;
1327
        }
1328
 
1329
        return(bestpol);
1330
}

powered by: WebSVN 2.1.0

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