]> git.saurik.com Git - apple/network_cmds.git/blame - rtadvd.tproj/config.c
network_cmds-176.3.1.tar.gz
[apple/network_cmds.git] / rtadvd.tproj / config.c
CommitLineData
7ba0088d
A
1/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */
2
3/*
4 * Copyright (C) 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 * $FreeBSD: src/usr.sbin/rtadvd/config.c,v 1.3.2.3 2001/07/03 11:02:14 ume Exp $
32 */
33
34#include <sys/param.h>
35#include <sys/ioctl.h>
36#include <sys/socket.h>
37#include <sys/time.h>
38#include <sys/sysctl.h>
39
40#include <net/if.h>
41#if defined(__FreeBSD__) && __FreeBSD__ >= 3
42#include <net/if_var.h>
43#endif /* __FreeBSD__ >= 3 */
44#include <net/route.h>
45#include <net/if_dl.h>
46
47#include <netinet/in.h>
48#include <netinet/in_var.h>
49#include <netinet/ip6.h>
50#include <netinet6/ip6_var.h>
51#include <netinet/icmp6.h>
52#ifdef MIP6
53#include <netinet6/mip6.h>
54#endif
55
56#include <arpa/inet.h>
57
58#include <stdio.h>
59#include <syslog.h>
60#include <errno.h>
61#include <string.h>
62#include <stdlib.h>
63#if defined(__NetBSD__) || defined(__OpenBSD__)
64#include <search.h>
65#endif
66#include <unistd.h>
67#include <ifaddrs.h>
68
69#include "rtadvd.h"
70#include "advcap.h"
71#include "timer.h"
72#include "if.h"
73#include "config.h"
74
75static void makeentry __P((char *, int, char *, int));
76static void get_prefix __P((struct rainfo *));
77static int getinet6sysctl __P((int));
78
79extern struct rainfo *ralist;
80
81void
82getconfig(intface)
83 char *intface;
84{
85 int stat, pfxs, i;
86 char tbuf[BUFSIZ];
87 struct rainfo *tmp;
88 long val;
89 long long val64;
90 char buf[BUFSIZ];
91 char *bp = buf;
92 char *addr;
93 static int forwarding = -1;
94
95#define MUSTHAVE(var, cap) \
96 do { \
97 int t; \
98 if ((t = agetnum(cap)) < 0) { \
99 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
100 cap, intface); \
101 exit(1); \
102 } \
103 var = t; \
104 } while (0)
105#define MAYHAVE(var, cap, def) \
106 do { \
107 if ((var = agetnum(cap)) < 0) \
108 var = def; \
109 } while (0)
110
111 if ((stat = agetent(tbuf, intface)) <= 0) {
112 memset(tbuf, 0, sizeof(tbuf));
113 syslog(LOG_INFO,
114 "<%s> %s isn't defined in the configuration file"
115 " or the configuration file doesn't exist."
116 " Treat it as default",
117 __FUNCTION__, intface);
118 }
119
120 tmp = (struct rainfo *)malloc(sizeof(*ralist));
121 memset(tmp, 0, sizeof(*tmp));
122 tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
123 tmp->route.next = tmp->route.prev = &tmp->route;
124
125 /* check if we are allowed to forward packets (if not determined) */
126 if (forwarding < 0) {
127 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
128 exit(1);
129 }
130
131 /* get interface information */
132 if (agetflag("nolladdr"))
133 tmp->advlinkopt = 0;
134 else
135 tmp->advlinkopt = 1;
136 if (tmp->advlinkopt) {
137 if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
138 syslog(LOG_ERR,
139 "<%s> can't get information of %s",
140 __FUNCTION__, intface);
141 exit(1);
142 }
143 tmp->ifindex = tmp->sdl->sdl_index;
144 } else
145 tmp->ifindex = if_nametoindex(intface);
146 strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
147 if ((tmp->phymtu = if_getmtu(intface)) == 0) {
148 tmp->phymtu = IPV6_MMTU;
149 syslog(LOG_WARNING,
150 "<%s> can't get interface mtu of %s. Treat as %d",
151 __FUNCTION__, intface, IPV6_MMTU);
152 }
153
154 /*
155 * set router configuration variables.
156 */
157 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
158 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
159 syslog(LOG_ERR,
160 "<%s> maxinterval must be between %e and %u",
161 __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
162 exit(1);
163 }
164 tmp->maxinterval = (u_int)val;
165 MAYHAVE(val, "mininterval", tmp->maxinterval/3);
166 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
167 syslog(LOG_ERR,
168 "<%s> mininterval must be between %e and %d",
169 __FUNCTION__,
170 MIN_MININTERVAL,
171 (tmp->maxinterval * 3) / 4);
172 exit(1);
173 }
174 tmp->mininterval = (u_int)val;
175
176 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
177 tmp->hoplimit = val & 0xff;
178
179 MAYHAVE(val, "raflags", 0);
180 tmp->managedflg = val & ND_RA_FLAG_MANAGED;
181 tmp->otherflg = val & ND_RA_FLAG_OTHER;
182#ifdef MIP6
183 if (mobileip6)
184 tmp->haflg = val & ND_RA_FLAG_HA;
185#endif
186#ifndef ND_RA_FLAG_RTPREF_MASK
187#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
188#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
189#endif
190 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
191 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
192 syslog(LOG_ERR, "<%s> invalid router preference on %s",
193 __FUNCTION__, intface);
194 exit(1);
195 }
196
197 MAYHAVE(val, "rltime", tmp->maxinterval * 3);
198 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
199 syslog(LOG_ERR,
200 "<%s> router lifetime on %s must be 0 or"
201 " between %d and %d",
202 __FUNCTION__, intface,
203 tmp->maxinterval, MAXROUTERLIFETIME);
204 exit(1);
205 }
206 /*
207 * Basically, hosts MUST NOT send Router Advertisement messages at any
208 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
209 * useful to allow hosts to advertise some parameters such as prefix
210 * information and link MTU. Thus, we allow hosts to invoke rtadvd
211 * only when router lifetime (on every advertising interface) is
212 * explicitly set zero. (see also the above section)
213 */
214 if (val && forwarding == 0) {
215 syslog(LOG_WARNING,
216 "<%s> non zero router lifetime is specified for %s, "
217 "which must not be allowed for hosts.",
218 __FUNCTION__, intface);
219 exit(1);
220 }
221 tmp->lifetime = val & 0xffff;
222
223 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
224 if (val > MAXREACHABLETIME) {
225 syslog(LOG_ERR,
226 "<%s> reachable time must be no greater than %d",
227 __FUNCTION__, MAXREACHABLETIME);
228 exit(1);
229 }
230 tmp->reachabletime = (u_int32_t)val;
231
232 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
233 if (val64 < 0 || val64 > 0xffffffff) {
234 syslog(LOG_ERR,
235 "<%s> retrans time out of range", __FUNCTION__);
236 exit(1);
237 }
238 tmp->retranstimer = (u_int32_t)val64;
239
240#ifndef MIP6
241 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) {
242 syslog(LOG_ERR,
243 "<%s> mobile-ip6 configuration not supported",
244 __FUNCTION__);
245 exit(1);
246 }
247#else
248 if (!mobileip6) {
249 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) {
250 syslog(LOG_ERR,
251 "<%s> mobile-ip6 configuration without "
252 "proper command line option",
253 __FUNCTION__);
254 exit(1);
255 }
256 } else {
257 tmp->hapref = 0;
258 if ((val = agetnum("hapref")) >= 0)
259 tmp->hapref = (int16_t)val;
260 if (tmp->hapref != 0) {
261 tmp->hatime = 0;
262 MUSTHAVE(val, "hatime");
263 tmp->hatime = (u_int16_t)val;
264 if (tmp->hatime <= 0) {
265 syslog(LOG_ERR,
266 "<%s> home agent lifetime must be greater than 0",
267 __FUNCTION__);
268 exit(1);
269 }
270 }
271 }
272#endif
273
274 /* prefix information */
275
276 /*
277 * This is an implementation specific parameter to consinder
278 * link propagation delays and poorly synchronized clocks when
279 * checking consistency of advertised lifetimes.
280 */
281 MAYHAVE(val, "clockskew", 0);
282 tmp->clockskew = val;
283
284 if ((pfxs = agetnum("addrs")) < 0) {
285 /* auto configure prefix information */
286 if (agetstr("addr", &bp) || agetstr("addr1", &bp)) {
287 syslog(LOG_ERR,
288 "<%s> conflicting prefix configuration for %s: "
289 "automatic and manual config at the same time",
290 __FUNCTION__, intface);
291 exit(1);
292 }
293 get_prefix(tmp);
294 }
295 else {
296 tmp->pfxs = pfxs;
297 for (i = 0; i < pfxs; i++) {
298 struct prefix *pfx;
299 char entbuf[256];
300 int added = (pfxs > 1) ? 1 : 0;
301
302 /* allocate memory to store prefix information */
303 if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
304 syslog(LOG_ERR,
305 "<%s> can't allocate enough memory",
306 __FUNCTION__);
307 exit(1);
308 }
309 memset(pfx, 0, sizeof(*pfx));
310
311 /* link into chain */
312 insque(pfx, &tmp->prefix);
313
314 pfx->origin = PREFIX_FROM_CONFIG;
315
316 makeentry(entbuf, i, "prefixlen", added);
317 MAYHAVE(val, entbuf, 64);
318 if (val < 0 || val > 128) {
319 syslog(LOG_ERR,
320 "<%s> prefixlen out of range",
321 __FUNCTION__);
322 exit(1);
323 }
324 pfx->prefixlen = (int)val;
325
326 makeentry(entbuf, i, "pinfoflags", added);
327#ifdef MIP6
328 if (mobileip6)
329 {
330 MAYHAVE(val, entbuf,
331 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO|
332 ND_OPT_PI_FLAG_ROUTER));
333 } else
334#endif
335 {
336 MAYHAVE(val, entbuf,
337 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
338 }
339 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
340 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
341#ifdef MIP6
342 pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER;
343#endif
344
345 makeentry(entbuf, i, "vltime", added);
346 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
347 if (val64 < 0 || val64 > 0xffffffff) {
348 syslog(LOG_ERR,
349 "<%s> vltime out of range",
350 __FUNCTION__);
351 exit(1);
352 }
353 pfx->validlifetime = (u_int32_t)val64;
354
355 makeentry(entbuf, i, "vltimedecr", added);
356 if (agetflag(entbuf)) {
357 struct timeval now;
358 gettimeofday(&now, 0);
359 pfx->vltimeexpire =
360 now.tv_sec + pfx->validlifetime;
361 }
362
363 makeentry(entbuf, i, "pltime", added);
364 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
365 if (val64 < 0 || val64 > 0xffffffff) {
366 syslog(LOG_ERR,
367 "<%s> pltime out of range",
368 __FUNCTION__);
369 exit(1);
370 }
371 pfx->preflifetime = (u_int32_t)val64;
372
373 makeentry(entbuf, i, "pltimedecr", added);
374 if (agetflag(entbuf)) {
375 struct timeval now;
376 gettimeofday(&now, 0);
377 pfx->pltimeexpire =
378 now.tv_sec + pfx->preflifetime;
379 }
380
381 makeentry(entbuf, i, "addr", added);
382 addr = (char *)agetstr(entbuf, &bp);
383 if (addr == NULL) {
384 syslog(LOG_ERR,
385 "<%s> need %s as an prefix for "
386 "interface %s",
387 __FUNCTION__, entbuf, intface);
388 exit(1);
389 }
390 if (inet_pton(AF_INET6, addr,
391 &pfx->prefix) != 1) {
392 syslog(LOG_ERR,
393 "<%s> inet_pton failed for %s",
394 __FUNCTION__, addr);
395 exit(1);
396 }
397 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
398 syslog(LOG_ERR,
399 "<%s> multicast prefix(%s) must "
400 "not be advertised (IF=%s)",
401 __FUNCTION__, addr, intface);
402 exit(1);
403 }
404 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
405 syslog(LOG_NOTICE,
406 "<%s> link-local prefix(%s) will be"
407 " advertised on %s",
408 __FUNCTION__, addr, intface);
409 }
410 }
411
412 MAYHAVE(val, "mtu", 0);
413 if (val < 0 || val > 0xffffffff) {
414 syslog(LOG_ERR,
415 "<%s> mtu out of range", __FUNCTION__);
416 exit(1);
417 }
418 tmp->linkmtu = (u_int32_t)val;
419 if (tmp->linkmtu == 0) {
420 char *mtustr;
421
422 if ((mtustr = (char *)agetstr("mtu", &bp)) &&
423 strcmp(mtustr, "auto") == 0)
424 tmp->linkmtu = tmp->phymtu;
425 }
426 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
427 syslog(LOG_ERR,
428 "<%s> advertised link mtu must be between"
429 " least MTU and physical link MTU",
430 __FUNCTION__);
431 exit(1);
432 }
433
434 /* route information */
435
436 MAYHAVE(val, "routes", 0);
437 if (val < 0 || val > 0xffffffff) {
438 syslog(LOG_ERR,
439 "<%s> number of route information improper", __FUNCTION__);
440 exit(1);
441 }
442 tmp->routes = val;
443 for (i = 0; i < tmp->routes; i++) {
444 struct rtinfo *rti;
445 char entbuf[256];
446 int added = (tmp->routes > 1) ? 1 : 0;
447
448 /* allocate memory to store prefix information */
449 if ((rti = malloc(sizeof(struct rtinfo))) == NULL) {
450 syslog(LOG_ERR,
451 "<%s> can't allocate enough memory",
452 __FUNCTION__);
453 exit(1);
454 }
455 memset(rti, 0, sizeof(*rti));
456
457 /* link into chain */
458 insque(rti, &tmp->route);
459
460 makeentry(entbuf, i, "rtrplen", added);
461 MAYHAVE(val, entbuf, 64);
462 if (val < 0 || val > 128) {
463 syslog(LOG_ERR,
464 "<%s> prefixlen out of range",
465 __FUNCTION__);
466 exit(1);
467 }
468 rti->prefixlen = (int)val;
469
470 makeentry(entbuf, i, "rtrflags", added);
471 MAYHAVE(val, entbuf, 0);
472 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
473 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
474 syslog(LOG_ERR, "<%s> invalid router preference",
475 __FUNCTION__);
476 exit(1);
477 }
478
479 makeentry(entbuf, i, "rtrltime", added);
480 /*
481 * XXX: since default value of route lifetime is not defined in
482 * draft-draves-route-selection-01.txt, I took the default
483 * value of valid lifetime of prefix as its default.
484 * It need be much considered.
485 */
486 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
487 if (val64 < 0 || val64 > 0xffffffff) {
488 syslog(LOG_ERR,
489 "<%s> rtrltime out of range",
490 __FUNCTION__);
491 exit(1);
492 }
493 rti->ltime = (u_int32_t)val64;
494
495 makeentry(entbuf, i, "rtrprefix", added);
496 addr = (char *)agetstr(entbuf, &bp);
497 if (addr == NULL) {
498 syslog(LOG_ERR,
499 "<%s> need %s as an route for "
500 "interface %s",
501 __FUNCTION__, entbuf, intface);
502 exit(1);
503 }
504 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
505 syslog(LOG_ERR,
506 "<%s> inet_pton failed for %s",
507 __FUNCTION__, addr);
508 exit(1);
509 }
510#if 0
511 /*
512 * XXX: currently there's no restriction in route information
513 * prefix according to draft-draves-route-selection-01.txt,
514 * however I think the similar restriction be necessary.
515 */
516 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
517 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
518 syslog(LOG_ERR,
519 "<%s> multicast route (%s) must "
520 "not be advertised (IF=%s)",
521 __FUNCTION__, addr, intface);
522 exit(1);
523 }
524 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
525 syslog(LOG_NOTICE,
526 "<%s> link-local route (%s) must "
527 "not be advertised on %s",
528 __FUNCTION__, addr, intface);
529 exit(1);
530 }
531#endif
532 }
533
534 /* okey */
535 tmp->next = ralist;
536 ralist = tmp;
537
538 /* construct the sending packet */
539 make_packet(tmp);
540
541 /* set timer */
542 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
543 tmp, tmp);
544 ra_timer_update((void *)tmp, &tmp->timer->tm);
545 rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
546}
547
548static void
549get_prefix(struct rainfo *rai)
550{
551 struct ifaddrs *ifap, *ifa;
552 struct prefix *pp;
553 struct in6_addr *a;
554 u_char *p, *ep, *m, *lim;
555 u_char ntopbuf[INET6_ADDRSTRLEN];
556
557 if (getifaddrs(&ifap) < 0) {
558 syslog(LOG_ERR,
559 "<%s> can't get interface addresses",
560 __FUNCTION__);
561 exit(1);
562 }
563 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
564 if (strcmp(ifa->ifa_name, rai->ifname) != 0)
565 continue;
566 if (ifa->ifa_addr->sa_family != AF_INET6)
567 continue;
568 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
569 if (IN6_IS_ADDR_LINKLOCAL(a))
570 continue;
571
572 /* allocate memory to store prefix info. */
573 if ((pp = malloc(sizeof(*pp))) == NULL) {
574 syslog(LOG_ERR,
575 "<%s> can't get allocate buffer for prefix",
576 __FUNCTION__);
577 exit(1);
578 }
579 memset(pp, 0, sizeof(*pp));
580
581 /* set prefix length */
582 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
583 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
584 pp->prefixlen = prefixlen(m, lim);
585 if (pp->prefixlen < 0 || pp->prefixlen > 128) {
586 syslog(LOG_ERR,
587 "<%s> failed to get prefixlen "
588 "or prefix is invalid",
589 __FUNCTION__);
590 exit(1);
591 }
592
593 /* set prefix, sweep bits outside of prefixlen */
594 memcpy(&pp->prefix, a, sizeof(*a));
595 p = (u_char *)&pp->prefix;
596 ep = (u_char *)(&pp->prefix + 1);
597 while (m < lim)
598 *p++ &= *m++;
599 while (p < ep)
600 *p++ = 0x00;
601
602 if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf,
603 sizeof(ntopbuf))) {
604 syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__);
605 exit(1);
606 }
607 syslog(LOG_DEBUG,
608 "<%s> add %s/%d to prefix list on %s",
609 __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname);
610
611 /* set other fields with protocol defaults */
612 pp->validlifetime = DEF_ADVVALIDLIFETIME;
613 pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
614 pp->onlinkflg = 1;
615 pp->autoconfflg = 1;
616 pp->origin = PREFIX_FROM_KERNEL;
617
618 /* link into chain */
619 insque(pp, &rai->prefix);
620
621 /* counter increment */
622 rai->pfxs++;
623 }
624
625 freeifaddrs(ifap);
626}
627
628static void
629makeentry(buf, id, string, add)
630 char *buf, *string;
631 int id, add;
632{
633 strcpy(buf, string);
634 if (add) {
635 char *cp;
636
637 cp = (char *)index(buf, '\0');
638 cp += sprintf(cp, "%d", id);
639 *cp = '\0';
640 }
641}
642
643/*
644 * Add a prefix to the list of specified interface and reconstruct
645 * the outgoing packet.
646 * The prefix must not be in the list.
647 * XXX: other parameter of the prefix(e.g. lifetime) shoule be
648 * able to be specified.
649 */
650static void
651add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
652{
653 struct prefix *prefix;
654 u_char ntopbuf[INET6_ADDRSTRLEN];
655
656 if ((prefix = malloc(sizeof(*prefix))) == NULL) {
657 syslog(LOG_ERR, "<%s> memory allocation failed",
658 __FUNCTION__);
659 return; /* XXX: error or exit? */
660 }
661 memset(prefix, 0, sizeof(*prefix));
662 prefix->prefix = ipr->ipr_prefix.sin6_addr;
663 prefix->prefixlen = ipr->ipr_plen;
664 prefix->validlifetime = ipr->ipr_vltime;
665 prefix->preflifetime = ipr->ipr_pltime;
666 prefix->onlinkflg = ipr->ipr_raf_onlink;
667 prefix->autoconfflg = ipr->ipr_raf_auto;
668 prefix->origin = PREFIX_FROM_DYNAMIC;
669
670 insque(prefix, &rai->prefix);
671
672 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
673 __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
674 ntopbuf, INET6_ADDRSTRLEN),
675 ipr->ipr_plen, rai->ifname);
676
677 /* free the previous packet */
678 free(rai->ra_data);
679 rai->ra_data = NULL;
680
681 /* reconstruct the packet */
682 rai->pfxs++;
683 make_packet(rai);
684
685 /*
686 * reset the timer so that the new prefix will be advertised quickly.
687 */
688 rai->initcounter = 0;
689 ra_timer_update((void *)rai, &rai->timer->tm);
690 rtadvd_set_timer(&rai->timer->tm, rai->timer);
691}
692
693/*
694 * Delete a prefix to the list of specified interface and reconstruct
695 * the outgoing packet.
696 * The prefix must be in the list.
697 */
698void
699delete_prefix(struct rainfo *rai, struct prefix *prefix)
700{
701 u_char ntopbuf[INET6_ADDRSTRLEN];
702
703 remque(prefix);
704 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
705 __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix,
706 ntopbuf, INET6_ADDRSTRLEN),
707 prefix->prefixlen, rai->ifname);
708 free(prefix);
709 rai->pfxs--;
710 make_packet(rai);
711}
712
713/*
714 * Try to get an in6_prefixreq contents for a prefix which matches
715 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
716 * the interface whose name is ipr->ipr_name[].
717 */
718static int
719init_prefix(struct in6_prefixreq *ipr)
720{
721 int s;
722
723 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
724 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
725 strerror(errno));
726 exit(1);
727 }
728
729 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
730 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__,
731 strerror(errno));
732
733 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
734 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
735 ipr->ipr_raf_onlink = 1;
736 ipr->ipr_raf_auto = 1;
737 /* omit other field initialization */
738 }
739 else if (ipr->ipr_origin < PR_ORIG_RR) {
740 u_char ntopbuf[INET6_ADDRSTRLEN];
741
742 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
743 "lower than PR_ORIG_RR(router renumbering)."
744 "This should not happen if I am router", __FUNCTION__,
745 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
746 sizeof(ntopbuf)), ipr->ipr_origin);
747 close(s);
748 return 1;
749 }
750
751 close(s);
752 return 0;
753}
754
755void
756make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
757{
758 struct in6_prefixreq ipr;
759
760 memset(&ipr, 0, sizeof(ipr));
761 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
762 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
763 "exist. This should not happen! %s", __FUNCTION__,
764 ifindex, strerror(errno));
765 exit(1);
766 }
767 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
768 ipr.ipr_prefix.sin6_family = AF_INET6;
769 ipr.ipr_prefix.sin6_addr = *addr;
770 ipr.ipr_plen = plen;
771
772 if (init_prefix(&ipr))
773 return; /* init failed by some error */
774 add_prefix(rai, &ipr);
775}
776
777void
778make_packet(struct rainfo *rainfo)
779{
780 size_t packlen, lladdroptlen = 0;
781 char *buf;
782 struct nd_router_advert *ra;
783 struct nd_opt_prefix_info *ndopt_pi;
784 struct nd_opt_mtu *ndopt_mtu;
785#ifdef MIP6
786 struct nd_opt_advinterval *ndopt_advint;
787 struct nd_opt_homeagent_info *ndopt_hai;
788#endif
789 struct nd_opt_route_info *ndopt_rti;
790 struct prefix *pfx;
791 struct rtinfo *rti;
792
793 /* calculate total length */
794 packlen = sizeof(struct nd_router_advert);
795 if (rainfo->advlinkopt) {
796 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
797 syslog(LOG_INFO,
798 "<%s> link-layer address option has"
799 " null length on %s."
800 " Treat as not included.",
801 __FUNCTION__, rainfo->ifname);
802 rainfo->advlinkopt = 0;
803 }
804 packlen += lladdroptlen;
805 }
806 if (rainfo->pfxs)
807 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
808 if (rainfo->linkmtu)
809 packlen += sizeof(struct nd_opt_mtu);
810#ifdef MIP6
811 if (mobileip6 && rainfo->maxinterval)
812 packlen += sizeof(struct nd_opt_advinterval);
813 if (mobileip6 && rainfo->hatime)
814 packlen += sizeof(struct nd_opt_homeagent_info);
815#endif
816#ifdef ND_OPT_ROUTE_INFO
817 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
818 packlen += sizeof(struct nd_opt_route_info) +
819 ((rti->prefixlen + 0x3f) >> 6) * 8;
820#endif
821
822 /* allocate memory for the packet */
823 if ((buf = malloc(packlen)) == NULL) {
824 syslog(LOG_ERR,
825 "<%s> can't get enough memory for an RA packet",
826 __FUNCTION__);
827 exit(1);
828 }
829 if (rainfo->ra_data) {
830 /* free the previous packet */
831 free(rainfo->ra_data);
832 rainfo->ra_data = NULL;
833 }
834 rainfo->ra_data = buf;
835 /* XXX: what if packlen > 576? */
836 rainfo->ra_datalen = packlen;
837
838 /*
839 * construct the packet
840 */
841 ra = (struct nd_router_advert *)buf;
842 ra->nd_ra_type = ND_ROUTER_ADVERT;
843 ra->nd_ra_code = 0;
844 ra->nd_ra_cksum = 0;
845 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
846 ra->nd_ra_flags_reserved = 0; /* just in case */
847 /*
848 * XXX: the router preference field, which is a 2-bit field, should be
849 * initialized before other fields.
850 */
851 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
852 ra->nd_ra_flags_reserved |=
853 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
854 ra->nd_ra_flags_reserved |=
855 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
856#ifdef MIP6
857 ra->nd_ra_flags_reserved |=
858 rainfo->haflg ? ND_RA_FLAG_HA : 0;
859#endif
860 ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
861 ra->nd_ra_reachable = htonl(rainfo->reachabletime);
862 ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
863 buf += sizeof(*ra);
864
865 if (rainfo->advlinkopt) {
866 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
867 buf += lladdroptlen;
868 }
869
870 if (rainfo->linkmtu) {
871 ndopt_mtu = (struct nd_opt_mtu *)buf;
872 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
873 ndopt_mtu->nd_opt_mtu_len = 1;
874 ndopt_mtu->nd_opt_mtu_reserved = 0;
875 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
876 buf += sizeof(struct nd_opt_mtu);
877 }
878
879#ifdef MIP6
880 if (mobileip6 && rainfo->maxinterval) {
881 ndopt_advint = (struct nd_opt_advinterval *)buf;
882 ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL;
883 ndopt_advint->nd_opt_adv_len = 1;
884 ndopt_advint->nd_opt_adv_reserved = 0;
885 ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval *
886 1000);
887 buf += sizeof(struct nd_opt_advinterval);
888 }
889#endif
890
891#ifdef MIP6
892 if (rainfo->hatime) {
893 ndopt_hai = (struct nd_opt_homeagent_info *)buf;
894 ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO;
895 ndopt_hai->nd_opt_hai_len = 1;
896 ndopt_hai->nd_opt_hai_reserved = 0;
897 ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref);
898 ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime);
899 buf += sizeof(struct nd_opt_homeagent_info);
900 }
901#endif
902
903 for (pfx = rainfo->prefix.next;
904 pfx != &rainfo->prefix; pfx = pfx->next) {
905 u_int32_t vltime, pltime;
906 struct timeval now;
907
908 ndopt_pi = (struct nd_opt_prefix_info *)buf;
909 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
910 ndopt_pi->nd_opt_pi_len = 4;
911 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
912 ndopt_pi->nd_opt_pi_flags_reserved = 0;
913 if (pfx->onlinkflg)
914 ndopt_pi->nd_opt_pi_flags_reserved |=
915 ND_OPT_PI_FLAG_ONLINK;
916 if (pfx->autoconfflg)
917 ndopt_pi->nd_opt_pi_flags_reserved |=
918 ND_OPT_PI_FLAG_AUTO;
919#ifdef MIP6
920 if (pfx->routeraddr)
921 ndopt_pi->nd_opt_pi_flags_reserved |=
922 ND_OPT_PI_FLAG_ROUTER;
923#endif
924 if (pfx->vltimeexpire || pfx->pltimeexpire)
925 gettimeofday(&now, NULL);
926 if (pfx->vltimeexpire == 0)
927 vltime = pfx->validlifetime;
928 else
929 vltime = (pfx->vltimeexpire > now.tv_sec) ?
930 pfx->vltimeexpire - now.tv_sec : 0;
931 if (pfx->pltimeexpire == 0)
932 pltime = pfx->preflifetime;
933 else
934 pltime = (pfx->pltimeexpire > now.tv_sec) ?
935 pfx->pltimeexpire - now.tv_sec : 0;
936 if (vltime < pltime) {
937 /*
938 * this can happen if vltime is decrement but pltime
939 * is not.
940 */
941 pltime = vltime;
942 }
943 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
944 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
945 ndopt_pi->nd_opt_pi_reserved2 = 0;
946 ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
947
948 buf += sizeof(struct nd_opt_prefix_info);
949 }
950
951#ifdef ND_OPT_ROUTE_INFO
952 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
953 u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
954
955 ndopt_rti = (struct nd_opt_route_info *)buf;
956 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
957 ndopt_rti->nd_opt_rti_len = 1 + psize;
958 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
959 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
960 ndopt_rti->nd_opt_rti_lifetime = rti->ltime;
961 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
962 buf += sizeof(struct nd_opt_route_info) + psize * 8;
963 }
964#endif
965
966 return;
967}
968
969static int
970getinet6sysctl(int code)
971{
972 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
973 int value;
974 size_t size;
975
976 mib[3] = code;
977 size = sizeof(value);
978 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
979 < 0) {
980 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
981 __FUNCTION__, code,
982 strerror(errno));
983 return(-1);
984 }
985 else
986 return(value);
987}