]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/in6_prefix.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_prefix.c
CommitLineData
1c79356b
A
1/* $KAME: in6_prefix.c,v 1.27 2000/03/29 23:13:13 itojun Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1982, 1986, 1991, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)in.c 8.2 (Berkeley) 11/15/93
65 */
66
67#include <sys/param.h>
1c79356b
A
68#include <sys/malloc.h>
69#include <sys/kernel.h>
70#include <sys/socket.h>
71#include <sys/socketvar.h>
72#include <sys/sockio.h>
73#include <sys/systm.h>
74#include <sys/syslog.h>
1c79356b 75#include <sys/proc.h>
1c79356b
A
76
77#include <net/if.h>
78
79#include <netinet/in.h>
80#include <netinet/in_var.h>
81#include <netinet/ip6.h>
82#include <netinet6/in6_prefix.h>
83#include <netinet6/ip6_var.h>
84
9bccf70c
A
85#ifdef __APPLE__
86#define M_IP6RR M_IP6MISC
87#define M_RR_ADDR M_IP6MISC
88#else
89static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix");
90static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid");
1c79356b
A
91#endif
92
93struct rr_prhead rr_prefix;
94
95#include <net/net_osdep.h>
96
97static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
98 struct rp_addr *rap));
99static int create_ra_entry __P((struct rp_addr **rapp));
100static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp));
101static void free_rp_entries __P((struct rr_prefix *rpp));
102static int link_stray_ia6s __P((struct rr_prefix *rpp));
103static void rp_remove __P((struct rr_prefix *rpp));
104
105/*
106 * Copy bits from src to tgt, from off bit for len bits.
107 * Caller must specify collect tgtsize and srcsize.
108 */
109static void
110bit_copy(char *tgt, u_int tgtsize, char *src, u_int srcsize,
111 u_int off, u_int len)
112{
113 char *sp, *tp;
114
115 /* arg values check */
116 if (srcsize < off || srcsize < (off + len) ||
117 tgtsize < off || tgtsize < (off + len)) {
118 log(LOG_ERR,
119 "in6_prefix.c: bit_copy: invalid args: srcsize %d,\n"
120 "tgtsize %d, off %d, len %d\n", srcsize, tgtsize, off,
121 len);
122 return;
123 }
124
125 /* search start point */
126 for (sp = src, tp = tgt; off >= 8; sp++, tp++)
127 off-=8;
128 /* copy starting bits */
129 if (off) {
130 char setbit;
131 int startbits;
132
133 startbits = min((8 - off), len);
134
135 for (setbit = (0x80 >> off); startbits;
136 setbit >>= 1, startbits--, len--)
137 *tp |= (setbit & *sp);
138 tp++;
139 sp++;
140 }
141 /* copy midium bits */
142 for (; len >= 8; sp++, tp++) {
143 *tp = *sp;
144 len-=8;
145 }
146 /* copy ending bits */
147 if (len) {
148 char setbit;
149
150 for (setbit = 0x80; len; setbit >>= 1, len--)
151 *tp |= (setbit & *sp);
152 }
153}
154
155static struct ifprefix *
156in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst)
157{
158 struct ifprefix *ifpr;
159
160 /* search matched prefix */
9bccf70c
A
161 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
162 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
163 {
1c79356b
A
164 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
165 ifpr->ifpr_type != IN6_PREFIX_RR)
166 continue;
167 if (plen <= in6_matchlen(dst, IFPR_IN6(ifpr)))
168 break;
169 }
170 return (ifpr);
171}
172
173/*
174 * Search prefix which matches arg prefix as specified in
175 * draft-ietf-ipngwg-router-renum-08.txt
176 */
177static struct rr_prefix *
178search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
179{
180 struct ifprefix *ifpr;
181 struct ifaddr *ifa;
182 struct rr_prefix *rpp;
183
184 /* search matched prefix */
185 ifpr = in6_prefixwithifp(ifp, ipr->ipr_plen,
186 &ipr->ipr_prefix.sin6_addr);
187 if (ifpr != NULL)
188 return ifpr2rp(ifpr);
189
190 /*
191 * search matched addr, and then search prefix
192 * which matches the addr
193 */
194
9bccf70c 195 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1c79356b
A
196 {
197 if (ifa->ifa_addr->sa_family != AF_INET6)
198 continue;
199 if (ipr->ipr_plen <=
200 in6_matchlen(&ipr->ipr_prefix.sin6_addr, IFA_IN6(ifa)))
201 break;
202 }
203 if (ifa == NULL)
204 return NULL;
205
206 rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
207 if (rpp != 0)
208 return rpp;
209
9bccf70c
A
210 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
211 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
212 {
1c79356b
A
213 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
214 ifpr->ifpr_type != IN6_PREFIX_RR)
215 continue;
216 if (ifpr->ifpr_plen <= in6_matchlen(IFA_IN6(ifa),
217 IFPR_IN6(ifpr)))
218 break;
219 }
220 if (ifpr != NULL)
221 log(LOG_ERR, "in6_prefix.c: search_matched_prefix: addr %s"
222 "has no pointer to prefix %s\n", ip6_sprintf(IFA_IN6(ifa)),
223 ip6_sprintf(IFPR_IN6(ifpr)));
224 return ifpr2rp(ifpr);
225}
226
227/*
228 * Search prefix which matches arg prefix as specified in
229 * draft-ietf-ipngwg-router-renum-08.txt, and mark it if exists.
230 * Return 1 if anything matched, and 0 if nothing matched.
231 */
232static int
233mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
234{
235 struct ifprefix *ifpr;
236 struct ifaddr *ifa;
237 int matchlen, matched = 0;
238
239 /* search matched prefixes */
9bccf70c
A
240 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
241 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
242 {
1c79356b
A
243 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
244 ifpr->ifpr_type != IN6_PREFIX_RR)
245 continue;
246 matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr,
247 IFPR_IN6(ifpr));
248 if (irr->irr_m_minlen > ifpr->ifpr_plen ||
249 irr->irr_m_maxlen < ifpr->ifpr_plen ||
250 irr->irr_m_len > matchlen)
251 continue;
252 matched = 1;
253 ifpr2rp(ifpr)->rp_statef_addmark = 1;
254 if (cmd == SIOCCIFPREFIX_IN6)
255 ifpr2rp(ifpr)->rp_statef_delmark = 1;
256 }
257
258 /*
259 * search matched addr, and then search prefixes
260 * which matche the addr
261 */
9bccf70c 262 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
1c79356b
A
263 {
264 struct rr_prefix *rpp;
265
266 if (ifa->ifa_addr->sa_family != AF_INET6)
267 continue;
268 matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr,
269 IFA_IN6(ifa));
270 if (irr->irr_m_minlen > matchlen ||
271 irr->irr_m_maxlen < matchlen || irr->irr_m_len > matchlen)
272 continue;
273 rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
274 if (rpp != 0) {
275 matched = 1;
276 rpp->rp_statef_addmark = 1;
277 if (cmd == SIOCCIFPREFIX_IN6)
278 rpp->rp_statef_delmark = 1;
279 } else
280 log(LOG_WARNING, "in6_prefix.c: mark_matched_prefixes:"
281 "no back pointer to ifprefix for %s. "
282 "ND autoconfigured addr?\n",
283 ip6_sprintf(IFA_IN6(ifa)));
284 }
285 return matched;
286}
287
288/*
289 * Mark global prefixes as to be deleted.
290 */
291static void
292delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr)
293{
294 struct ifprefix *ifpr;
295
296 /* search matched prefixes */
9bccf70c
A
297 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
298 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
299 {
1c79356b
A
300 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
301 ifpr->ifpr_type != IN6_PREFIX_RR)
302 continue;
303 /* mark delete global prefix */
304 if (in6_addrscope(RP_IN6(ifpr2rp(ifpr))) ==
305 IPV6_ADDR_SCOPE_GLOBAL)
306 ifpr2rp(ifpr)->rp_statef_delmark = 1;
307 }
308}
309
310/* Unmark prefixes */
311static void
312unmark_prefixes(struct ifnet *ifp)
313{
314 struct ifprefix *ifpr;
315
316 /* unmark all prefix */
9bccf70c
A
317 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
318 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
319 {
1c79356b
A
320 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
321 ifpr->ifpr_type != IN6_PREFIX_RR)
322 continue;
323 /* unmark prefix */
324 ifpr2rp(ifpr)->rp_statef_addmark = 0;
325 ifpr2rp(ifpr)->rp_statef_delmark = 0;
326 }
327}
328
329static void
330init_prefix_ltimes(struct rr_prefix *rpp)
331{
1c79356b
A
332
333 if (rpp->rp_pltime == RR_INFINITE_LIFETIME ||
334 rpp->rp_rrf_decrprefd == 0)
335 rpp->rp_preferred = 0;
336 else
337 rpp->rp_preferred = time_second + rpp->rp_pltime;
338 if (rpp->rp_vltime == RR_INFINITE_LIFETIME ||
339 rpp->rp_rrf_decrvalid == 0)
340 rpp->rp_expire = 0;
341 else
342 rpp->rp_expire = time_second + rpp->rp_vltime;
343}
344
345static int
346rr_are_ifid_equal(struct in6_addr *ii1, struct in6_addr *ii2, int ii_len)
347{
348 int ii_bytelen, ii_bitlen;
349 int p_bytelen, p_bitlen;
350
351 /* sanity check */
352 if (1 > ii_len ||
353 ii_len > 124) { /* as RFC2373, prefix is at least 4 bit */
354 log(LOG_ERR, "rr_are_ifid_equal: invalid ifid length(%d)\n",
355 ii_len);
356 return(0);
357 }
358
359 ii_bytelen = ii_len / 8;
360 ii_bitlen = ii_len % 8;
361
362 p_bytelen = sizeof(struct in6_addr) - ii_bytelen - 1;
363 p_bitlen = 8 - ii_bitlen;
364
365 if (bcmp(ii1->s6_addr + p_bytelen + 1, ii2->s6_addr + p_bytelen + 1,
366 ii_bytelen))
367 return(0);
368 if (((ii1->s6_addr[p_bytelen] << p_bitlen) & 0xff) !=
369 ((ii2->s6_addr[p_bytelen] << p_bitlen) & 0xff))
370 return(0);
371
372 return(1);
373}
374
375static struct rp_addr *
376search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid)
377{
378 struct rp_addr *rap;
379
9bccf70c
A
380 LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
381 {
1c79356b
A
382 if (rr_are_ifid_equal(ifid, &rap->ra_ifid,
383 (sizeof(struct in6_addr) << 3) -
384 rpp->rp_plen))
385 break;
9bccf70c 386 }
1c79356b
A
387 return rap;
388}
389
390static int
9bccf70c 391assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
1c79356b
A
392{
393 int error = 0;
394 struct rp_addr *rap;
395 int s;
396
397 if ((error = create_ra_entry(&rap)) != 0)
398 return error;
399
400 /* copy interface id part */
401 bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
402 (caddr_t)IA6_IN6(ia),
403 sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen);
404 /* link to ia, and put into list */
405 rap->ra_addr = ia;
9bccf70c 406 ifaref(&rap->ra_addr->ia_ifa);
1c79356b
A
407#if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */
408 ia->ia6_ifpr = rp2ifpr(rpp);
409#endif
410 s = splnet();
411 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
412 splx(s);
413
414 return 0;
415}
416
9bccf70c
A
417/*
418 * add a link-local address to an interface. we will add new interface address
419 * (prefix database + new interface id).
420 */
1c79356b
A
421static int
422in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
423{
424 struct rr_prefix *rpp;
425 struct rp_addr *rap;
426 struct socket so;
427 int error, s;
428
429 if ((error = create_ra_entry(&rap)) != 0)
430 return(error);
431 /* copy interface id part */
432 bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
433 (caddr_t)IA6_IN6(ia), sizeof(*IA6_IN6(ia)) << 3,
434 64, (sizeof(rap->ra_ifid) << 3) - 64);
435 /* XXX: init dummy so */
436 bzero(&so, sizeof(so));
437 /* insert into list */
1c79356b 438 LIST_FOREACH(rpp, &rr_prefix, rp_entry)
1c79356b 439 {
9bccf70c
A
440 /*
441 * do not attempt to add an address, if ifp does not match
442 */
443 if (rpp->rp_ifp != ia->ia_ifp)
444 continue;
445
1c79356b
A
446 s = splnet();
447 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
448 splx(s);
449 add_each_addr(&so, rpp, rap);
450 }
451 return 0;
452}
453
9bccf70c
A
454/*
455 * add an address to an interface. if the interface id portion is new,
456 * we will add new interface address (prefix database + new interface id).
457 */
1c79356b
A
458int
459in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
460{
461 int plen = (sizeof(*IA6_IN6(ia)) << 3) - iilen;
462 struct ifprefix *ifpr;
463 struct rp_addr *rap;
464 int error = 0;
465
466 if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia)))
467 return(in6_prefix_add_llifid(iilen, ia));
468 ifpr = in6_prefixwithifp(ia->ia_ifp, plen, IA6_IN6(ia));
469 if (ifpr == NULL) {
470 struct rr_prefix rp;
471 struct socket so;
9bccf70c 472 int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */
1c79356b
A
473
474 /* allocate a prefix for ia, with default properties */
475
476 /* init rp */
477 bzero(&rp, sizeof(rp));
478 rp.rp_type = IN6_PREFIX_RR;
479 rp.rp_ifp = ia->ia_ifp;
480 rp.rp_plen = pplen;
481 rp.rp_prefix.sin6_len = sizeof(rp.rp_prefix);
482 rp.rp_prefix.sin6_family = AF_INET6;
483 bit_copy((char *)RP_IN6(&rp), sizeof(*RP_IN6(&rp)) << 3,
484 (char *)&ia->ia_addr.sin6_addr,
485 sizeof(ia->ia_addr.sin6_addr) << 3,
486 0, pplen);
487 rp.rp_vltime = rp.rp_pltime = RR_INFINITE_LIFETIME;
488 rp.rp_raf_onlink = 1;
489 rp.rp_raf_auto = 1;
490 /* Is some FlagMasks for rrf necessary? */
491 rp.rp_rrf_decrvalid = rp.rp_rrf_decrprefd = 0;
492 rp.rp_origin = PR_ORIG_RR; /* can be renumbered */
493
494 /* create ra_entry */
495 error = link_stray_ia6s(&rp);
496 if (error != 0) {
497 free_rp_entries(&rp);
498 return error;
499 }
500
501 /* XXX: init dummy so */
502 bzero(&so, sizeof(so));
1c79356b
A
503
504 error = add_each_prefix(&so, &rp);
505
506 /* free each rp_addr entry */
507 free_rp_entries(&rp);
508
509 if (error != 0)
510 return error;
511
512 /* search again */
513 ifpr = in6_prefixwithifp(ia->ia_ifp, pplen, IA6_IN6(ia));
514 if (ifpr == NULL)
515 return 0;
516 }
517 rap = search_ifidwithprefix(ifpr2rp(ifpr), IA6_IN6(ia));
518 if (rap != NULL) {
519 if (rap->ra_addr == NULL) {
520 rap->ra_addr = ia;
9bccf70c 521 ifaref(&rap->ra_addr->ia_ifa);
1c79356b
A
522 } else if (rap->ra_addr != ia) {
523 /* There may be some inconsistencies between addrs. */
524 log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix"
9bccf70c 525 " already has another ia %p(%s) on its ifid list\n",
1c79356b
A
526 ip6_sprintf(IA6_IN6(ia)), plen,
527 rap->ra_addr,
528 ip6_sprintf(IA6_IN6(rap->ra_addr)));
529 return EADDRINUSE /* XXX */;
530 }
531 ia->ia6_ifpr = ifpr;
532 return 0;
533 }
9bccf70c 534 error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia);
1c79356b
A
535 if (error == 0)
536 ia->ia6_ifpr = ifpr;
537 return (error);
538}
539
540void
541in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
542{
543 struct rp_addr *rap;
544
545 if (ia->ia6_ifpr == NULL)
546 return;
547 rap = search_ifidwithprefix(ifpr2rp(ia->ia6_ifpr), IA6_IN6(ia));
548 if (rap != NULL) {
549 int s = splnet();
550 LIST_REMOVE(rap, ra_entry);
551 splx(s);
552 if (rap->ra_addr)
9bccf70c
A
553 ifafree(&rap->ra_addr->ia_ifa);
554 FREE(rap, M_RR_ADDR);
1c79356b
A
555 }
556
1c79356b 557 if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead))
1c79356b
A
558 rp_remove(ifpr2rp(ia->ia6_ifpr));
559}
560
561void
562in6_purgeprefix(ifp)
563 struct ifnet *ifp;
564{
565 struct ifprefix *ifpr, *nextifpr;
566
567 /* delete prefixes before ifnet goes away */
1c79356b
A
568 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
569 ifpr = nextifpr)
1c79356b 570 {
1c79356b 571 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
1c79356b
A
572 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
573 ifpr->ifpr_type != IN6_PREFIX_RR)
574 continue;
575 (void)delete_each_prefix(ifpr2rp(ifpr), PR_ORIG_KERNEL);
576 }
577}
578
579static void
580add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
581{
582 struct in6_ifaddr *ia6;
583 struct in6_aliasreq ifra;
584 int error;
585
586 /* init ifra */
587 bzero(&ifra, sizeof(ifra));
588 strncpy(ifra.ifra_name, if_name(rpp->rp_ifp), sizeof(ifra.ifra_name));
589 ifra.ifra_addr.sin6_family = ifra.ifra_prefixmask.sin6_family =
590 AF_INET6;
591 ifra.ifra_addr.sin6_len = ifra.ifra_prefixmask.sin6_len =
592 sizeof(ifra.ifra_addr);
593 /* copy prefix part */
594 bit_copy((char *)&ifra.ifra_addr.sin6_addr,
595 sizeof(ifra.ifra_addr.sin6_addr) << 3,
596 (char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
597 0, rpp->rp_plen);
598 /* copy interface id part */
599 bit_copy((char *)&ifra.ifra_addr.sin6_addr,
600 sizeof(ifra.ifra_addr.sin6_addr) << 3,
601 (char *)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
602 rpp->rp_plen, (sizeof(rap->ra_ifid) << 3) - rpp->rp_plen);
603 in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen);
604 /* don't care ifra_flags for now */
605
9bccf70c
A
606 /*
607 * XXX: if we did this with finite lifetime values, the lifetimes would
608 * decrese in time and never incremented.
609 * we should need more clarifications on the prefix mechanism...
610 */
611 ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime;
612 ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime;
613
1c79356b
A
614 ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr);
615 if (ia6 != NULL) {
616 if (ia6->ia6_ifpr == NULL) {
617 /* link this addr and the prefix each other */
9bccf70c
A
618 if (rap->ra_addr)
619 ifafree(&rap->ra_addr->ia_ifa);
1c79356b 620 rap->ra_addr = ia6;
9bccf70c 621 ifaref(&rap->ra_addr->ia_ifa);
1c79356b
A
622 ia6->ia6_ifpr = rp2ifpr(rpp);
623 return;
624 }
625 if (ia6->ia6_ifpr == rp2ifpr(rpp)) {
9bccf70c
A
626 if (rap->ra_addr)
627 ifafree(&rap->ra_addr->ia_ifa);
1c79356b 628 rap->ra_addr = ia6;
9bccf70c 629 ifaref(&rap->ra_addr->ia_ifa);
1c79356b
A
630 return;
631 }
632 /*
633 * The addr is already assigned to other
634 * prefix.
635 * There may be some inconsistencies between
636 * prefixes.
637 * e.g. overraped prefixes with common starting
638 * part and different plefixlen.
639 * Or, completely duplicated prefixes?
640 * log it and return.
641 */
9bccf70c
A
642 log(LOG_ERR,
643 "in6_prefix.c: add_each_addr: addition of an addr %s/%d "
644 "failed because there is already another addr %s/%d\n",
1c79356b
A
645 ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
646 ip6_sprintf(IA6_IN6(ia6)),
9bccf70c 647 in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL));
1c79356b
A
648 return;
649 }
650 /* propagate ANYCAST flag if it is set for ancestor addr */
651 if (rap->ra_flags.anycast != 0)
652 ifra.ifra_flags |= IN6_IFF_ANYCAST;
9bccf70c
A
653 error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp,
654 current_proc());
655 if (error != 0) {
1c79356b
A
656 log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
657 "%s/%d failed because in6_control failed for error %d\n",
658 ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
659 error);
660 return;
9bccf70c 661 }
1c79356b
A
662
663 /*
664 * link beween this addr and the prefix will be done
665 * in in6_prefix_add_ifid
666 */
667}
668
669static int
670rrpr_update(struct socket *so, struct rr_prefix *new)
671{
672 struct rr_prefix *rpp;
673 struct ifprefix *ifpr;
674 struct rp_addr *rap;
675 int s;
676
677 /* search existing prefix */
9bccf70c
A
678 for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr;
679 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
680 {
1c79356b
A
681 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
682 ifpr->ifpr_type != IN6_PREFIX_RR)
683 continue;
684 if (ifpr->ifpr_plen == new->rp_plen &&
685 in6_are_prefix_equal(IFPR_IN6(ifpr), RP_IN6(new),
686 ifpr->ifpr_plen))
687 break;
688 }
689 rpp = ifpr2rp(ifpr);
690 if (rpp != NULL) {
691 /*
692 * We got a prefix which we have seen in the past.
693 */
694 /*
695 * If the origin of the already-installed prefix is more
696 * preferable than the new one, ignore installation request.
697 */
698 if (rpp->rp_origin > new->rp_origin)
699 return(EPERM);
700
701 /* update prefix information */
702 rpp->rp_flags.prf_ra = new->rp_flags.prf_ra;
703 if (rpp->rp_origin >= PR_ORIG_RR)
704 rpp->rp_flags.prf_rr = new->rp_flags.prf_rr;
705 rpp->rp_vltime = new->rp_vltime;
706 rpp->rp_pltime = new->rp_pltime;
707 rpp->rp_expire = new->rp_expire;
708 rpp->rp_preferred = new->rp_preferred;
709 rpp->rp_statef_delmark = 0; /* cancel deletion */
710 /*
711 * Interface id related update.
712 * add rp_addr entries in new into rpp, if they have not
713 * been already included in rpp.
714 */
1c79356b 715 while (!LIST_EMPTY(&new->rp_addrhead))
1c79356b
A
716 {
717 rap = LIST_FIRST(&new->rp_addrhead);
718 LIST_REMOVE(rap, ra_entry);
719 if (search_ifidwithprefix(rpp, &rap->ra_ifid)
720 != NULL) {
721 if (rap->ra_addr)
9bccf70c
A
722 ifafree(&rap->ra_addr->ia_ifa);
723 FREE(rap, M_RR_ADDR);
1c79356b
A
724 continue;
725 }
726 s = splnet();
727 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
728 splx(s);
729 }
730 } else {
731 /*
732 * We got a fresh prefix.
733 */
734 /* create new prefix */
9bccf70c 735 rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IP6RR,
1c79356b
A
736 M_NOWAIT);
737 if (rpp == NULL) {
738 log(LOG_ERR, "in6_prefix.c: rrpr_update:%d"
739 ": ENOBUFS for rr_prefix\n", __LINE__);
740 return(ENOBUFS);
741 }
742 /* initilization */
743 *rpp = *new;
744 LIST_INIT(&rpp->rp_addrhead);
745 /* move rp_addr entries of new to rpp */
1c79356b 746 while (!LIST_EMPTY(&new->rp_addrhead))
1c79356b
A
747 {
748 rap = LIST_FIRST(&new->rp_addrhead);
749 LIST_REMOVE(rap, ra_entry);
750 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
751 }
752
753 /* let rp_ifpr.ifpr_prefix point rr_prefix. */
754 rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix;
755 /* link rr_prefix entry to if_prefixlist */
756 {
757 struct ifnet *ifp = rpp->rp_ifp;
758 struct ifprefix *ifpr;
759
9bccf70c
A
760 if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead))
761 != NULL) {
762 for ( ; TAILQ_NEXT(ifpr, ifpr_list);
763 ifpr = TAILQ_NEXT(ifpr, ifpr_list))
1c79356b 764 continue;
9bccf70c 765 TAILQ_NEXT(ifpr, ifpr_list) = rp2ifpr(rpp);
1c79356b 766 } else
9bccf70c
A
767 TAILQ_FIRST(&ifp->if_prefixhead) =
768 rp2ifpr(rpp);
1c79356b
A
769 rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR;
770 }
771 /* link rr_prefix entry to rr_prefix list */
772 s = splnet();
773 LIST_INSERT_HEAD(&rr_prefix, rpp, rp_entry);
774 splx(s);
775 }
776
777 if (!new->rp_raf_auto)
778 return 0;
779
780 /*
781 * Add an address for each interface id, if it is not yet
782 * If it existed but not pointing to the prefix yet,
783 * init the prefix pointer.
784 */
9bccf70c
A
785 LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
786 {
1c79356b
A
787 if (rap->ra_addr != NULL) {
788 if (rap->ra_addr->ia6_ifpr == NULL)
789 rap->ra_addr->ia6_ifpr = rp2ifpr(rpp);
790 continue;
791 }
792 add_each_addr(so, rpp, rap);
793 }
794 return 0;
795}
796
797static int
798add_each_prefix(struct socket *so, struct rr_prefix *rpp)
799{
800 init_prefix_ltimes(rpp);
801 return(rrpr_update(so, rpp));
802}
803
804static void
805rp_remove(struct rr_prefix *rpp)
806{
807 int s;
808
809 s = splnet();
810 /* unlink rp_entry from if_prefixlist */
811 {
812 struct ifnet *ifp = rpp->rp_ifp;
813 struct ifprefix *ifpr;
814
9bccf70c
A
815 if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) == rp2ifpr(rpp))
816 TAILQ_FIRST(&ifp->if_prefixhead) =
817 TAILQ_NEXT(ifpr, ifpr_list);
1c79356b 818 else {
9bccf70c
A
819 while (TAILQ_NEXT(ifpr, ifpr_list) != NULL &&
820 (TAILQ_NEXT(ifpr, ifpr_list) != rp2ifpr(rpp)))
821 ifpr = TAILQ_NEXT(ifpr, ifpr_list);
822 if (TAILQ_NEXT(ifpr, ifpr_list))
823 TAILQ_NEXT(ifpr, ifpr_list) =
824 TAILQ_NEXT(rp2ifpr(rpp), ifpr_list);
825 else
826 printf("Couldn't unlink rr_prefix from ifp\n");
1c79356b
A
827 }
828 }
829 /* unlink rp_entry from rr_prefix list */
830 LIST_REMOVE(rpp, rp_entry);
831 splx(s);
9bccf70c 832 FREE(rpp, M_IP6RR);
1c79356b
A
833}
834
835static int
836create_ra_entry(struct rp_addr **rapp)
837{
9bccf70c 838 *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_RR_ADDR,
1c79356b
A
839 M_NOWAIT);
840 if (*rapp == NULL) {
841 log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS"
842 "for rp_addr\n", __LINE__);
843 return ENOBUFS;
844 }
845 bzero(*rapp, sizeof(*(*rapp)));
846
847 return 0;
848}
849
850static int
851init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
852 struct rr_prefix *rpp)
853{
854 struct rp_addr *orap;
855
856 /* init rp */
857 bzero(rpp, sizeof(*rpp));
858 rpp->rp_type = IN6_PREFIX_RR;
859 rpp->rp_ifp = ifpr->ifpr_ifp;
860 rpp->rp_plen = ifpr->ifpr_plen;
861 rpp->rp_prefix.sin6_len = sizeof(rpp->rp_prefix);
862 rpp->rp_prefix.sin6_family = AF_INET6;
863 bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
864 (char *)&irr->irr_useprefix.sin6_addr,
865 sizeof(irr->irr_useprefix.sin6_addr) << 3,
866 0, irr->irr_u_uselen);
867 /* copy keeplen part if necessary as necessary len */
868 if (irr->irr_u_uselen < ifpr->ifpr_plen)
869 bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
870 (char *)IFPR_IN6(ifpr), sizeof(*IFPR_IN6(ifpr)) << 3,
871 irr->irr_u_uselen,
872 min(ifpr->ifpr_plen - irr->irr_u_uselen,
873 irr->irr_u_keeplen));
9bccf70c
A
874 LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry)
875 {
1c79356b
A
876 struct rp_addr *rap;
877 int error = 0;
878
879 if ((error = create_ra_entry(&rap)) != 0)
880 return error;
881 rap->ra_ifid = orap->ra_ifid;
882 rap->ra_flags.anycast = (orap->ra_addr != NULL &&
883 (orap->ra_addr->ia6_flags &
884 IN6_IFF_ANYCAST) != 0) ? 1 : 0;
885 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
886 }
887 rpp->rp_vltime = irr->irr_vltime;
888 rpp->rp_pltime = irr->irr_pltime;
889 rpp->rp_raf_onlink = irr->irr_raf_mask_onlink ? irr->irr_raf_onlink :
890 ifpr2rp(ifpr)->rp_raf_onlink;
891 rpp->rp_raf_auto = irr->irr_raf_mask_auto ? irr->irr_raf_auto :
892 ifpr2rp(ifpr)->rp_raf_auto;
893 /* Is some FlagMasks for rrf necessary? */
894 rpp->rp_rrf = irr->irr_rrf;
895 rpp->rp_origin = irr->irr_origin;
896
897 return 0;
898}
899
900static void
901free_rp_entries(struct rr_prefix *rpp)
902{
903 /*
904 * This func is only called with rpp on stack(not on list).
905 * So no splnet() here
906 */
1c79356b 907 while (!LIST_EMPTY(&rpp->rp_addrhead))
1c79356b
A
908 {
909 struct rp_addr *rap;
910
911 rap = LIST_FIRST(&rpp->rp_addrhead);
912 LIST_REMOVE(rap, ra_entry);
913 if (rap->ra_addr)
9bccf70c
A
914 ifafree(&rap->ra_addr->ia_ifa);
915 FREE(rap, M_RR_ADDR);
1c79356b
A
916 }
917}
918
919static int
920add_useprefixes(struct socket *so, struct ifnet *ifp,
921 struct in6_rrenumreq *irr)
922{
923 struct ifprefix *ifpr, *nextifpr;
924 struct rr_prefix rp;
925 int error = 0;
926
927 /* add prefixes to each of marked prefix */
9bccf70c
A
928 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
929 {
930 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
1c79356b
A
931 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
932 ifpr->ifpr_type != IN6_PREFIX_RR)
933 continue;
934 if (ifpr2rp(ifpr)->rp_statef_addmark) {
935 if ((error = init_newprefix(irr, ifpr, &rp)) != 0)
936 break;
937 error = add_each_prefix(so, &rp);
938 }
939 }
940 /* free each rp_addr entry */
941 free_rp_entries(&rp);
942
943 return error;
944}
945
946static void
947unprefer_prefix(struct rr_prefix *rpp)
948{
949 struct rp_addr *rap;
1c79356b
A
950
951 for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
952 rap = rap->ra_entry.le_next) {
953 if (rap->ra_addr == NULL)
954 continue;
955 rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second;
956 rap->ra_addr->ia6_lifetime.ia6t_pltime = 0;
957 }
958}
959
960int
961delete_each_prefix(struct rr_prefix *rpp, u_char origin)
962{
963 int error = 0;
964
965 if (rpp->rp_origin > origin)
966 return(EPERM);
967
968 while (rpp->rp_addrhead.lh_first != NULL) {
969 struct rp_addr *rap;
970 int s;
971
972 s = splnet();
973 rap = LIST_FIRST(&rpp->rp_addrhead);
9bccf70c
A
974 if (rap == NULL) {
975 splx(s);
1c79356b 976 break;
9bccf70c 977 }
1c79356b
A
978 LIST_REMOVE(rap, ra_entry);
979 splx(s);
980 if (rap->ra_addr == NULL) {
9bccf70c 981 FREE(rap, M_RR_ADDR);
1c79356b
A
982 continue;
983 }
984 rap->ra_addr->ia6_ifpr = NULL;
985
9bccf70c
A
986 in6_purgeaddr(&rap->ra_addr->ia_ifa);
987 ifafree(&rap->ra_addr->ia_ifa);
988 FREE(rap, M_RR_ADDR);
1c79356b
A
989 }
990 rp_remove(rpp);
991
992 return error;
993}
994
995static void
996delete_prefixes(struct ifnet *ifp, u_char origin)
997{
998 struct ifprefix *ifpr, *nextifpr;
999
1000 /* delete prefixes marked as tobe deleted */
9bccf70c
A
1001 for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
1002 {
1003 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
1c79356b
A
1004 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
1005 ifpr->ifpr_type != IN6_PREFIX_RR)
1006 continue;
1007 if (ifpr2rp(ifpr)->rp_statef_delmark)
1008 (void)delete_each_prefix(ifpr2rp(ifpr), origin);
1009 }
1010}
1011
1012static int
1013link_stray_ia6s(struct rr_prefix *rpp)
1014{
1015 struct ifaddr *ifa;
1016
1c79356b
A
1017 for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa;
1018 ifa = ifa->ifa_list.tqe_next)
1c79356b
A
1019 {
1020 struct rp_addr *rap;
1021 struct rr_prefix *orpp;
1022 int error = 0;
1023
1024 if (ifa->ifa_addr->sa_family != AF_INET6)
1025 continue;
1026 if (rpp->rp_plen > in6_matchlen(RP_IN6(rpp), IFA_IN6(ifa)))
1027 continue;
1028
1029 orpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
1030 if (orpp != NULL) {
1031 if (!in6_are_prefix_equal(RP_IN6(orpp), RP_IN6(rpp),
1032 rpp->rp_plen))
1033 log(LOG_ERR, "in6_prefix.c: link_stray_ia6s:"
1034 "addr %s/%d already linked to a prefix"
1035 "and it matches also %s/%d\n",
1036 ip6_sprintf(IFA_IN6(ifa)), orpp->rp_plen,
1037 ip6_sprintf(RP_IN6(rpp)),
1038 rpp->rp_plen);
1039 continue;
1040 }
9bccf70c 1041 if ((error = assign_ra_entry(rpp,
1c79356b
A
1042 (sizeof(rap->ra_ifid) << 3) -
1043 rpp->rp_plen,
1044 (struct in6_ifaddr *)ifa)) != 0)
1045 return error;
1046 }
1047 return 0;
1048}
1049
1050/* XXX assumes that permission is already checked by the caller */
1051int
1052in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
1053 struct ifnet *ifp)
1054{
1055 struct rr_prefix *rpp, rp_tmp;
1056 struct rp_addr *rap;
1057 struct in6_prefixreq *ipr = (struct in6_prefixreq *)data;
1058 struct in6_rrenumreq *irr = (struct in6_rrenumreq *)data;
1059 struct ifaddr *ifa;
1060 int error = 0;
1061
1062 /*
1063 * Failsafe for errneous address config program.
1064 * Let's hope rrenumd don't make a mistakes.
1065 */
1066 if (ipr->ipr_origin <= PR_ORIG_RA)
1067 ipr->ipr_origin = PR_ORIG_STATIC;
1068
1069 switch (cmd) {
1070 case SIOCSGIFPREFIX_IN6:
1071 delmark_global_prefixes(ifp, irr);
1072 /* FALL THROUGH */
1073 case SIOCAIFPREFIX_IN6:
1074 case SIOCCIFPREFIX_IN6:
1075 /* check if preferred lifetime > valid lifetime */
1076 if (irr->irr_pltime > irr->irr_vltime) {
1077 log(LOG_NOTICE,
1078 "in6_prefix_ioctl: preferred lifetime"
1079 "(%ld) is greater than valid lifetime(%ld)\n",
1080 (u_long)irr->irr_pltime, (u_long)irr->irr_vltime);
1081 error = EINVAL;
1082 break;
1083 }
1084 if (mark_matched_prefixes(cmd, ifp, irr)) {
1085 if (irr->irr_u_uselen != 0)
1086 if ((error = add_useprefixes(so, ifp, irr))
1087 != 0)
1088 goto failed;
1089 if (cmd != SIOCAIFPREFIX_IN6)
1090 delete_prefixes(ifp, irr->irr_origin);
1091 } else
1092 return (EADDRNOTAVAIL);
1093 failed:
1094 unmark_prefixes(ifp);
1095 break;
1096 case SIOCGIFPREFIX_IN6:
1097 rpp = search_matched_prefix(ifp, ipr);
1098 if (rpp == NULL || ifp != rpp->rp_ifp)
1099 return (EADDRNOTAVAIL);
1100
1101 ipr->ipr_origin = rpp->rp_origin;
1102 ipr->ipr_plen = rpp->rp_plen;
1103 ipr->ipr_vltime = rpp->rp_vltime;
1104 ipr->ipr_pltime = rpp->rp_pltime;
1105 ipr->ipr_flags = rpp->rp_flags;
1106 ipr->ipr_prefix = rpp->rp_prefix;
1107
1108 break;
1109 case SIOCSIFPREFIX_IN6:
1110 /* check if preferred lifetime > valid lifetime */
1111 if (ipr->ipr_pltime > ipr->ipr_vltime) {
1112 log(LOG_NOTICE,
1113 "in6_prefix_ioctl: preferred lifetime"
1114 "(%ld) is greater than valid lifetime(%ld)\n",
1115 (u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime);
1116 error = EINVAL;
1117 break;
1118 }
1119
1120 /* init rp_tmp */
1121 bzero((caddr_t)&rp_tmp, sizeof(rp_tmp));
1122 rp_tmp.rp_ifp = ifp;
1123 rp_tmp.rp_plen = ipr->ipr_plen;
1124 rp_tmp.rp_prefix = ipr->ipr_prefix;
1125 rp_tmp.rp_vltime = ipr->ipr_vltime;
1126 rp_tmp.rp_pltime = ipr->ipr_pltime;
1127 rp_tmp.rp_flags = ipr->ipr_flags;
1128 rp_tmp.rp_origin = ipr->ipr_origin;
1129
1130 /* create rp_addr entries, usually at least for lladdr */
1131 if ((error = link_stray_ia6s(&rp_tmp)) != 0) {
1132 free_rp_entries(&rp_tmp);
1133 break;
1134 }
1c79356b
A
1135 for (ifa = ifp->if_addrlist.tqh_first;
1136 ifa;
1137 ifa = ifa->ifa_list.tqe_next)
1c79356b
A
1138 {
1139 if (ifa->ifa_addr == NULL)
1140 continue; /* just for safety */
1141 if (ifa->ifa_addr->sa_family != AF_INET6)
1142 continue;
1143 if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)) == 0)
1144 continue;
1145
1146 if ((error = create_ra_entry(&rap)) != 0) {
1147 free_rp_entries(&rp_tmp);
1148 goto bad;
1149 }
1150 /* copy interface id part */
1151 bit_copy((caddr_t)&rap->ra_ifid,
1152 sizeof(rap->ra_ifid) << 3,
1153 (caddr_t)IFA_IN6(ifa),
1154 sizeof(*IFA_IN6(ifa)) << 3,
1155 rp_tmp.rp_plen,
1156 (sizeof(rap->ra_ifid) << 3) - rp_tmp.rp_plen);
1157 /* insert into list */
1158 LIST_INSERT_HEAD(&rp_tmp.rp_addrhead, rap, ra_entry);
1159 }
1160
1161 error = add_each_prefix(so, &rp_tmp);
1162
1163 /* free each rp_addr entry */
1164 free_rp_entries(&rp_tmp);
1165
1166 break;
1167 case SIOCDIFPREFIX_IN6:
1168 rpp = search_matched_prefix(ifp, ipr);
1169 if (rpp == NULL || ifp != rpp->rp_ifp)
1170 return (EADDRNOTAVAIL);
1171
1172 error = delete_each_prefix(rpp, ipr->ipr_origin);
1173 break;
1174 }
1175 bad:
1176 return error;
1177}
1178
0b4e3aa0
A
1179void
1180in6_rr_timer_funneled(void *ignored_arg)
1181{
1182#ifdef __APPLE__
1183 boolean_t funnel_state;
1184 funnel_state = thread_funnel_set(network_flock, TRUE);
1185#endif
1186 in6_rr_timer(ignored_arg);
1187#ifdef __APPLE__
1188 (void) thread_funnel_set(network_flock, FALSE);
1189#endif
1190}
1191
1c79356b
A
1192void
1193in6_rr_timer(void *ignored_arg)
1194{
1195 int s;
1196 struct rr_prefix *rpp;
1c79356b 1197
0b4e3aa0 1198 timeout(in6_rr_timer_funneled, (caddr_t)0, ip6_rr_prune * hz);
1c79356b
A
1199
1200 s = splnet();
1201 /* expire */
1202 rpp = LIST_FIRST(&rr_prefix);
1203 while (rpp) {
1204 if (rpp->rp_expire && rpp->rp_expire < time_second) {
1205 struct rr_prefix *next_rpp;
1206
1207 next_rpp = LIST_NEXT(rpp, rp_entry);
1208 delete_each_prefix(rpp, PR_ORIG_KERNEL);
1209 rpp = next_rpp;
1210 continue;
1211 }
1212 if (rpp->rp_preferred && rpp->rp_preferred < time_second)
1213 unprefer_prefix(rpp);
1214 rpp = LIST_NEXT(rpp, rp_entry);
1215 }
1216 splx(s);
1c79356b 1217}