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
;
63 * We have some arrays that should be indexed by if_index.
64 * since if_index will grow dynamically, they should grow too.
66 if (scope6_ids
== NULL
|| if_index
>= if_indexlim
) {
70 while (if_index
>= if_indexlim
)
73 /* grow scope index array */
74 n
= if_indexlim
* sizeof(struct scope6_id
);
75 /* XXX: need new malloc type? */
76 q
= (caddr_t
)_MALLOC(n
, M_IFADDR
, M_WAITOK
);
79 bcopy((caddr_t
)scope6_ids
, q
, n
/2);
80 FREE((caddr_t
)scope6_ids
, M_IFADDR
);
82 scope6_ids
= (struct scope6_id
*)q
;
85 #define SID scope6_ids[ifp->if_index]
87 /* don't initialize if called twice */
88 if (SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]) {
93 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
94 * Should we rather hardcode here?
96 SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = ifp
->if_index
;
98 /* by default, we don't care about scope boundary for these scopes. */
99 SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
] = 1;
100 SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
] = 1;
113 if (scope6_ids
== NULL
) /* paranoid? */
117 * XXX: We need more consistency checks of the relationship among
118 * scopes (e.g. an organization should be larger than a site).
122 * TODO(XXX): after setting, we should reflect the changes to
123 * interface addresses, routing table entries, PCB entries...
126 for (i
= 0; i
< 16; i
++) {
128 idlist
[i
] != scope6_ids
[ifp
->if_index
].s6id_list
[i
]) {
129 if (i
== IPV6_ADDR_SCOPE_LINKLOCAL
&&
130 idlist
[i
] > if_index
) {
132 * XXX: theoretically, there should be no
133 * relationship between link IDs and interface
134 * IDs, but we check the consistency for
135 * safety in later use.
141 * XXX: we must need lots of work in this case,
142 * but we simply set the new value in this initial
145 scope6_ids
[ifp
->if_index
].s6id_list
[i
] = idlist
[i
];
157 if (scope6_ids
== NULL
) /* paranoid? */
160 bcopy(scope6_ids
[ifp
->if_index
].s6id_list
, idlist
,
161 sizeof(scope6_ids
[ifp
->if_index
].s6id_list
));
168 * Get a scope of the address. Node-local, link-local, site-local or global.
172 struct in6_addr
*addr
;
176 if (addr
->s6_addr8
[0] == 0xfe) {
177 scope
= addr
->s6_addr8
[1] & 0xc0;
181 return IPV6_ADDR_SCOPE_LINKLOCAL
;
184 return IPV6_ADDR_SCOPE_SITELOCAL
;
187 return IPV6_ADDR_SCOPE_GLOBAL
; /* just in case */
193 if (addr
->s6_addr8
[0] == 0xff) {
194 scope
= addr
->s6_addr8
[1] & 0x0f;
197 * due to other scope such as reserved,
198 * return scope doesn't work.
201 case IPV6_ADDR_SCOPE_NODELOCAL
:
202 return IPV6_ADDR_SCOPE_NODELOCAL
;
204 case IPV6_ADDR_SCOPE_LINKLOCAL
:
205 return IPV6_ADDR_SCOPE_LINKLOCAL
;
207 case IPV6_ADDR_SCOPE_SITELOCAL
:
208 return IPV6_ADDR_SCOPE_SITELOCAL
;
211 return IPV6_ADDR_SCOPE_GLOBAL
;
216 if (bcmp(&in6addr_loopback
, addr
, sizeof(*addr
) - 1) == 0) {
217 if (addr
->s6_addr8
[15] == 1) /* loopback */
218 return IPV6_ADDR_SCOPE_NODELOCAL
;
219 if (addr
->s6_addr8
[15] == 0) /* unspecified */
220 return IPV6_ADDR_SCOPE_LINKLOCAL
;
223 return IPV6_ADDR_SCOPE_GLOBAL
;
228 struct ifnet
*ifp
, /* must not be NULL */
229 struct in6_addr
*addr
) /* must not be NULL */
231 int scope
= in6_addrscope(addr
);
232 int index
= ifp
->if_index
;
234 if (scope6_ids
== NULL
) /* paranoid? */
236 if (index
>= if_indexlim
)
239 #define SID scope6_ids[index]
241 case IPV6_ADDR_SCOPE_NODELOCAL
:
242 return(-1); /* XXX: is this an appropriate value? */
244 case IPV6_ADDR_SCOPE_LINKLOCAL
:
245 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]);
247 case IPV6_ADDR_SCOPE_SITELOCAL
:
248 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
]);
250 case IPV6_ADDR_SCOPE_ORGLOCAL
:
251 return(SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
]);
254 return(0); /* XXX: treat as global. */
261 struct ifnet
*ifp
) /* note that this might be NULL */
264 * Currently, this function just set the default "link" according to
265 * the given interface.
266 * We might eventually have to separate the notion of "link" from
267 * "interface" and provide a user interface to set the default.
270 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] =
274 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 0;
281 if (scope6_ids
== NULL
) /* paranoid? */
284 bcopy(scope6_ids
[0].s6id_list
, idlist
,
285 sizeof(scope6_ids
[0].s6id_list
));
292 struct in6_addr
*addr
)
294 return(scope6_ids
[0].s6id_list
[in6_addrscope(addr
)]);