Home | History | Annotate | Line # | Download | only in rtadvd
config.c revision 1.6
      1 /*	$NetBSD: config.c,v 1.6 2000/03/13 06:16:46 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 
     32 #include <sys/param.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/socket.h>
     35 #include <sys/time.h>
     36 
     37 #include <net/if.h>
     38 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
     39 #include <net/if_var.h>
     40 #endif /* __FreeBSD__ >= 3 */
     41 #include <net/route.h>
     42 #include <net/if_dl.h>
     43 
     44 #include <netinet/in.h>
     45 #include <netinet/in_var.h>
     46 #include <netinet/ip6.h>
     47 #include <netinet6/ip6_var.h>
     48 #include <netinet/icmp6.h>
     49 #ifdef MIP6
     50 #include <netinet6/mip6.h>
     51 #endif
     52 
     53 #include <arpa/inet.h>
     54 
     55 #include <stdio.h>
     56 #include <syslog.h>
     57 #include <errno.h>
     58 #include <string.h>
     59 #include <stdlib.h>
     60 #ifdef __NetBSD__
     61 #include <search.h>
     62 #endif
     63 #include <unistd.h>
     64 
     65 #include "rtadvd.h"
     66 #include "advcap.h"
     67 #include "timer.h"
     68 #include "if.h"
     69 #include "config.h"
     70 
     71 static void makeentry __P((char *, int, char *, int));
     72 static void get_prefix __P((struct rainfo *));
     73 
     74 extern struct rainfo *ralist;
     75 
     76 void
     77 getconfig(intface)
     78 	char *intface;
     79 {
     80 	int stat, pfxs, i;
     81 	char tbuf[BUFSIZ];
     82 	struct rainfo *tmp;
     83 	long val;
     84 	char buf[BUFSIZ];
     85 	char *bp = buf;
     86 	char *addr;
     87 
     88 #define MUSTHAVE(var, cap)	\
     89     do {								\
     90 	int t;								\
     91 	if ((t = agetnum(cap)) < 0) {					\
     92 		fprintf(stderr, "rtadvd: need %s for interface %s\n",	\
     93 			cap, intface);					\
     94 		exit(1);						\
     95 	}								\
     96 	var = t;							\
     97      } while (0)
     98 #define MAYHAVE(var, cap, def)	\
     99      do {								\
    100 	if ((var = agetnum(cap)) < 0)					\
    101 		var = def;						\
    102      } while (0)
    103 
    104 	if ((stat = agetent(tbuf, intface)) <= 0) {
    105 		memset(tbuf, 0, sizeof(tbuf));
    106 		syslog(LOG_INFO,
    107 		       "<%s> %s isn't defined in the configuration file"
    108 		       " or the configuration file doesn't exist."
    109 		       " Treat it as default",
    110 		        __FUNCTION__, intface);
    111 	}
    112 
    113 	tmp = (struct rainfo *)malloc(sizeof(*ralist));
    114 	memset(tmp, 0, sizeof(*tmp));
    115 	tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
    116 
    117 	/* get interface information */
    118 	if (agetflag("nolladdr"))
    119 		tmp->advlinkopt = 0;
    120 	else
    121 		tmp->advlinkopt = 1;
    122 	if (tmp->advlinkopt) {
    123 		if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
    124 			syslog(LOG_ERR,
    125 			       "<%s> can't get information of %s",
    126 			       __FUNCTION__, intface);
    127 			exit(1);
    128 		}
    129 		tmp->ifindex = tmp->sdl->sdl_index;
    130 	} else
    131 		tmp->ifindex = if_nametoindex(intface);
    132 	strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
    133 	if ((tmp->phymtu = if_getmtu(intface)) == 0) {
    134 		tmp->phymtu = IPV6_MMTU;
    135 		syslog(LOG_WARNING,
    136 		       "<%s> can't get interface mtu of %s. Treat as %d",
    137 		       __FUNCTION__, intface, IPV6_MMTU);
    138 	}
    139 
    140 	/*
    141 	 * set router configuration variables.
    142 	 */
    143 	MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
    144 	if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
    145 		syslog(LOG_ERR,
    146 		       "<%s> maxinterval must be between %e and %u",
    147 		       __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
    148 		exit(1);
    149 	}
    150 	tmp->maxinterval = (u_int)val;
    151 	MAYHAVE(val, "mininterval", tmp->maxinterval/3);
    152 	if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
    153 		syslog(LOG_ERR,
    154 		       "<%s> mininterval must be between %e and %d",
    155 		       __FUNCTION__,
    156 		       MIN_MININTERVAL,
    157 		       (tmp->maxinterval * 3) / 4);
    158 		exit(1);
    159 	}
    160 	tmp->mininterval = (u_int)val;
    161 
    162 	MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
    163 	tmp->hoplimit = val & 0xff;
    164 
    165 	MAYHAVE(val, "raflags", 0);
    166 	tmp->managedflg= val & ND_RA_FLAG_MANAGED;
    167 	tmp->otherflg = val & ND_RA_FLAG_OTHER;
    168 #ifdef MIP6
    169 	if (mobileip6)
    170 		tmp->haflg = val & ND_RA_FLAG_HA;
    171 #endif
    172 
    173 	MAYHAVE(val, "rltime", tmp->maxinterval * 3);
    174 	if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
    175 		syslog(LOG_ERR,
    176 		       "<%s> router lifetime on %s must be 0 or"
    177 		       " between %d and %d",
    178 		       __FUNCTION__, intface,
    179 		       tmp->maxinterval, MAXROUTERLIFETIME);
    180 		exit(1);
    181 	}
    182 	tmp->lifetime = val & 0xffff;
    183 
    184 	MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
    185 	if (val > MAXREACHABLETIME) {
    186 		syslog(LOG_ERR,
    187 		       "<%s> reachable time must be no greater than %d",
    188 		       __FUNCTION__, MAXREACHABLETIME);
    189 		exit(1);
    190 	}
    191 	tmp->reachabletime = (u_int32_t)val;
    192 
    193 	MAYHAVE(val, "retrans", DEF_ADVRETRANSTIMER);
    194 	if (val < 0 || val > 0xffffffff) {
    195 		syslog(LOG_ERR,
    196 		       "<%s> retrans time out of range", __FUNCTION__);
    197 		exit(1);
    198 	}
    199 	tmp->retranstimer = (u_int32_t)val;
    200 
    201 #ifdef MIP6
    202 	if (!mobileip6)
    203 #else
    204 	if (1)
    205 #endif
    206 	{
    207 		if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) {
    208 			syslog(LOG_ERR,
    209 			       "<%s> mobile-ip6 configuration without "
    210 			       "proper command line option",
    211 			       __FUNCTION__);
    212 			exit(1);
    213 		}
    214 	}
    215 #ifdef MIP6
    216 	else {
    217 		tmp->hapref = 0;
    218 		if ((val = agetnum("hapref")) >= 0)
    219 			tmp->hapref = (int16_t)val;
    220 		if (tmp->hapref != 0) {
    221 			tmp->hatime = 0;
    222 			MUSTHAVE(val, "hatime");
    223 			tmp->hatime = (u_int16_t)val;
    224 			if (tmp->hatime <= 0) {
    225 				syslog(LOG_ERR,
    226 				       "<%s> home agent lifetime must be greater than 0",
    227 				       __FUNCTION__);
    228 				exit(1);
    229 			}
    230 		}
    231 	}
    232 #endif
    233 
    234 	/* prefix information */
    235 	if ((pfxs = agetnum("addrs")) < 0) {
    236 		/* auto configure prefix information */
    237 		if (agetstr("addr", &bp) || agetstr("addr1", &bp)) {
    238 			syslog(LOG_ERR,
    239 			       "<%s> conflicting prefix configuration for %s: "
    240 			       "automatic and manual config at the same time",
    241 			       __FUNCTION__, intface);
    242 			exit(1);
    243 		}
    244 		get_prefix(tmp);
    245 	}
    246 	else {
    247 		tmp->pfxs = pfxs;
    248 		for (i = 0; i < pfxs; i++) {
    249 			struct prefix *pfx;
    250 			char entbuf[256];
    251 			int added = (pfxs > 1) ? 1 : 0;
    252 
    253 			/* allocate memory to store prefix information */
    254 			if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
    255 				syslog(LOG_ERR,
    256 				       "<%s> can't allocate enough memory",
    257 				       __FUNCTION__);
    258 				exit(1);
    259 			}
    260 			/* link into chain */
    261 			insque(pfx, &tmp->prefix);
    262 
    263 			makeentry(entbuf, i, "prefixlen", added);
    264 			MAYHAVE(val, entbuf, 64);
    265 			if (val < 0 || val > 128) {
    266 				syslog(LOG_ERR,
    267 				       "<%s> prefixlen out of range",
    268 				       __FUNCTION__);
    269 				exit(1);
    270 			}
    271 			pfx->prefixlen = (int)val;
    272 
    273 			makeentry(entbuf, i, "pinfoflags", added);
    274 #ifdef MIP6
    275 			if (mobileip6)
    276 			{
    277 				MAYHAVE(val, entbuf,
    278 				    (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO|
    279 					 ND_OPT_PI_FLAG_RTADDR));
    280 			} else
    281 #endif
    282 			{
    283 				MAYHAVE(val, entbuf,
    284 				    (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
    285 			}
    286 			pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
    287 			pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
    288 #ifdef MIP6
    289 			if (mobileip6)
    290 				pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR;
    291 #endif
    292 
    293 			makeentry(entbuf, i, "vltime", added);
    294 			MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME);
    295 			if (val < 0 || val > 0xffffffff) {
    296 				syslog(LOG_ERR,
    297 				       "<%s> vltime out of range",
    298 				       __FUNCTION__);
    299 				exit(1);
    300 			}
    301 			pfx->validlifetime = (u_int32_t)val;
    302 
    303 			makeentry(entbuf, i, "pltime", added);
    304 			MAYHAVE(val, entbuf, DEF_ADVPREFERREDLIFETIME);
    305 			if (val < 0 || val > 0xffffffff) {
    306 				syslog(LOG_ERR,
    307 				       "<%s> pltime out of range",
    308 				       __FUNCTION__);
    309 				exit(1);
    310 			}
    311 			pfx->preflifetime = (u_int32_t)val;
    312 
    313 			makeentry(entbuf, i, "addr", added);
    314 			addr = (char *)agetstr(entbuf, &bp);
    315 			if (addr == NULL) {
    316 				syslog(LOG_ERR,
    317 				       "<%s> need %s as an prefix for "
    318 				       "interface %s",
    319 				       __FUNCTION__, entbuf, intface);
    320 				exit(1);
    321 			}
    322 			if (inet_pton(AF_INET6, addr,
    323 				      &pfx->prefix) != 1) {
    324 				syslog(LOG_ERR,
    325 				       "<%s> inet_pton failed for %s",
    326 				       __FUNCTION__, addr);
    327 				exit(1);
    328 			}
    329 			if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
    330 				syslog(LOG_ERR,
    331 				       "<%s> multicast prefix(%s) must "
    332 				       "not be advertised (IF=%s)",
    333 				       __FUNCTION__, addr, intface);
    334 				exit(1);
    335 			}
    336 			if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
    337 				syslog(LOG_NOTICE,
    338 				       "<%s> link-local prefix(%s) will be"
    339 				       " advertised on %s",
    340 				       __FUNCTION__, addr, intface);
    341 		}
    342 	}
    343 
    344 	MAYHAVE(val, "mtu", 0);
    345 	if (val < 0 || val > 0xffffffff) {
    346 		syslog(LOG_ERR,
    347 		       "<%s> mtu out of range", __FUNCTION__);
    348 		exit(1);
    349 	}
    350 	tmp->linkmtu = (u_int32_t)val;
    351 	if (tmp->linkmtu == 0) {
    352 		char *mtustr;
    353 
    354 		if ((mtustr = (char *)agetstr("mtu", &bp)) &&
    355 		    strcmp(mtustr, "auto") == 0)
    356 			tmp->linkmtu = tmp->phymtu;
    357 	}
    358 	else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
    359 		syslog(LOG_ERR,
    360 		       "<%s> advertised link mtu must be between"
    361 		       " least MTU and physical link MTU",
    362 		       __FUNCTION__);
    363 		exit(1);
    364 	}
    365 
    366 	/* okey */
    367 	tmp->next = ralist;
    368 	ralist = tmp;
    369 
    370 	/* construct the sending packet */
    371 	make_packet(tmp);
    372 
    373 	/* set timer */
    374 	tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
    375 				      tmp, tmp);
    376 	ra_timer_update((void *)tmp, &tmp->timer->tm);
    377 	rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
    378 }
    379 
    380 static void
    381 get_prefix(struct rainfo *rai)
    382 {
    383 	size_t len;
    384 	u_char *buf, *lim, *next;
    385 	u_char ntopbuf[INET6_ADDRSTRLEN];
    386 
    387 	if ((len = rtbuf_len()) < 0) {
    388 		syslog(LOG_ERR,
    389 		       "<%s> can't get buffer length for routing info",
    390 		       __FUNCTION__);
    391 		exit(1);
    392 	}
    393 	if ((buf = malloc(len)) == NULL) {
    394 		syslog(LOG_ERR,
    395 		       "<%s> can't allocate buffer", __FUNCTION__);
    396 		exit(1);
    397 	}
    398 	if (get_rtinfo(buf, &len) < 0) {
    399 		syslog(LOG_ERR,
    400 		       "<%s> can't get routing inforamtion", __FUNCTION__);
    401 		exit(1);
    402 	}
    403 
    404 	lim = buf + len;
    405 	next = get_next_msg(buf, lim, rai->ifindex, &len,
    406 			    RTADV_TYPE2BITMASK(RTM_GET));
    407 	while (next < lim) {
    408 		struct prefix *pp;
    409 		struct in6_addr *a;
    410 
    411 		/* allocate memory to store prefix info. */
    412 		if ((pp = malloc(sizeof(*pp))) == NULL) {
    413 			syslog(LOG_ERR,
    414 			       "<%s> can't get allocate buffer for prefix",
    415 			       __FUNCTION__);
    416 			exit(1);
    417 		}
    418 		memset(pp, 0, sizeof(*pp));
    419 
    420 		/* set prefix and its length */
    421 		a = get_addr(next);
    422 		memcpy(&pp->prefix, a, sizeof(*a));
    423 		if ((pp->prefixlen = get_prefixlen(next)) < 0) {
    424 			syslog(LOG_ERR,
    425 			       "<%s> failed to get prefixlen "
    426 			       "or prefixl is invalid",
    427 			       __FUNCTION__);
    428 			exit(1);
    429 		}
    430 		syslog(LOG_DEBUG,
    431 		       "<%s> add %s/%d to prefix list on %s",
    432 		       __FUNCTION__,
    433 		       inet_ntop(AF_INET6, a, ntopbuf, INET6_ADDRSTRLEN),
    434 		       pp->prefixlen, rai->ifname);
    435 
    436 		/* set other fields with protocol defaults */
    437 		pp->validlifetime = DEF_ADVVALIDLIFETIME;
    438 		pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
    439 		pp->onlinkflg = 1;
    440 		pp->autoconfflg = 1;
    441 
    442 		/* link into chain */
    443 		insque(pp, &rai->prefix);
    444 
    445 		/* counter increment */
    446 		rai->pfxs++;
    447 
    448 		/* forward pointer and get next prefix(if any) */
    449 		next += len;
    450 		next = get_next_msg(next, lim, rai->ifindex,
    451 				    &len, RTADV_TYPE2BITMASK(RTM_GET));
    452 	}
    453 
    454 	free(buf);
    455 }
    456 
    457 static void
    458 makeentry(buf, id, string, add)
    459     char *buf, *string;
    460     int id, add;
    461 {
    462 	strcpy(buf, string);
    463 	if (add) {
    464 		char *cp;
    465 
    466 		cp = (char *)index(buf, '\0');
    467 		cp += sprintf(cp, "%d", id);
    468 		*cp = '\0';
    469 	}
    470 }
    471 
    472 /*
    473  * Add a prefix to the list of specified interface and reconstruct
    474  * the outgoing packet.
    475  * The prefix must not be in the list.
    476  * XXX: other parameter of the prefix(e.g. lifetime) shoule be
    477  * able to be specified.
    478  */
    479 static void
    480 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
    481 {
    482 	struct prefix *prefix;
    483 	u_char ntopbuf[INET6_ADDRSTRLEN];
    484 
    485 	if ((prefix = malloc(sizeof(*prefix))) == NULL) {
    486 		syslog(LOG_ERR, "<%s> memory allocation failed",
    487 		       __FUNCTION__);
    488 		return;		/* XXX: error or exit? */
    489 	}
    490 	prefix->prefix = ipr->ipr_prefix.sin6_addr;
    491 	prefix->prefixlen = ipr->ipr_plen;
    492 	prefix->validlifetime = ipr->ipr_vltime;
    493 	prefix->preflifetime = ipr->ipr_pltime;
    494 	prefix->onlinkflg = ipr->ipr_raf_onlink;
    495 	prefix->autoconfflg = ipr->ipr_raf_auto;
    496 
    497 	insque(prefix, &rai->prefix);
    498 
    499 	syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
    500 	       __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
    501 				       ntopbuf, INET6_ADDRSTRLEN),
    502 	       ipr->ipr_plen, rai->ifname);
    503 
    504 	/* free the previous packet */
    505 	free(rai->ra_data);
    506 	rai->ra_data = 0;
    507 
    508 	/* reconstruct the packet */
    509 	rai->pfxs++;
    510 	make_packet(rai);
    511 
    512 	/*
    513 	 * reset the timer so that the new prefix will be advertised quickly.
    514 	 */
    515 	rai->initcounter = 0;
    516 	ra_timer_update((void *)rai, &rai->timer->tm);
    517 	rtadvd_set_timer(&rai->timer->tm, rai->timer);
    518 }
    519 
    520 /*
    521  * Delete a prefix to the list of specified interface and reconstruct
    522  * the outgoing packet.
    523  * The prefix must be in the list
    524  */
    525 void
    526 delete_prefix(struct rainfo *rai, struct prefix *prefix)
    527 {
    528 	u_char ntopbuf[INET6_ADDRSTRLEN];
    529 
    530 	remque(prefix);
    531 	syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
    532 	       __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix,
    533 				       ntopbuf, INET6_ADDRSTRLEN),
    534 	       prefix->prefixlen, rai->ifname);
    535 	free(prefix);
    536 	rai->pfxs--;
    537 	make_packet(rai);
    538 }
    539 
    540 /*
    541  * Try to get an in6_prefixreq contents for a prefix which matches
    542  * ipr->ipr_prefix and ipr->ipr_plen and belongs to
    543  * the interface whose name is ipr->ipr_name[].
    544  */
    545 static int
    546 init_prefix(struct in6_prefixreq *ipr)
    547 {
    548 	int s;
    549 
    550 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    551 		syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
    552 		       strerror(errno));
    553 		exit(1);
    554 	}
    555 
    556 	if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
    557 		syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__,
    558 		       strerror(errno));
    559 
    560 		ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
    561 		ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
    562 		ipr->ipr_raf_onlink = 1;
    563 		ipr->ipr_raf_auto = 1;
    564 		/* omit other field initialization */
    565 	}
    566 	else if (ipr->ipr_origin < PR_ORIG_RR) {
    567 		u_char ntopbuf[INET6_ADDRSTRLEN];
    568 
    569 		syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
    570 		       "lower than PR_ORIG_RR(router renumbering)."
    571 		       "This should not happen if I am router", __FUNCTION__,
    572 		       inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
    573 				 sizeof(ntopbuf)), ipr->ipr_origin);
    574 		close(s);
    575 		return 1;
    576 	}
    577 
    578 	close(s);
    579 	return 0;
    580 }
    581 
    582 void
    583 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
    584 {
    585 	struct in6_prefixreq ipr;
    586 
    587 	memset(&ipr, 0, sizeof(ipr));
    588 	if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
    589 		syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
    590 		       "exist. This should not happen! %s", __FUNCTION__,
    591 		       ifindex, strerror(errno));
    592 		exit(1);
    593 	}
    594 	ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
    595 	ipr.ipr_prefix.sin6_family = AF_INET6;
    596 	ipr.ipr_prefix.sin6_addr = *addr;
    597 	ipr.ipr_plen = plen;
    598 
    599 	if (init_prefix(&ipr))
    600 		return; /* init failed by some error */
    601 	add_prefix(rai, &ipr);
    602 }
    603 
    604 void
    605 make_packet(struct rainfo *rainfo)
    606 {
    607 	size_t packlen, lladdroptlen = 0;
    608 	char *buf;
    609 	struct nd_router_advert *ra;
    610 	struct nd_opt_prefix_info *ndopt_pi;
    611 	struct nd_opt_mtu *ndopt_mtu;
    612 #ifdef MIP6
    613 	struct nd_opt_advint *ndopt_advint;
    614 	struct nd_opt_hai *ndopt_hai;
    615 #endif
    616 	struct prefix *pfx;
    617 
    618 	/* calculate total length */
    619 	packlen = sizeof(struct nd_router_advert);
    620 	if (rainfo->advlinkopt) {
    621 		if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
    622 			syslog(LOG_INFO,
    623 			       "<%s> link-layer address option has"
    624 			       " null length on %s."
    625 			       " Treat as not included.",
    626 			       __FUNCTION__, rainfo->ifname);
    627 			rainfo->advlinkopt = 0;
    628 		}
    629 		packlen += lladdroptlen;
    630 	}
    631 	if (rainfo->pfxs)
    632 		packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
    633 	if (rainfo->linkmtu)
    634 		packlen += sizeof(struct nd_opt_mtu);
    635 #ifdef MIP6
    636 	if (mobileip6 && rainfo->maxinterval)
    637 		packlen += sizeof(struct nd_opt_advint);
    638 	if (mobileip6 && rainfo->hatime)
    639 		packlen += sizeof(struct nd_opt_hai);
    640 #endif
    641 
    642 	/* allocate memory for the packet */
    643 	if ((buf = malloc(packlen)) == NULL) {
    644 		syslog(LOG_ERR,
    645 		       "<%s> can't get enough memory for an RA packet",
    646 		       __FUNCTION__);
    647 		exit(1);
    648 	}
    649 	rainfo->ra_data = buf;
    650 	/* XXX: what if packlen > 576? */
    651 	rainfo->ra_datalen = packlen;
    652 
    653 	/*
    654 	 * construct the packet
    655 	 */
    656 	ra = (struct nd_router_advert *)buf;
    657 	ra->nd_ra_type = ND_ROUTER_ADVERT;
    658 	ra->nd_ra_code = 0;
    659 	ra->nd_ra_cksum = 0;
    660 	ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
    661 	ra->nd_ra_flags_reserved = 0;
    662 	ra->nd_ra_flags_reserved |=
    663 		rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
    664 	ra->nd_ra_flags_reserved |=
    665 		rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
    666 #ifdef MIP6
    667 	ra->nd_ra_flags_reserved |=
    668 		rainfo->haflg ? ND_RA_FLAG_HA : 0;
    669 #endif
    670 	ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
    671 	ra->nd_ra_reachable = htonl(rainfo->reachabletime);
    672 	ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
    673 	buf += sizeof(*ra);
    674 
    675 	if (rainfo->advlinkopt) {
    676 		lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
    677 		buf += lladdroptlen;
    678 	}
    679 
    680 	if (rainfo->linkmtu) {
    681 		ndopt_mtu = (struct nd_opt_mtu *)buf;
    682 		ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
    683 		ndopt_mtu->nd_opt_mtu_len = 1;
    684 		ndopt_mtu->nd_opt_mtu_reserved = 0;
    685 		ndopt_mtu->nd_opt_mtu_mtu = ntohl(rainfo->linkmtu);
    686 		buf += sizeof(struct nd_opt_mtu);
    687 	}
    688 
    689 #ifdef MIP6
    690 	if (mobileip6 && rainfo->maxinterval) {
    691 		ndopt_advint = (struct nd_opt_advint *)buf;
    692 		ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL;
    693 		ndopt_advint->nd_opt_int_len = 1;
    694 		ndopt_advint->nd_opt_int_reserved = 0;
    695 		ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval *
    696 							  1000);
    697 		buf += sizeof(struct nd_opt_advint);
    698 	}
    699 #endif
    700 
    701 #ifdef MIP6
    702 	if (rainfo->hatime) {
    703 		ndopt_hai = (struct nd_opt_hai *)buf;
    704 		ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
    705 		ndopt_hai->nd_opt_hai_len = 1;
    706 		ndopt_hai->nd_opt_hai_reserved = 0;
    707 		ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref);
    708 		ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime);
    709 		buf += sizeof(struct nd_opt_hai);
    710 	}
    711 #endif
    712 
    713 	for (pfx = rainfo->prefix.next;
    714 	     pfx != &rainfo->prefix; pfx = pfx->next) {
    715 		ndopt_pi = (struct nd_opt_prefix_info *)buf;
    716 		ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
    717 		ndopt_pi->nd_opt_pi_len = 4;
    718 		ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
    719 		ndopt_pi->nd_opt_pi_flags_reserved = 0;
    720 		if (pfx->onlinkflg)
    721 			ndopt_pi->nd_opt_pi_flags_reserved |=
    722 				ND_OPT_PI_FLAG_ONLINK;
    723 		if (pfx->autoconfflg)
    724 			ndopt_pi->nd_opt_pi_flags_reserved |=
    725 				ND_OPT_PI_FLAG_AUTO;
    726 #ifdef MIP6
    727 		if (pfx->routeraddr)
    728 			ndopt_pi->nd_opt_pi_flags_reserved |=
    729 				ND_OPT_PI_FLAG_RTADDR;
    730 #endif
    731 		ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime);
    732 		ndopt_pi->nd_opt_pi_preferred_time =
    733 			ntohl(pfx->preflifetime);
    734 		ndopt_pi->nd_opt_pi_reserved2 = 0;
    735 		ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
    736 
    737 		buf += sizeof(struct nd_opt_prefix_info);
    738 	}
    739 
    740 	return;
    741 }
    742