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