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

Subversion Repositories openrisc

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/scope6.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: scope6.c,v 1.27 2001/12/18 02:23:45 itojun Exp $ */
23
 
24
/*
25
 * Copyright (C) 2000 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
#include <sys/param.h>
54
#include <sys/malloc.h>
55
#include <sys/mbuf.h>
56
#include <sys/socket.h>
57
#include <sys/queue.h>
58
 
59
#include <net/route.h>
60
#include <net/if.h>
61
 
62
#include <netinet/in.h>
63
 
64
#include <netinet6/in6_var.h>
65
#include <netinet6/scope6_var.h>
66
 
67
#ifdef ENABLE_DEFAULT_SCOPE
68
int ip6_use_defzone = 1;
69
#else
70
int ip6_use_defzone = 0;
71
#endif
72
 
73
struct scope6_id {
74
        /*
75
         * 16 is correspondent to 4bit multicast scope field.
76
         * i.e. from node-local to global with some reserved/unassigned types.
77
         */
78
        u_int32_t s6id_list[16];
79
};
80
static size_t if_indexlim = 8;
81
struct scope6_id *scope6_ids = NULL;
82
 
83
void
84
scope6_ifattach(ifp)
85
        struct ifnet *ifp;
86
{
87
#ifdef __NetBSD__
88
        int s = splsoftnet();
89
#else
90
        int s = splnet();
91
#endif
92
 
93
        /*
94
         * We have some arrays that should be indexed by if_index.
95
         * since if_index will grow dynamically, they should grow too.
96
         */
97
        if (scope6_ids == NULL || if_index >= if_indexlim) {
98
                size_t n;
99
                caddr_t q;
100
 
101
                while (if_index >= if_indexlim)
102
                        if_indexlim <<= 1;
103
 
104
                /* grow scope index array */
105
                n = if_indexlim * sizeof(struct scope6_id);
106
                /* XXX: need new malloc type? */
107
                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
108
                bzero(q, n);
109
                if (scope6_ids) {
110
                        bcopy((caddr_t)scope6_ids, q, n/2);
111
                        free((caddr_t)scope6_ids, M_IFADDR);
112
                }
113
                scope6_ids = (struct scope6_id *)q;
114
        }
115
 
116
#define SID scope6_ids[ifp->if_index]
117
 
118
        /* don't initialize if called twice */
119
        if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) {
120
                splx(s);
121
                return;
122
        }
123
 
124
        /*
125
         * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
126
         * Should we rather hardcode here?
127
         */
128
        SID.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
129
        SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
130
#ifdef MULTI_SCOPE
131
        /* by default, we don't care about scope boundary for these scopes. */
132
        SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
133
        SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
134
#endif
135
#undef SID
136
 
137
        splx(s);
138
}
139
 
140
int
141
scope6_set(ifp, idlist)
142
        struct ifnet *ifp;
143
        u_int32_t *idlist;
144
{
145
        int i, s;
146
        int error = 0;
147
 
148
        if (scope6_ids == NULL) /* paranoid? */
149
                return(EINVAL);
150
 
151
        /*
152
         * XXX: We need more consistency checks of the relationship among
153
         * scopes (e.g. an organization should be larger than a site).
154
         */
155
 
156
        /*
157
         * TODO(XXX): after setting, we should reflect the changes to
158
         * interface addresses, routing table entries, PCB entries...
159
         */
160
 
161
#ifdef __NetBSD__
162
        s = splsoftnet();
163
#else
164
        s = splnet();
165
#endif
166
 
167
        for (i = 0; i < 16; i++) {
168
                if (idlist[i] &&
169
                    idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) {
170
                        /*
171
                         * An interface zone ID must be the corresponding
172
                         * interface index by definition.
173
                         */
174
                        if (i == IPV6_ADDR_SCOPE_INTFACELOCAL &&
175
                            idlist[i] != ifp->if_index) {
176
                                splx(s);
177
                                return(EINVAL);
178
                        }
179
 
180
                        if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
181
                            idlist[i] > if_index) {
182
                                /*
183
                                 * XXX: theoretically, there should be no
184
                                 * relationship between link IDs and interface
185
                                 * IDs, but we check the consistency for
186
                                 * safety in later use.
187
                                 */
188
                                splx(s);
189
                                return(EINVAL);
190
                        }
191
 
192
                        /*
193
                         * XXX: we must need lots of work in this case,
194
                         * but we simply set the new value in this initial
195
                         * implementation.
196
                         */
197
                        scope6_ids[ifp->if_index].s6id_list[i] = idlist[i];
198
                }
199
        }
200
        splx(s);
201
 
202
        return(error);
203
}
204
 
205
int
206
scope6_get(ifp, idlist)
207
        struct ifnet *ifp;
208
        u_int32_t *idlist;
209
{
210
        if (scope6_ids == NULL) /* paranoid? */
211
                return(EINVAL);
212
 
213
        bcopy(scope6_ids[ifp->if_index].s6id_list, idlist,
214
              sizeof(scope6_ids[ifp->if_index].s6id_list));
215
 
216
        return(0);
217
}
218
 
219
 
220
/*
221
 * Get a scope of the address. Node-local, link-local, site-local or global.
222
 */
223
int
224
in6_addrscope(addr)
225
        struct in6_addr *addr;
226
{
227
        int scope;
228
 
229
        if (addr->s6_addr[0] == 0xfe) {
230
                scope = addr->s6_addr[1] & 0xc0;
231
 
232
                switch (scope) {
233
                case 0x80:
234
                        return IPV6_ADDR_SCOPE_LINKLOCAL;
235
                        break;
236
                case 0xc0:
237
                        return IPV6_ADDR_SCOPE_SITELOCAL;
238
                        break;
239
                default:
240
                        return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
241
                        break;
242
                }
243
        }
244
 
245
 
246
        if (addr->s6_addr[0] == 0xff) {
247
                scope = addr->s6_addr[1] & 0x0f;
248
 
249
                /*
250
                 * due to other scope such as reserved,
251
                 * return scope doesn't work.
252
                 */
253
                switch (scope) {
254
                case IPV6_ADDR_SCOPE_INTFACELOCAL:
255
                        return IPV6_ADDR_SCOPE_INTFACELOCAL;
256
                        break;
257
                case IPV6_ADDR_SCOPE_LINKLOCAL:
258
                        return IPV6_ADDR_SCOPE_LINKLOCAL;
259
                        break;
260
                case IPV6_ADDR_SCOPE_SITELOCAL:
261
                        return IPV6_ADDR_SCOPE_SITELOCAL;
262
                        break;
263
                default:
264
                        return IPV6_ADDR_SCOPE_GLOBAL;
265
                        break;
266
                }
267
        }
268
 
269
        /*
270
         * Regard loopback and unspecified addresses as global, since
271
         * they have no ambiguity.
272
         */
273
        if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
274
                if (addr->s6_addr[15] == 1) /* loopback */
275
                        return IPV6_ADDR_SCOPE_LINKLOCAL;
276
                if (addr->s6_addr[15] == 0) /* unspecified */
277
                        return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
278
        }
279
 
280
        return IPV6_ADDR_SCOPE_GLOBAL;
281
}
282
 
283
/*
284
 * When we introduce the "4+28" split semantics in sin6_scope_id,
285
 * a 32bit integer is not enough to tell a large ID from an error (-1).
286
 * So, we intentionally use a large type as the return value.
287
 */
288
int64_t
289
in6_addr2zoneid(ifp, addr)
290
        struct ifnet *ifp;      /* must not be NULL */
291
        struct in6_addr *addr;  /* must not be NULL */
292
{
293
        int scope;
294
 
295
#ifdef DIAGNOSTIC
296
        if (scope6_ids == NULL) { /* should not happen */
297
                panic("in6_addr2zoneid: scope array is NULL");
298
                /* NOTREACHED */
299
        }
300
        if (ifp->if_index >= if_indexlim) {
301
                panic("in6_addr2zoneid: invalid interface");
302
                /* NOTREACHED */
303
        }
304
#endif
305
 
306
        /*
307
         * special case: the loopback address can only belong to a loopback
308
         * interface.
309
         */
310
        if (IN6_IS_ADDR_LOOPBACK(addr)) {
311
                if (!(ifp->if_flags & IFF_LOOPBACK))
312
                        return(-1);
313
                else
314
                        return(0); /* there's no ambiguity */
315
        }
316
 
317
        scope = in6_addrscope(addr);
318
 
319
#define SID scope6_ids[ifp->if_index]
320
        switch (scope) {
321
        case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
322
                return(SID.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL]);
323
 
324
        case IPV6_ADDR_SCOPE_LINKLOCAL:
325
                return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
326
 
327
        case IPV6_ADDR_SCOPE_SITELOCAL:
328
                return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
329
 
330
        case IPV6_ADDR_SCOPE_ORGLOCAL:
331
                return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
332
 
333
        default:
334
                return(0);       /* XXX: treat as global. */
335
        }
336
#undef SID
337
}
338
 
339
void
340
scope6_setdefault(ifp)
341
        struct ifnet *ifp;      /* note that this might be NULL */
342
{
343
        /*
344
         * Currently, this function just set the default "interfaces"
345
         * and "links" according to the given interface.
346
         * We might eventually have to separate the notion of "link" from
347
         * "interface" and provide a user interface to set the default.
348
         */
349
        if (ifp) {
350
                scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] =
351
                        ifp->if_index;
352
                scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
353
                        ifp->if_index;
354
        }
355
        else {
356
                scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0;
357
                scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
358
        }
359
}
360
 
361
int
362
scope6_get_default(idlist)
363
        u_int32_t *idlist;
364
{
365
        if (scope6_ids == NULL) /* paranoid? */
366
                return(EINVAL);
367
 
368
        bcopy(scope6_ids[0].s6id_list, idlist,
369
              sizeof(scope6_ids[0].s6id_list));
370
 
371
        return(0);
372
}
373
 
374
u_int32_t
375
scope6_addr2default(addr)
376
        struct in6_addr *addr;
377
{
378
        /*
379
         * special case: The loopback address should be considered as
380
         * link-local, but there's no ambiguity in the syntax.
381
         */
382
        if (IN6_IS_ADDR_LOOPBACK(addr))
383
                return(0);
384
 
385
        return(scope6_ids[0].s6id_list[in6_addrscope(addr)]);
386
}
387
 
388
/*
389
 * XXX: some applications assume the kernel guesses a correct zone ID when the
390
 * outgoing interface is explicitly specified, and omit specifying the ID.
391
 * This is a bad manner, but we handle such cases anyway.
392
 * Note that this function intentionally overrides the argument SIN6.
393
 */
394
int
395
scope6_setzoneid(ifp, sin6)
396
        struct ifnet *ifp;
397
        struct sockaddr_in6 *sin6;
398
{
399
        int64_t zoneid;
400
        int error;
401
 
402
        zoneid = in6_addr2zoneid(ifp, &sin6->sin6_addr);
403
 
404
        if (zoneid < 0)
405
                return(ENXIO);
406
        if (zoneid) {
407
                sin6->sin6_scope_id = zoneid;
408
                if ((error = in6_embedscope(&sin6->sin6_addr, sin6)) != 0)
409
                        return(error);
410
        }
411
 
412
        return(0);
413
}
414
 
415
/*
416
 * Check if the zone ID in SIN6 is valid according to the scope of the
417
 * address.  If DFEFAULTOK is true and the zone ID is unspecified, fill the
418
 * default value for the scope type in the ID field.
419
 * This function also embeds the zone ID into the 128bit address field if
420
 * necessary.  This format is internally used in the kernel.
421
 * As a result, it is ensured that SIN6 has a valid scope zone ID and the
422
 * address part is converted to the internal form.
423
 *
424
 * The caller must expect that SIN6 can be modified within this function;
425
 * if it is not desired to override the original value a local copy must be
426
 * made in advance.
427
 */
428
int
429
scope6_check_id(sin6, defaultok)
430
        struct sockaddr_in6 *sin6;
431
        int defaultok;
432
{
433
        u_int32_t zoneid;
434
        struct in6_addr *in6 = &sin6->sin6_addr;
435
        struct ifnet *ifp;
436
 
437
        if ((zoneid = sin6->sin6_scope_id) != 0) {
438
                /*
439
                 * At this moment, we only check interface-local and
440
                 * link-local scope IDs, and use interface indices as the
441
                 * zone IDs assuming a one-to-one mapping between interfaces
442
                 * and links.
443
                 * XXX: in6_embedscope() below does the same check (in case
444
                 * of !SCOPEDROUTING).  We should eventually centralize the
445
                 * check in this function.
446
                 */
447
                if (IN6_IS_SCOPE_LINKLOCAL(in6) ||
448
                    IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
449
                        if (if_index < zoneid)
450
                                return(ENXIO);
451
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
452
                        ifp = ifnet_byindex(zoneid);
453
#else
454
                        ifp = ifindex2ifnet[zoneid];
455
#endif
456
                        if (ifp == NULL) /* XXX: this can happen for some OS */
457
                                return(ENXIO);
458
                }
459
        } else if (defaultok)
460
                sin6->sin6_scope_id = scope6_addr2default(in6);
461
 
462
        /* KAME hack: embed scopeid */
463
        if (in6_embedscope(in6, sin6) != 0)
464
                return(EINVAL);
465
 
466
        return(0);
467
}

powered by: WebSVN 2.1.0

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