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