1 /* $FreeBSD: src/sys/netinet6/scope6.c,v 1.3 2002/03/25 10:12:51 ume Exp $ */
2 /* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */
5 * Copyright (C) 2000 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/param.h>
34 #include <sys/malloc.h>
36 #include <sys/socket.h>
37 #include <sys/systm.h>
38 #include <sys/queue.h>
40 #include <net/route.h>
43 #include <netinet/in.h>
45 #include <netinet6/in6_var.h>
46 #include <netinet6/scope6_var.h>
50 * 16 is correspondent to 4bit multicast scope field.
51 * i.e. from node-local to global with some reserved/unassigned types.
53 u_int32_t s6id_list
[16];
55 static size_t if_indexlim
= 8;
56 struct scope6_id
*scope6_ids
= NULL
;
65 * We have some arrays that should be indexed by if_index.
66 * since if_index will grow dynamically, they should grow too.
68 if (scope6_ids
== NULL
|| if_index
>= if_indexlim
) {
72 while (if_index
>= if_indexlim
)
75 /* grow scope index array */
76 n
= if_indexlim
* sizeof(struct scope6_id
);
77 /* XXX: need new malloc type? */
78 q
= (caddr_t
)_MALLOC(n
, M_IFADDR
, M_WAITOK
);
81 bcopy((caddr_t
)scope6_ids
, q
, n
/2);
82 FREE((caddr_t
)scope6_ids
, M_IFADDR
);
84 scope6_ids
= (struct scope6_id
*)q
;
87 #define SID scope6_ids[ifp->if_index]
89 /* don't initialize if called twice */
90 if (SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]) {
96 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
97 * Should we rather hardcode here?
99 SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = ifp
->if_index
;
101 /* by default, we don't care about scope boundary for these scopes. */
102 SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
] = 1;
103 SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
] = 1;
118 if (scope6_ids
== NULL
) /* paranoid? */
122 * XXX: We need more consistency checks of the relationship among
123 * scopes (e.g. an organization should be larger than a site).
127 * TODO(XXX): after setting, we should reflect the changes to
128 * interface addresses, routing table entries, PCB entries...
133 for (i
= 0; i
< 16; i
++) {
135 idlist
[i
] != scope6_ids
[ifp
->if_index
].s6id_list
[i
]) {
136 if (i
== IPV6_ADDR_SCOPE_LINKLOCAL
&&
137 idlist
[i
] > if_index
) {
139 * XXX: theoretically, there should be no
140 * relationship between link IDs and interface
141 * IDs, but we check the consistency for
142 * safety in later use.
149 * XXX: we must need lots of work in this case,
150 * but we simply set the new value in this initial
153 scope6_ids
[ifp
->if_index
].s6id_list
[i
] = idlist
[i
];
166 if (scope6_ids
== NULL
) /* paranoid? */
169 bcopy(scope6_ids
[ifp
->if_index
].s6id_list
, idlist
,
170 sizeof(scope6_ids
[ifp
->if_index
].s6id_list
));
177 * Get a scope of the address. Node-local, link-local, site-local or global.
181 struct in6_addr
*addr
;
185 if (addr
->s6_addr8
[0] == 0xfe) {
186 scope
= addr
->s6_addr8
[1] & 0xc0;
190 return IPV6_ADDR_SCOPE_LINKLOCAL
;
193 return IPV6_ADDR_SCOPE_SITELOCAL
;
196 return IPV6_ADDR_SCOPE_GLOBAL
; /* just in case */
202 if (addr
->s6_addr8
[0] == 0xff) {
203 scope
= addr
->s6_addr8
[1] & 0x0f;
206 * due to other scope such as reserved,
207 * return scope doesn't work.
210 case IPV6_ADDR_SCOPE_NODELOCAL
:
211 return IPV6_ADDR_SCOPE_NODELOCAL
;
213 case IPV6_ADDR_SCOPE_LINKLOCAL
:
214 return IPV6_ADDR_SCOPE_LINKLOCAL
;
216 case IPV6_ADDR_SCOPE_SITELOCAL
:
217 return IPV6_ADDR_SCOPE_SITELOCAL
;
220 return IPV6_ADDR_SCOPE_GLOBAL
;
225 if (bcmp(&in6addr_loopback
, addr
, sizeof(*addr
) - 1) == 0) {
226 if (addr
->s6_addr8
[15] == 1) /* loopback */
227 return IPV6_ADDR_SCOPE_NODELOCAL
;
228 if (addr
->s6_addr8
[15] == 0) /* unspecified */
229 return IPV6_ADDR_SCOPE_LINKLOCAL
;
232 return IPV6_ADDR_SCOPE_GLOBAL
;
237 struct ifnet
*ifp
, /* must not be NULL */
238 struct in6_addr
*addr
) /* must not be NULL */
240 int scope
= in6_addrscope(addr
);
241 int index
= ifp
->if_index
;
243 if (scope6_ids
== NULL
) /* paranoid? */
245 if (index
>= if_indexlim
)
248 #define SID scope6_ids[index]
250 case IPV6_ADDR_SCOPE_NODELOCAL
:
251 return(-1); /* XXX: is this an appropriate value? */
253 case IPV6_ADDR_SCOPE_LINKLOCAL
:
254 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]);
256 case IPV6_ADDR_SCOPE_SITELOCAL
:
257 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
]);
259 case IPV6_ADDR_SCOPE_ORGLOCAL
:
260 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
]);
263 return(0); /* XXX: treat as global. */
270 struct ifnet
*ifp
) /* note that this might be NULL */
273 * Currently, this function just set the default "link" according to
274 * the given interface.
275 * We might eventually have to separate the notion of "link" from
276 * "interface" and provide a user interface to set the default.
279 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] =
283 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 0;
290 if (scope6_ids
== NULL
) /* paranoid? */
293 bcopy(scope6_ids
[0].s6id_list
, idlist
,
294 sizeof(scope6_ids
[0].s6id_list
));
301 struct in6_addr
*addr
)
303 return(scope6_ids
[0].s6id_list
[in6_addrscope(addr
)]);