]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/scope6.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / netinet6 / scope6.c
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 $ */
3
4 /*
5 * Copyright (C) 2000 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/systm.h>
38 #include <sys/queue.h>
39
40 #include <net/route.h>
41 #include <net/if.h>
42
43 #include <netinet/in.h>
44
45 #include <netinet6/in6_var.h>
46 #include <netinet6/scope6_var.h>
47
48 struct scope6_id {
49 /*
50 * 16 is correspondent to 4bit multicast scope field.
51 * i.e. from node-local to global with some reserved/unassigned types.
52 */
53 u_int32_t s6id_list[16];
54 };
55 static size_t if_indexlim = 8;
56 struct scope6_id *scope6_ids = NULL;
57
58 void
59 scope6_ifattach(
60 struct ifnet *ifp)
61 {
62 /*
63 * We have some arrays that should be indexed by if_index.
64 * since if_index will grow dynamically, they should grow too.
65 */
66 if (scope6_ids == NULL || if_index >= if_indexlim) {
67 size_t n;
68 caddr_t q;
69
70 while (if_index >= if_indexlim)
71 if_indexlim <<= 1;
72
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);
77 bzero(q, n);
78 if (scope6_ids) {
79 bcopy((caddr_t)scope6_ids, q, n/2);
80 FREE((caddr_t)scope6_ids, M_IFADDR);
81 }
82 scope6_ids = (struct scope6_id *)q;
83 }
84
85 #define SID scope6_ids[ifp->if_index]
86
87 /* don't initialize if called twice */
88 if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) {
89 return;
90 }
91
92 /*
93 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
94 * Should we rather hardcode here?
95 */
96 SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
97 #if MULTI_SCOPE
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;
101 #endif
102 #undef SID
103 }
104
105 int
106 scope6_set(
107 struct ifnet *ifp,
108 u_int32_t *idlist)
109 {
110 int i;
111 int error = 0;
112
113 if (scope6_ids == NULL) /* paranoid? */
114 return(EINVAL);
115
116 /*
117 * XXX: We need more consistency checks of the relationship among
118 * scopes (e.g. an organization should be larger than a site).
119 */
120
121 /*
122 * TODO(XXX): after setting, we should reflect the changes to
123 * interface addresses, routing table entries, PCB entries...
124 */
125
126 for (i = 0; i < 16; i++) {
127 if (idlist[i] &&
128 idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) {
129 if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
130 idlist[i] > if_index) {
131 /*
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.
136 */
137 return(EINVAL);
138 }
139
140 /*
141 * XXX: we must need lots of work in this case,
142 * but we simply set the new value in this initial
143 * implementation.
144 */
145 scope6_ids[ifp->if_index].s6id_list[i] = idlist[i];
146 }
147 }
148
149 return(error);
150 }
151
152 int
153 scope6_get(
154 struct ifnet *ifp,
155 u_int32_t *idlist)
156 {
157 if (scope6_ids == NULL) /* paranoid? */
158 return(EINVAL);
159
160 bcopy(scope6_ids[ifp->if_index].s6id_list, idlist,
161 sizeof(scope6_ids[ifp->if_index].s6id_list));
162
163 return(0);
164 }
165
166
167 /*
168 * Get a scope of the address. Node-local, link-local, site-local or global.
169 */
170 int
171 in6_addrscope(addr)
172 struct in6_addr *addr;
173 {
174 int scope;
175
176 if (addr->s6_addr8[0] == 0xfe) {
177 scope = addr->s6_addr8[1] & 0xc0;
178
179 switch (scope) {
180 case 0x80:
181 return IPV6_ADDR_SCOPE_LINKLOCAL;
182 break;
183 case 0xc0:
184 return IPV6_ADDR_SCOPE_SITELOCAL;
185 break;
186 default:
187 return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
188 break;
189 }
190 }
191
192
193 if (addr->s6_addr8[0] == 0xff) {
194 scope = addr->s6_addr8[1] & 0x0f;
195
196 /*
197 * due to other scope such as reserved,
198 * return scope doesn't work.
199 */
200 switch (scope) {
201 case IPV6_ADDR_SCOPE_NODELOCAL:
202 return IPV6_ADDR_SCOPE_NODELOCAL;
203 break;
204 case IPV6_ADDR_SCOPE_LINKLOCAL:
205 return IPV6_ADDR_SCOPE_LINKLOCAL;
206 break;
207 case IPV6_ADDR_SCOPE_SITELOCAL:
208 return IPV6_ADDR_SCOPE_SITELOCAL;
209 break;
210 default:
211 return IPV6_ADDR_SCOPE_GLOBAL;
212 break;
213 }
214 }
215
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;
221 }
222
223 return IPV6_ADDR_SCOPE_GLOBAL;
224 }
225
226 int
227 in6_addr2scopeid(
228 struct ifnet *ifp, /* must not be NULL */
229 struct in6_addr *addr) /* must not be NULL */
230 {
231 int scope = in6_addrscope(addr);
232 int index = ifp->if_index;
233
234 if (scope6_ids == NULL) /* paranoid? */
235 return(0); /* XXX */
236 if (index >= if_indexlim)
237 return(0); /* XXX */
238
239 #define SID scope6_ids[index]
240 switch(scope) {
241 case IPV6_ADDR_SCOPE_NODELOCAL:
242 return(-1); /* XXX: is this an appropriate value? */
243
244 case IPV6_ADDR_SCOPE_LINKLOCAL:
245 return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
246
247 case IPV6_ADDR_SCOPE_SITELOCAL:
248 return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
249
250 case IPV6_ADDR_SCOPE_ORGLOCAL:
251 return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
252
253 default:
254 return(0); /* XXX: treat as global. */
255 }
256 #undef SID
257 }
258
259 void
260 scope6_setdefault(
261 struct ifnet *ifp) /* note that this might be NULL */
262 {
263 /*
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.
268 */
269 if (ifp) {
270 scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
271 ifp->if_index;
272 }
273 else
274 scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
275 }
276
277 int
278 scope6_get_default(
279 u_int32_t *idlist)
280 {
281 if (scope6_ids == NULL) /* paranoid? */
282 return(EINVAL);
283
284 bcopy(scope6_ids[0].s6id_list, idlist,
285 sizeof(scope6_ids[0].s6id_list));
286
287 return(0);
288 }
289
290 u_int32_t
291 scope6_addr2default(
292 struct in6_addr *addr)
293 {
294 return(scope6_ids[0].s6id_list[in6_addrscope(addr)]);
295 }