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>
48 extern lck_mtx_t
*scope6_mutex
;
52 * 16 is correspondent to 4bit multicast scope field.
53 * i.e. from node-local to global with some reserved/unassigned types.
55 u_int32_t s6id_list
[16];
57 static size_t if_scope_indexlim
= 8;
58 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 lck_mtx_lock(scope6_mutex
);
69 if (scope6_ids
== NULL
|| if_index
>= if_scope_indexlim
) {
72 int newlim
= if_scope_indexlim
;
74 while (if_index
>= newlim
)
77 /* grow scope index array */
78 n
= newlim
* sizeof(struct scope6_id
);
79 /* XXX: need new malloc type? */
80 q
= (caddr_t
)_MALLOC(n
, M_IFADDR
, M_WAITOK
);
82 lck_mtx_unlock(scope6_mutex
);
85 if_scope_indexlim
= newlim
;
88 bcopy((caddr_t
)scope6_ids
, q
, n
/2);
89 FREE((caddr_t
)scope6_ids
, M_IFADDR
);
91 scope6_ids
= (struct scope6_id
*)q
;
94 #define SID scope6_ids[ifp->if_index]
96 /* don't initialize if called twice */
97 if (SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]) {
98 lck_mtx_unlock(scope6_mutex
);
103 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
104 * Should we rather hardcode here?
106 SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = ifp
->if_index
;
108 /* by default, we don't care about scope boundary for these scopes. */
109 SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
] = 1;
110 SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
] = 1;
113 lck_mtx_unlock(scope6_mutex
);
126 if (scope6_ids
== NULL
) /* paranoid? */
130 * XXX: We need more consistency checks of the relationship among
131 * scopes (e.g. an organization should be larger than a site).
135 * TODO(XXX): after setting, we should reflect the changes to
136 * interface addresses, routing table entries, PCB entries...
139 lck_mtx_lock(scope6_mutex
);
140 for (i
= 0; i
< 16; i
++) {
142 idlist
[i
] != scope6_ids
[ifp
->if_index
].s6id_list
[i
]) {
143 if (i
== IPV6_ADDR_SCOPE_LINKLOCAL
&&
144 idlist
[i
] > if_index
) {
146 * XXX: theoretically, there should be no
147 * relationship between link IDs and interface
148 * IDs, but we check the consistency for
149 * safety in later use.
151 lck_mtx_unlock(scope6_mutex
);
156 * XXX: we must need lots of work in this case,
157 * but we simply set the new value in this initial
160 scope6_ids
[ifp
->if_index
].s6id_list
[i
] = idlist
[i
];
163 lck_mtx_unlock(scope6_mutex
);
173 if (scope6_ids
== NULL
) /* paranoid? */
176 lck_mtx_lock(scope6_mutex
);
177 bcopy(scope6_ids
[ifp
->if_index
].s6id_list
, idlist
,
178 sizeof(scope6_ids
[ifp
->if_index
].s6id_list
));
179 lck_mtx_unlock(scope6_mutex
);
186 * Get a scope of the address. Node-local, link-local, site-local or global.
190 struct in6_addr
*addr
;
194 if (addr
->s6_addr8
[0] == 0xfe) {
195 scope
= addr
->s6_addr8
[1] & 0xc0;
199 return IPV6_ADDR_SCOPE_LINKLOCAL
;
202 return IPV6_ADDR_SCOPE_SITELOCAL
;
205 return IPV6_ADDR_SCOPE_GLOBAL
; /* just in case */
211 if (addr
->s6_addr8
[0] == 0xff) {
212 scope
= addr
->s6_addr8
[1] & 0x0f;
215 * due to other scope such as reserved,
216 * return scope doesn't work.
219 case IPV6_ADDR_SCOPE_NODELOCAL
:
220 return IPV6_ADDR_SCOPE_NODELOCAL
;
222 case IPV6_ADDR_SCOPE_LINKLOCAL
:
223 return IPV6_ADDR_SCOPE_LINKLOCAL
;
225 case IPV6_ADDR_SCOPE_SITELOCAL
:
226 return IPV6_ADDR_SCOPE_SITELOCAL
;
229 return IPV6_ADDR_SCOPE_GLOBAL
;
234 if (bcmp(&in6addr_loopback
, addr
, sizeof(*addr
) - 1) == 0) {
235 if (addr
->s6_addr8
[15] == 1) /* loopback */
236 return IPV6_ADDR_SCOPE_NODELOCAL
;
237 if (addr
->s6_addr8
[15] == 0) /* unspecified */
238 return IPV6_ADDR_SCOPE_LINKLOCAL
;
241 return IPV6_ADDR_SCOPE_GLOBAL
;
246 struct ifnet
*ifp
, /* must not be NULL */
247 struct in6_addr
*addr
) /* must not be NULL */
249 int scope
= in6_addrscope(addr
);
250 int index
= ifp
->if_index
;
253 if (scope6_ids
== NULL
) /* paranoid? */
256 lck_mtx_lock(scope6_mutex
);
257 if (index
>= if_scope_indexlim
) {
258 lck_mtx_unlock(scope6_mutex
);
262 #define SID scope6_ids[index]
264 case IPV6_ADDR_SCOPE_NODELOCAL
:
265 retid
= -1; /* XXX: is this an appropriate value? */
267 case IPV6_ADDR_SCOPE_LINKLOCAL
:
268 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
];
270 case IPV6_ADDR_SCOPE_SITELOCAL
:
271 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
];
273 case IPV6_ADDR_SCOPE_ORGLOCAL
:
274 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
];
277 break; /* XXX: value 0, treat as global. */
281 lck_mtx_unlock(scope6_mutex
);
287 struct ifnet
*ifp
) /* note that this might be NULL */
290 * Currently, this function just set the default "link" according to
291 * the given interface.
292 * We might eventually have to separate the notion of "link" from
293 * "interface" and provide a user interface to set the default.
295 lck_mtx_lock(scope6_mutex
);
297 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] =
301 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 0;
302 lck_mtx_unlock(scope6_mutex
);
309 if (scope6_ids
== NULL
) /* paranoid? */
312 lck_mtx_lock(scope6_mutex
);
313 bcopy(scope6_ids
[0].s6id_list
, idlist
,
314 sizeof(scope6_ids
[0].s6id_list
));
315 lck_mtx_unlock(scope6_mutex
);
322 struct in6_addr
*addr
)
325 int index
= in6_addrscope(addr
);
326 lck_mtx_lock(scope6_mutex
);
327 id
= scope6_ids
[0].s6id_list
[index
];
328 lck_mtx_unlock(scope6_mutex
);