1 |
27 |
unneback |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// src/sys/netinet6/nd6_rtr.c
|
4 |
|
|
//
|
5 |
|
|
//==========================================================================
|
6 |
|
|
//####BSDCOPYRIGHTBEGIN####
|
7 |
|
|
//
|
8 |
|
|
// -------------------------------------------
|
9 |
|
|
//
|
10 |
|
|
// Portions of this software may have been derived from OpenBSD,
|
11 |
|
|
// FreeBSD or other sources, and are covered by the appropriate
|
12 |
|
|
// copyright disclaimers included herein.
|
13 |
|
|
//
|
14 |
|
|
// Portions created by Red Hat are
|
15 |
|
|
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
|
16 |
|
|
//
|
17 |
|
|
// -------------------------------------------
|
18 |
|
|
//
|
19 |
|
|
//####BSDCOPYRIGHTEND####
|
20 |
|
|
//==========================================================================
|
21 |
|
|
|
22 |
|
|
/* $KAME: nd6_rtr.c,v 1.187 2001/12/18 02:01:25 itojun Exp $ */
|
23 |
|
|
|
24 |
|
|
/*
|
25 |
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
26 |
|
|
* All rights reserved.
|
27 |
|
|
*
|
28 |
|
|
* Redistribution and use in source and binary forms, with or without
|
29 |
|
|
* modification, are permitted provided that the following conditions
|
30 |
|
|
* are met:
|
31 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
32 |
|
|
* notice, this list of conditions and the following disclaimer.
|
33 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
34 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
35 |
|
|
* documentation and/or other materials provided with the distribution.
|
36 |
|
|
* 3. Neither the name of the project nor the names of its contributors
|
37 |
|
|
* may be used to endorse or promote products derived from this software
|
38 |
|
|
* without specific prior written permission.
|
39 |
|
|
*
|
40 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
41 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
42 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
43 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
44 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
45 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
46 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
47 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
48 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
49 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
50 |
|
|
* SUCH DAMAGE.
|
51 |
|
|
*/
|
52 |
|
|
|
53 |
|
|
#include <sys/param.h>
|
54 |
|
|
#include <sys/malloc.h>
|
55 |
|
|
#include <sys/mbuf.h>
|
56 |
|
|
#include <sys/socket.h>
|
57 |
|
|
#include <sys/sockio.h>
|
58 |
|
|
#include <sys/time.h>
|
59 |
|
|
#include <sys/errno.h>
|
60 |
|
|
#include <sys/queue.h>
|
61 |
|
|
#ifdef __OpenBSD__
|
62 |
|
|
#include <dev/rndvar.h>
|
63 |
|
|
#endif
|
64 |
|
|
|
65 |
|
|
#include <net/if.h>
|
66 |
|
|
#include <net/if_types.h>
|
67 |
|
|
#include <net/if_dl.h>
|
68 |
|
|
#include <net/route.h>
|
69 |
|
|
#include <net/radix.h>
|
70 |
|
|
|
71 |
|
|
#include <netinet/in.h>
|
72 |
|
|
#include <netinet6/in6_var.h>
|
73 |
|
|
#include <netinet6/in6_ifattach.h>
|
74 |
|
|
#include <netinet/ip6.h>
|
75 |
|
|
#include <netinet6/ip6_var.h>
|
76 |
|
|
#include <netinet6/nd6.h>
|
77 |
|
|
#include <netinet/icmp6.h>
|
78 |
|
|
#include <netinet6/scope6_var.h>
|
79 |
|
|
|
80 |
|
|
#ifdef MIP6
|
81 |
|
|
#include <netinet6/mip6.h>
|
82 |
|
|
#endif /* MIP6 */
|
83 |
|
|
|
84 |
|
|
#define SDL(s) ((struct sockaddr_dl *)s)
|
85 |
|
|
|
86 |
|
|
static int rtpref __P((struct nd_defrouter *));
|
87 |
|
|
static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
|
88 |
|
|
static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *));
|
89 |
|
|
static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
|
90 |
|
|
struct nd_defrouter *));
|
91 |
|
|
static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
|
92 |
|
|
static void pfxrtr_del __P((struct nd_pfxrouter *));
|
93 |
|
|
static struct nd_pfxrouter *find_pfxlist_reachable_router
|
94 |
|
|
__P((struct nd_prefix *));
|
95 |
|
|
static void defrouter_delreq __P((struct nd_defrouter *));
|
96 |
|
|
static void defrouter_addifreq __P((struct ifnet *));
|
97 |
|
|
static void defrouter_delifreq __P((void));
|
98 |
|
|
static void nd6_rtmsg __P((int, struct rtentry *));
|
99 |
|
|
|
100 |
|
|
static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
|
101 |
|
|
struct in6_addrlifetime *lt6));
|
102 |
|
|
|
103 |
|
|
static int rt6_deleteroute __P((struct radix_node *, void *));
|
104 |
|
|
|
105 |
|
|
extern int nd6_recalc_reachtm_interval;
|
106 |
|
|
|
107 |
|
|
static struct ifnet *nd6_defifp;
|
108 |
|
|
int nd6_defifindex;
|
109 |
|
|
static struct ifaddr *nd6_defif_installed = NULL;
|
110 |
|
|
|
111 |
|
|
int ip6_use_tempaddr = 0;
|
112 |
|
|
|
113 |
|
|
int ip6_desync_factor;
|
114 |
|
|
u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
|
115 |
|
|
u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
|
116 |
|
|
int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
|
117 |
|
|
|
118 |
|
|
/* RTPREF_MEDIUM has to be 0! */
|
119 |
|
|
#define RTPREF_HIGH 1
|
120 |
|
|
#define RTPREF_MEDIUM 0
|
121 |
|
|
#define RTPREF_LOW (-1)
|
122 |
|
|
#define RTPREF_INVALID (-2)
|
123 |
|
|
|
124 |
|
|
/*
|
125 |
|
|
* Receive Router Solicitation Message - just for routers.
|
126 |
|
|
* Router solicitation/advertisement is mostly managed by userland program
|
127 |
|
|
* (rtadvd) so here we have no function like nd6_ra_output().
|
128 |
|
|
*
|
129 |
|
|
* Based on RFC 2461
|
130 |
|
|
*/
|
131 |
|
|
void
|
132 |
|
|
nd6_rs_input(m, off, icmp6len)
|
133 |
|
|
struct mbuf *m;
|
134 |
|
|
int off, icmp6len;
|
135 |
|
|
{
|
136 |
|
|
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
137 |
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
138 |
|
|
struct nd_router_solicit *nd_rs;
|
139 |
|
|
struct in6_addr saddr6 = ip6->ip6_src;
|
140 |
|
|
#if 0
|
141 |
|
|
struct in6_addr daddr6 = ip6->ip6_dst;
|
142 |
|
|
#endif
|
143 |
|
|
char *lladdr = NULL;
|
144 |
|
|
int lladdrlen = 0;
|
145 |
|
|
#if 0
|
146 |
|
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
|
147 |
|
|
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
|
148 |
|
|
struct rtentry *rt = NULL;
|
149 |
|
|
int is_newentry;
|
150 |
|
|
#endif
|
151 |
|
|
union nd_opts ndopts;
|
152 |
|
|
|
153 |
|
|
/* If I'm not a router, ignore it. */
|
154 |
|
|
if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
|
155 |
|
|
goto freeit;
|
156 |
|
|
|
157 |
|
|
/* Sanity checks */
|
158 |
|
|
if (ip6->ip6_hlim != 255) {
|
159 |
|
|
nd6log((LOG_ERR,
|
160 |
|
|
"nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
|
161 |
|
|
ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
|
162 |
|
|
ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
|
163 |
|
|
goto bad;
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
/*
|
167 |
|
|
* Don't update the neighbor cache, if src = ::.
|
168 |
|
|
* This indicates that the src has no IP address assigned yet.
|
169 |
|
|
*/
|
170 |
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
|
171 |
|
|
goto freeit;
|
172 |
|
|
|
173 |
|
|
#ifndef PULLDOWN_TEST
|
174 |
|
|
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
175 |
|
|
nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
|
176 |
|
|
#else
|
177 |
|
|
IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
|
178 |
|
|
if (nd_rs == NULL) {
|
179 |
|
|
icmp6stat.icp6s_tooshort++;
|
180 |
|
|
return;
|
181 |
|
|
}
|
182 |
|
|
#endif
|
183 |
|
|
|
184 |
|
|
icmp6len -= sizeof(*nd_rs);
|
185 |
|
|
nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
|
186 |
|
|
if (nd6_options(&ndopts) < 0) {
|
187 |
|
|
nd6log((LOG_INFO,
|
188 |
|
|
"nd6_rs_input: invalid ND option, ignored\n"));
|
189 |
|
|
/* nd6_options have incremented stats */
|
190 |
|
|
goto freeit;
|
191 |
|
|
}
|
192 |
|
|
|
193 |
|
|
if (ndopts.nd_opts_src_lladdr) {
|
194 |
|
|
lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
|
195 |
|
|
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
199 |
|
|
nd6log((LOG_INFO,
|
200 |
|
|
"nd6_rs_input: lladdrlen mismatch for %s "
|
201 |
|
|
"(if %d, RS packet %d)\n",
|
202 |
|
|
ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
|
203 |
|
|
goto bad;
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
|
207 |
|
|
|
208 |
|
|
freeit:
|
209 |
|
|
m_freem(m);
|
210 |
|
|
return;
|
211 |
|
|
|
212 |
|
|
bad:
|
213 |
|
|
icmp6stat.icp6s_badrs++;
|
214 |
|
|
m_freem(m);
|
215 |
|
|
}
|
216 |
|
|
|
217 |
|
|
/*
|
218 |
|
|
* Receive Router Advertisement Message.
|
219 |
|
|
*
|
220 |
|
|
* Based on RFC 2461
|
221 |
|
|
* TODO: on-link bit on prefix information
|
222 |
|
|
* TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
|
223 |
|
|
*/
|
224 |
|
|
void
|
225 |
|
|
nd6_ra_input(m, off, icmp6len)
|
226 |
|
|
struct mbuf *m;
|
227 |
|
|
int off, icmp6len;
|
228 |
|
|
{
|
229 |
|
|
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
230 |
|
|
struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
|
231 |
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
232 |
|
|
struct nd_router_advert *nd_ra;
|
233 |
|
|
struct in6_addr saddr6 = ip6->ip6_src;
|
234 |
|
|
#if 0
|
235 |
|
|
struct in6_addr daddr6 = ip6->ip6_dst;
|
236 |
|
|
int flags; /* = nd_ra->nd_ra_flags_reserved; */
|
237 |
|
|
int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
|
238 |
|
|
int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
|
239 |
|
|
#endif
|
240 |
|
|
union nd_opts ndopts;
|
241 |
|
|
struct nd_defrouter *dr;
|
242 |
|
|
|
243 |
|
|
/*
|
244 |
|
|
* We only accept RAs only when
|
245 |
|
|
* the system-wide variable allows the acceptance, and
|
246 |
|
|
* per-interface variable allows RAs on the receiving interface.
|
247 |
|
|
*/
|
248 |
|
|
if (ip6_accept_rtadv == 0)
|
249 |
|
|
goto freeit;
|
250 |
|
|
if (!(nd_ifinfo[ifp->if_index].flags & ND6_IFF_ACCEPT_RTADV))
|
251 |
|
|
goto freeit;
|
252 |
|
|
|
253 |
|
|
if (ip6->ip6_hlim != 255) {
|
254 |
|
|
nd6log((LOG_ERR,
|
255 |
|
|
"nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
|
256 |
|
|
ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
|
257 |
|
|
ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
|
258 |
|
|
goto bad;
|
259 |
|
|
}
|
260 |
|
|
|
261 |
|
|
if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
|
262 |
|
|
nd6log((LOG_ERR,
|
263 |
|
|
"nd6_ra_input: src %s is not link-local\n",
|
264 |
|
|
ip6_sprintf(&saddr6)));
|
265 |
|
|
goto bad;
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
#ifndef PULLDOWN_TEST
|
269 |
|
|
IP6_EXTHDR_CHECK(m, off, icmp6len,);
|
270 |
|
|
nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
|
271 |
|
|
#else
|
272 |
|
|
IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
|
273 |
|
|
if (nd_ra == NULL) {
|
274 |
|
|
icmp6stat.icp6s_tooshort++;
|
275 |
|
|
return;
|
276 |
|
|
}
|
277 |
|
|
#endif
|
278 |
|
|
|
279 |
|
|
icmp6len -= sizeof(*nd_ra);
|
280 |
|
|
nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
|
281 |
|
|
if (nd6_options(&ndopts) < 0) {
|
282 |
|
|
nd6log((LOG_INFO,
|
283 |
|
|
"nd6_ra_input: invalid ND option, ignored\n"));
|
284 |
|
|
/* nd6_options have incremented stats */
|
285 |
|
|
goto freeit;
|
286 |
|
|
}
|
287 |
|
|
|
288 |
|
|
{
|
289 |
|
|
struct nd_defrouter dr0;
|
290 |
|
|
u_int32_t advreachable = nd_ra->nd_ra_reachable;
|
291 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
292 |
|
|
long time_second = time.tv_sec;
|
293 |
|
|
#endif
|
294 |
|
|
|
295 |
|
|
Bzero(&dr0, sizeof(dr0));
|
296 |
|
|
dr0.rtaddr = saddr6;
|
297 |
|
|
dr0.flags = nd_ra->nd_ra_flags_reserved;
|
298 |
|
|
dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
|
299 |
|
|
dr0.expire = time_second + dr0.rtlifetime;
|
300 |
|
|
dr0.ifp = ifp;
|
301 |
|
|
dr0.advint = 0; /* Mobile IPv6 */
|
302 |
|
|
dr0.advint_expire = 0; /* Mobile IPv6 */
|
303 |
|
|
dr0.advints_lost = 0; /* Mobile IPv6 */
|
304 |
|
|
/* unspecified or not? (RFC 2461 6.3.4) */
|
305 |
|
|
if (advreachable) {
|
306 |
|
|
NTOHL(advreachable);
|
307 |
|
|
if (advreachable <= MAX_REACHABLE_TIME &&
|
308 |
|
|
ndi->basereachable != advreachable) {
|
309 |
|
|
ndi->basereachable = advreachable;
|
310 |
|
|
ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
|
311 |
|
|
ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
|
312 |
|
|
}
|
313 |
|
|
}
|
314 |
|
|
if (nd_ra->nd_ra_retransmit)
|
315 |
|
|
ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
|
316 |
|
|
if (nd_ra->nd_ra_curhoplimit)
|
317 |
|
|
ndi->chlim = nd_ra->nd_ra_curhoplimit;
|
318 |
|
|
dr = defrtrlist_update(&dr0);
|
319 |
|
|
}
|
320 |
|
|
|
321 |
|
|
/*
|
322 |
|
|
* prefix
|
323 |
|
|
*/
|
324 |
|
|
if (ndopts.nd_opts_pi) {
|
325 |
|
|
struct nd_opt_hdr *pt;
|
326 |
|
|
struct nd_opt_prefix_info *pi = NULL;
|
327 |
|
|
struct nd_prefix pr;
|
328 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
329 |
|
|
long time_second = time.tv_sec;
|
330 |
|
|
#endif
|
331 |
|
|
|
332 |
|
|
for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
|
333 |
|
|
pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
|
334 |
|
|
pt = (struct nd_opt_hdr *)((caddr_t)pt +
|
335 |
|
|
(pt->nd_opt_len << 3))) {
|
336 |
|
|
if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
|
337 |
|
|
continue;
|
338 |
|
|
pi = (struct nd_opt_prefix_info *)pt;
|
339 |
|
|
|
340 |
|
|
if (pi->nd_opt_pi_len != 4) {
|
341 |
|
|
nd6log((LOG_INFO,
|
342 |
|
|
"nd6_ra_input: invalid option "
|
343 |
|
|
"len %d for prefix information option, "
|
344 |
|
|
"ignored\n", pi->nd_opt_pi_len));
|
345 |
|
|
continue;
|
346 |
|
|
}
|
347 |
|
|
|
348 |
|
|
if (128 < pi->nd_opt_pi_prefix_len) {
|
349 |
|
|
nd6log((LOG_INFO,
|
350 |
|
|
"nd6_ra_input: invalid prefix "
|
351 |
|
|
"len %d for prefix information option, "
|
352 |
|
|
"ignored\n", pi->nd_opt_pi_prefix_len));
|
353 |
|
|
continue;
|
354 |
|
|
}
|
355 |
|
|
|
356 |
|
|
if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
|
357 |
|
|
|| IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
|
358 |
|
|
nd6log((LOG_INFO,
|
359 |
|
|
"nd6_ra_input: invalid prefix "
|
360 |
|
|
"%s, ignored\n",
|
361 |
|
|
ip6_sprintf(&pi->nd_opt_pi_prefix)));
|
362 |
|
|
continue;
|
363 |
|
|
}
|
364 |
|
|
|
365 |
|
|
/* aggregatable unicast address, rfc2374 */
|
366 |
|
|
if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
|
367 |
|
|
&& pi->nd_opt_pi_prefix_len != 64) {
|
368 |
|
|
nd6log((LOG_INFO,
|
369 |
|
|
"nd6_ra_input: invalid prefixlen "
|
370 |
|
|
"%d for rfc2374 prefix %s, ignored\n",
|
371 |
|
|
pi->nd_opt_pi_prefix_len,
|
372 |
|
|
ip6_sprintf(&pi->nd_opt_pi_prefix)));
|
373 |
|
|
continue;
|
374 |
|
|
}
|
375 |
|
|
|
376 |
|
|
bzero(&pr, sizeof(pr));
|
377 |
|
|
pr.ndpr_prefix.sin6_family = AF_INET6;
|
378 |
|
|
pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
|
379 |
|
|
pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
|
380 |
|
|
pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
|
381 |
|
|
|
382 |
|
|
pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
|
383 |
|
|
ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
|
384 |
|
|
pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
|
385 |
|
|
ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
|
386 |
|
|
#ifdef MIP6
|
387 |
|
|
pr.ndpr_raf_router = (pi->nd_opt_pi_flags_reserved &
|
388 |
|
|
ND_OPT_PI_FLAG_ROUTER) ? 1 : 0;
|
389 |
|
|
#endif /* MIP6 */
|
390 |
|
|
pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
|
391 |
|
|
pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
|
392 |
|
|
pr.ndpr_pltime =
|
393 |
|
|
ntohl(pi->nd_opt_pi_preferred_time);
|
394 |
|
|
pr.ndpr_lastupdate = time_second;
|
395 |
|
|
|
396 |
|
|
if (in6_init_prefix_ltimes(&pr))
|
397 |
|
|
continue; /* prefix lifetime init failed */
|
398 |
|
|
#ifdef MIP6
|
399 |
|
|
if (MIP6_IS_MN) {
|
400 |
|
|
if (mip6_prefix_list_update(&saddr6, &pr, dr, m)) {
|
401 |
|
|
mip6log((LOG_ERR,
|
402 |
|
|
"%s:%d: "
|
403 |
|
|
"prefix info processing "
|
404 |
|
|
"failed\n",
|
405 |
|
|
__FILE__, __LINE__));
|
406 |
|
|
goto freeit;
|
407 |
|
|
}
|
408 |
|
|
}
|
409 |
|
|
#endif /* MIP6 */
|
410 |
|
|
(void)prelist_update(&pr, dr, m);
|
411 |
|
|
}
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
#ifdef MIP6
|
415 |
|
|
if (MIP6_IS_MN) {
|
416 |
|
|
/* check reachability of all routers. */
|
417 |
|
|
mip6_probe_routers();
|
418 |
|
|
}
|
419 |
|
|
|
420 |
|
|
/* update home agent list. */
|
421 |
|
|
if ((MIP6_IS_MN || MIP6_IS_HA)
|
422 |
|
|
&& dr
|
423 |
|
|
&& (dr->flags & ND_RA_FLAG_HOME_AGENT)) {
|
424 |
|
|
if (mip6_ha_list_update_hainfo(&mip6_ha_list,
|
425 |
|
|
dr, ndopts.nd_opts_hai)) {
|
426 |
|
|
mip6log((LOG_ERR,
|
427 |
|
|
"%s:%d: global HA list update failed\n",
|
428 |
|
|
__FILE__, __LINE__));
|
429 |
|
|
}
|
430 |
|
|
}
|
431 |
|
|
if (dr == NULL) {
|
432 |
|
|
struct mip6_ha *mha;
|
433 |
|
|
|
434 |
|
|
/* the home agent is shutting down. */
|
435 |
|
|
mha = mip6_ha_list_find_withaddr(&mip6_ha_list, &saddr6);
|
436 |
|
|
if (mha) {
|
437 |
|
|
if (mip6_ha_list_remove(&mip6_ha_list, mha)) {
|
438 |
|
|
mip6log((LOG_ERR,
|
439 |
|
|
"%s:%d: HA entry remove failed.\n",
|
440 |
|
|
__FILE__, __LINE__));
|
441 |
|
|
}
|
442 |
|
|
}
|
443 |
|
|
}
|
444 |
|
|
#endif /* MIP6 */
|
445 |
|
|
|
446 |
|
|
/*
|
447 |
|
|
* MTU
|
448 |
|
|
*/
|
449 |
|
|
if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
|
450 |
|
|
u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
|
451 |
|
|
|
452 |
|
|
/* lower bound */
|
453 |
|
|
if (mtu < IPV6_MMTU) {
|
454 |
|
|
nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
|
455 |
|
|
"mtu=%d sent from %s, ignoring\n",
|
456 |
|
|
mtu, ip6_sprintf(&ip6->ip6_src)));
|
457 |
|
|
goto skip;
|
458 |
|
|
}
|
459 |
|
|
|
460 |
|
|
/* upper bound */
|
461 |
|
|
if (ndi->maxmtu) {
|
462 |
|
|
if (mtu <= ndi->maxmtu) {
|
463 |
|
|
int change = (ndi->linkmtu != mtu);
|
464 |
|
|
|
465 |
|
|
ndi->linkmtu = mtu;
|
466 |
|
|
if (change) /* in6_maxmtu may change */
|
467 |
|
|
in6_setmaxmtu();
|
468 |
|
|
} else {
|
469 |
|
|
nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
|
470 |
|
|
"mtu=%d sent from %s; "
|
471 |
|
|
"exceeds maxmtu %d, ignoring\n",
|
472 |
|
|
mtu, ip6_sprintf(&ip6->ip6_src),
|
473 |
|
|
ndi->maxmtu));
|
474 |
|
|
}
|
475 |
|
|
} else {
|
476 |
|
|
nd6log((LOG_INFO, "nd6_ra_input: mtu option "
|
477 |
|
|
"mtu=%d sent from %s; maxmtu unknown, "
|
478 |
|
|
"ignoring\n",
|
479 |
|
|
mtu, ip6_sprintf(&ip6->ip6_src)));
|
480 |
|
|
}
|
481 |
|
|
}
|
482 |
|
|
|
483 |
|
|
skip:
|
484 |
|
|
|
485 |
|
|
/*
|
486 |
|
|
* Source link layer address
|
487 |
|
|
*/
|
488 |
|
|
{
|
489 |
|
|
char *lladdr = NULL;
|
490 |
|
|
int lladdrlen = 0;
|
491 |
|
|
|
492 |
|
|
if (ndopts.nd_opts_src_lladdr) {
|
493 |
|
|
lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
|
494 |
|
|
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
498 |
|
|
nd6log((LOG_INFO,
|
499 |
|
|
"nd6_ra_input: lladdrlen mismatch for %s "
|
500 |
|
|
"(if %d, RA packet %d)\n",
|
501 |
|
|
ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
|
502 |
|
|
goto bad;
|
503 |
|
|
}
|
504 |
|
|
|
505 |
|
|
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
|
506 |
|
|
|
507 |
|
|
/*
|
508 |
|
|
* Installing a link-layer address might change the state of the
|
509 |
|
|
* router's neighbor cache, which might also affect our on-link
|
510 |
|
|
* detection of adveritsed prefixes.
|
511 |
|
|
*/
|
512 |
|
|
pfxlist_onlink_check();
|
513 |
|
|
}
|
514 |
|
|
|
515 |
|
|
freeit:
|
516 |
|
|
m_freem(m);
|
517 |
|
|
return;
|
518 |
|
|
|
519 |
|
|
bad:
|
520 |
|
|
icmp6stat.icp6s_badra++;
|
521 |
|
|
m_freem(m);
|
522 |
|
|
}
|
523 |
|
|
|
524 |
|
|
/*
|
525 |
|
|
* default router list proccessing sub routines
|
526 |
|
|
*/
|
527 |
|
|
|
528 |
|
|
/* tell the change to user processes watching the routing socket. */
|
529 |
|
|
static void
|
530 |
|
|
nd6_rtmsg(cmd, rt)
|
531 |
|
|
int cmd;
|
532 |
|
|
struct rtentry *rt;
|
533 |
|
|
{
|
534 |
|
|
struct rt_addrinfo info;
|
535 |
|
|
|
536 |
|
|
bzero((caddr_t)&info, sizeof(info));
|
537 |
|
|
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) /* BSDI4 */
|
538 |
|
|
/* maybe this is unnecessary */
|
539 |
|
|
info.rti_flags = rt->rt_flags;
|
540 |
|
|
#endif
|
541 |
|
|
info.rti_info[RTAX_DST] = rt_key(rt);
|
542 |
|
|
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
543 |
|
|
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
|
544 |
|
|
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
|
545 |
|
|
info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addrlist->ifa_addr;
|
546 |
|
|
#else
|
547 |
|
|
info.rti_info[RTAX_IFP] =
|
548 |
|
|
(struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);
|
549 |
|
|
#endif
|
550 |
|
|
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
551 |
|
|
|
552 |
|
|
rt_missmsg(cmd, &info, rt->rt_flags, 0);
|
553 |
|
|
}
|
554 |
|
|
|
555 |
|
|
void
|
556 |
|
|
defrouter_addreq(new)
|
557 |
|
|
struct nd_defrouter *new;
|
558 |
|
|
{
|
559 |
|
|
struct sockaddr_in6 def, mask, gate;
|
560 |
|
|
struct rtentry *newrt = NULL;
|
561 |
|
|
int s;
|
562 |
|
|
int error;
|
563 |
|
|
|
564 |
|
|
Bzero(&def, sizeof(def));
|
565 |
|
|
Bzero(&mask, sizeof(mask));
|
566 |
|
|
Bzero(&gate, sizeof(gate));
|
567 |
|
|
|
568 |
|
|
def.sin6_len = mask.sin6_len = gate.sin6_len
|
569 |
|
|
= sizeof(struct sockaddr_in6);
|
570 |
|
|
def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
|
571 |
|
|
gate.sin6_addr = new->rtaddr;
|
572 |
|
|
|
573 |
|
|
#ifdef __NetBSD__
|
574 |
|
|
s = splsoftnet();
|
575 |
|
|
#else
|
576 |
|
|
s = splnet();
|
577 |
|
|
#endif
|
578 |
|
|
error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
|
579 |
|
|
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
|
580 |
|
|
RTF_GATEWAY, &newrt);
|
581 |
|
|
if (newrt) {
|
582 |
|
|
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
|
583 |
|
|
newrt->rt_refcnt--;
|
584 |
|
|
}
|
585 |
|
|
if (error == 0)
|
586 |
|
|
new->installed = 1;
|
587 |
|
|
splx(s);
|
588 |
|
|
return;
|
589 |
|
|
}
|
590 |
|
|
|
591 |
|
|
/* Add a route to a given interface as default */
|
592 |
|
|
static void
|
593 |
|
|
defrouter_addifreq(ifp)
|
594 |
|
|
struct ifnet *ifp;
|
595 |
|
|
{
|
596 |
|
|
struct sockaddr_in6 def, mask;
|
597 |
|
|
struct ifaddr *ifa;
|
598 |
|
|
struct rtentry *newrt = NULL;
|
599 |
|
|
int error, flags;
|
600 |
|
|
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
|
601 |
|
|
struct rt_addrinfo info;
|
602 |
|
|
#endif
|
603 |
|
|
|
604 |
|
|
/* remove one if we have already installed one */
|
605 |
|
|
if (nd6_defif_installed)
|
606 |
|
|
defrouter_delifreq();
|
607 |
|
|
|
608 |
|
|
bzero(&def, sizeof(def));
|
609 |
|
|
bzero(&mask, sizeof(mask));
|
610 |
|
|
|
611 |
|
|
def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
|
612 |
|
|
def.sin6_family = mask.sin6_family = AF_INET6;
|
613 |
|
|
|
614 |
|
|
/*
|
615 |
|
|
* Search for an ifaddr beloging to the specified interface.
|
616 |
|
|
* XXX: An IPv6 address are required to be assigned on the interface.
|
617 |
|
|
*/
|
618 |
|
|
if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
|
619 |
|
|
nd6log((LOG_ERR, /* better error? */
|
620 |
|
|
"defrouter_addifreq: failed to find an ifaddr "
|
621 |
|
|
"to install a route to interface %s\n",
|
622 |
|
|
if_name(ifp)));
|
623 |
|
|
return;
|
624 |
|
|
}
|
625 |
|
|
|
626 |
|
|
flags = ifa->ifa_flags;
|
627 |
|
|
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
|
628 |
|
|
bzero(&info, sizeof(info));
|
629 |
|
|
info.rti_info[RTAX_DST] = (struct sockaddr *)&def;
|
630 |
|
|
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)ifa->ifa_addr;
|
631 |
|
|
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
|
632 |
|
|
info.rti_info[RTAX_IFA] = (struct sockaddr *)ifa->ifa_addr;
|
633 |
|
|
info.rti_flags = flags;
|
634 |
|
|
error = rtrequest1(RTM_ADD, &info, &newrt);
|
635 |
|
|
#else
|
636 |
|
|
error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
|
637 |
|
|
(struct sockaddr *)&mask, flags, &newrt);
|
638 |
|
|
#endif
|
639 |
|
|
if (error != 0) {
|
640 |
|
|
nd6log((LOG_ERR,
|
641 |
|
|
"defrouter_addifreq: failed to install a route to "
|
642 |
|
|
"interface %s (errno = %d)\n",
|
643 |
|
|
if_name(ifp), error));
|
644 |
|
|
|
645 |
|
|
if (newrt) /* maybe unnecessary, but do it for safety */
|
646 |
|
|
newrt->rt_refcnt--;
|
647 |
|
|
} else {
|
648 |
|
|
if (newrt) {
|
649 |
|
|
nd6_rtmsg(RTM_ADD, newrt);
|
650 |
|
|
newrt->rt_refcnt--;
|
651 |
|
|
}
|
652 |
|
|
}
|
653 |
|
|
|
654 |
|
|
nd6_defif_installed = ifa;
|
655 |
|
|
IFAREF(ifa);
|
656 |
|
|
}
|
657 |
|
|
|
658 |
|
|
/* Remove a default route points to interface */
|
659 |
|
|
static void
|
660 |
|
|
defrouter_delifreq()
|
661 |
|
|
{
|
662 |
|
|
struct sockaddr_in6 def, mask;
|
663 |
|
|
struct rtentry *oldrt = NULL;
|
664 |
|
|
|
665 |
|
|
if (!nd6_defif_installed)
|
666 |
|
|
return;
|
667 |
|
|
|
668 |
|
|
Bzero(&def, sizeof(def));
|
669 |
|
|
Bzero(&mask, sizeof(mask));
|
670 |
|
|
|
671 |
|
|
def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
|
672 |
|
|
def.sin6_family = mask.sin6_family = AF_INET6;
|
673 |
|
|
|
674 |
|
|
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
|
675 |
|
|
(struct sockaddr *)nd6_defif_installed->ifa_addr,
|
676 |
|
|
(struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
|
677 |
|
|
if (oldrt) {
|
678 |
|
|
nd6_rtmsg(RTM_DELETE, oldrt);
|
679 |
|
|
if (oldrt->rt_refcnt <= 0) {
|
680 |
|
|
/*
|
681 |
|
|
* XXX: borrowed from the RTM_DELETE case of
|
682 |
|
|
* rtrequest().
|
683 |
|
|
*/
|
684 |
|
|
oldrt->rt_refcnt++;
|
685 |
|
|
rtfree(oldrt);
|
686 |
|
|
}
|
687 |
|
|
}
|
688 |
|
|
|
689 |
|
|
IFAFREE(nd6_defif_installed);
|
690 |
|
|
nd6_defif_installed = NULL;
|
691 |
|
|
}
|
692 |
|
|
|
693 |
|
|
struct nd_defrouter *
|
694 |
|
|
defrouter_lookup(addr, ifp)
|
695 |
|
|
struct in6_addr *addr;
|
696 |
|
|
struct ifnet *ifp;
|
697 |
|
|
{
|
698 |
|
|
struct nd_defrouter *dr;
|
699 |
|
|
|
700 |
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
701 |
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
702 |
|
|
if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
|
703 |
|
|
return(dr);
|
704 |
|
|
}
|
705 |
|
|
|
706 |
|
|
return(NULL); /* search failed */
|
707 |
|
|
}
|
708 |
|
|
|
709 |
|
|
void
|
710 |
|
|
defrtrlist_del(dr)
|
711 |
|
|
struct nd_defrouter *dr;
|
712 |
|
|
{
|
713 |
|
|
struct nd_defrouter *deldr = NULL;
|
714 |
|
|
struct nd_prefix *pr;
|
715 |
|
|
|
716 |
|
|
/*
|
717 |
|
|
* Flush all the routing table entries that use the router
|
718 |
|
|
* as a next hop.
|
719 |
|
|
*/
|
720 |
|
|
if (!ip6_forwarding && ip6_accept_rtadv) {
|
721 |
|
|
/* above is a good condition? */
|
722 |
|
|
rt6_flush(&dr->rtaddr, dr->ifp);
|
723 |
|
|
}
|
724 |
|
|
|
725 |
|
|
if (dr->installed) {
|
726 |
|
|
deldr = dr;
|
727 |
|
|
defrouter_delreq(dr);
|
728 |
|
|
}
|
729 |
|
|
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
|
730 |
|
|
|
731 |
|
|
/*
|
732 |
|
|
* Also delete all the pointers to the router in each prefix lists.
|
733 |
|
|
*/
|
734 |
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
735 |
|
|
struct nd_pfxrouter *pfxrtr;
|
736 |
|
|
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
|
737 |
|
|
pfxrtr_del(pfxrtr);
|
738 |
|
|
}
|
739 |
|
|
pfxlist_onlink_check();
|
740 |
|
|
|
741 |
|
|
/*
|
742 |
|
|
* If the router is the primary one, choose a new one.
|
743 |
|
|
* Note that defrouter_select() will remove the current gateway
|
744 |
|
|
* from the routing table.
|
745 |
|
|
*/
|
746 |
|
|
if (deldr)
|
747 |
|
|
defrouter_select();
|
748 |
|
|
|
749 |
|
|
free(dr, M_IP6NDP);
|
750 |
|
|
}
|
751 |
|
|
|
752 |
|
|
/*
|
753 |
|
|
* Remove the default route for a given router.
|
754 |
|
|
* This is just a subroutine function for defrouter_select(), and should
|
755 |
|
|
* not be called from anywhere else.
|
756 |
|
|
*/
|
757 |
|
|
static void
|
758 |
|
|
defrouter_delreq(dr)
|
759 |
|
|
struct nd_defrouter *dr;
|
760 |
|
|
{
|
761 |
|
|
struct sockaddr_in6 def, mask, gw;
|
762 |
|
|
struct rtentry *oldrt = NULL;
|
763 |
|
|
|
764 |
|
|
Bzero(&def, sizeof(def));
|
765 |
|
|
Bzero(&mask, sizeof(mask));
|
766 |
|
|
Bzero(&gw, sizeof(gw));
|
767 |
|
|
|
768 |
|
|
def.sin6_len = mask.sin6_len = gw.sin6_len =
|
769 |
|
|
sizeof(struct sockaddr_in6);
|
770 |
|
|
def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6;
|
771 |
|
|
if (dr)
|
772 |
|
|
gw.sin6_addr = dr->rtaddr;
|
773 |
|
|
|
774 |
|
|
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
|
775 |
|
|
dr ? (struct sockaddr *)&gw : NULL,
|
776 |
|
|
(struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
|
777 |
|
|
if (oldrt) {
|
778 |
|
|
nd6_rtmsg(RTM_DELETE, oldrt);
|
779 |
|
|
if (oldrt->rt_refcnt <= 0) {
|
780 |
|
|
/*
|
781 |
|
|
* XXX: borrowed from the RTM_DELETE case of
|
782 |
|
|
* rtrequest().
|
783 |
|
|
*/
|
784 |
|
|
oldrt->rt_refcnt++;
|
785 |
|
|
rtfree(oldrt);
|
786 |
|
|
}
|
787 |
|
|
}
|
788 |
|
|
|
789 |
|
|
if (dr)
|
790 |
|
|
dr->installed = 0;
|
791 |
|
|
}
|
792 |
|
|
|
793 |
|
|
/*
|
794 |
|
|
* remove all default routes from default router list
|
795 |
|
|
*/
|
796 |
|
|
void
|
797 |
|
|
defrouter_reset()
|
798 |
|
|
{
|
799 |
|
|
struct nd_defrouter *dr;
|
800 |
|
|
|
801 |
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
802 |
|
|
dr = TAILQ_NEXT(dr, dr_entry))
|
803 |
|
|
defrouter_delreq(dr);
|
804 |
|
|
defrouter_delifreq();
|
805 |
|
|
|
806 |
|
|
/*
|
807 |
|
|
* XXX should we also nuke any default routers in the kernel, by
|
808 |
|
|
* going through them by rtalloc1()?
|
809 |
|
|
*/
|
810 |
|
|
}
|
811 |
|
|
|
812 |
|
|
/*
|
813 |
|
|
* Default Router Selection according to Section 6.3.6 of RFC 2461 and
|
814 |
|
|
* draft-ietf-ipngwg-router-selection:
|
815 |
|
|
* 1) Routers that are reachable or probably reachable should be preferred.
|
816 |
|
|
* If we have more than one (probably) reachable router, prefer ones
|
817 |
|
|
* with the highest router preference.
|
818 |
|
|
* 2) When no routers on the list are known to be reachable or
|
819 |
|
|
* probably reachable, routers SHOULD be selected in a round-robin
|
820 |
|
|
* fashion, regardless of router preference values.
|
821 |
|
|
* 3) If the Default Router List is empty, assume that all
|
822 |
|
|
* destinations are on-link.
|
823 |
|
|
*
|
824 |
|
|
* We assume nd_defrouter is sorted by router preference value.
|
825 |
|
|
* Since the code below covers both with and without router preference cases,
|
826 |
|
|
* we do not need to classify the cases by ifdef.
|
827 |
|
|
*
|
828 |
|
|
* At this moment, we do not try to install more than one default router,
|
829 |
|
|
* even when the multipath routing is available, because we're not sure about
|
830 |
|
|
* the benefits for stub hosts comparing to the risk of making the code
|
831 |
|
|
* complicated and the possibility of introducing bugs.
|
832 |
|
|
*/
|
833 |
|
|
void
|
834 |
|
|
defrouter_select()
|
835 |
|
|
{
|
836 |
|
|
#ifdef __NetBSD__
|
837 |
|
|
int s = splsoftnet();
|
838 |
|
|
#else
|
839 |
|
|
int s = splnet();
|
840 |
|
|
#endif
|
841 |
|
|
struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
|
842 |
|
|
struct rtentry *rt = NULL;
|
843 |
|
|
struct llinfo_nd6 *ln = NULL;
|
844 |
|
|
|
845 |
|
|
/*
|
846 |
|
|
* This function should be called only when acting as an autoconfigured
|
847 |
|
|
* host. Although the remaining part of this function is not effective
|
848 |
|
|
* if the node is not an autoconfigured host, we explicitly exclude
|
849 |
|
|
* such cases here for safety.
|
850 |
|
|
*/
|
851 |
|
|
if (ip6_forwarding || !ip6_accept_rtadv) {
|
852 |
|
|
nd6log((LOG_WARNING,
|
853 |
|
|
"defrouter_select: called unexpectedly (forwarding=%d, "
|
854 |
|
|
"accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
|
855 |
|
|
splx(s);
|
856 |
|
|
return;
|
857 |
|
|
}
|
858 |
|
|
|
859 |
|
|
/*
|
860 |
|
|
* Let's handle easy case (3) first:
|
861 |
|
|
* If default router list is empty, we should probably install
|
862 |
|
|
* an interface route and assume that all destinations are on-link.
|
863 |
|
|
*/
|
864 |
|
|
if (!TAILQ_FIRST(&nd_defrouter)) {
|
865 |
|
|
/*
|
866 |
|
|
* XXX: The specification does not say this mechanism should
|
867 |
|
|
* be restricted to hosts, but this would be not useful
|
868 |
|
|
* (even harmful) for routers.
|
869 |
|
|
* This test is meaningless due to a test at the beginning of
|
870 |
|
|
* the function, but we intentionally keep it to make the note
|
871 |
|
|
* clear.
|
872 |
|
|
*/
|
873 |
|
|
if (!ip6_forwarding) {
|
874 |
|
|
if (nd6_defifp) {
|
875 |
|
|
/*
|
876 |
|
|
* Install a route to the default interface
|
877 |
|
|
* as default route.
|
878 |
|
|
*/
|
879 |
|
|
defrouter_addifreq(nd6_defifp);
|
880 |
|
|
} else {
|
881 |
|
|
/*
|
882 |
|
|
* purge the existing route.
|
883 |
|
|
* XXX: is this really correct?
|
884 |
|
|
*/
|
885 |
|
|
defrouter_delifreq();
|
886 |
|
|
nd6log((LOG_INFO, "defrouter_select: "
|
887 |
|
|
"there's no default router and no default"
|
888 |
|
|
" interface\n"));
|
889 |
|
|
}
|
890 |
|
|
}
|
891 |
|
|
splx(s);
|
892 |
|
|
return;
|
893 |
|
|
}
|
894 |
|
|
|
895 |
|
|
/*
|
896 |
|
|
* If we have a default route for the default interface, delete it.
|
897 |
|
|
* Note that the existence of the route is checked in the delete
|
898 |
|
|
* function.
|
899 |
|
|
*/
|
900 |
|
|
defrouter_delifreq();
|
901 |
|
|
|
902 |
|
|
/*
|
903 |
|
|
* Search for a (probably) reachable router from the list.
|
904 |
|
|
* We just pick up the first reachable one (if any), assuming that
|
905 |
|
|
* the ordering rule of the list described in defrtrlist_update().
|
906 |
|
|
*/
|
907 |
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
908 |
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
909 |
|
|
if (!selected_dr &&
|
910 |
|
|
(rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
|
911 |
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
912 |
|
|
ND6_IS_LLINFO_PROBREACH(ln)) {
|
913 |
|
|
selected_dr = dr;
|
914 |
|
|
}
|
915 |
|
|
|
916 |
|
|
if (dr->installed && !installed_dr)
|
917 |
|
|
installed_dr = dr;
|
918 |
|
|
else if (dr->installed && installed_dr) {
|
919 |
|
|
/* this should not happen. warn for diagnosis. */
|
920 |
|
|
log(LOG_ERR, "defrouter_select: more than one router"
|
921 |
|
|
" is installed\n");
|
922 |
|
|
}
|
923 |
|
|
}
|
924 |
|
|
/*
|
925 |
|
|
* If none of the default routers was found to be reachable,
|
926 |
|
|
* round-robin the list regardless of preference.
|
927 |
|
|
* Otherwise, if we have an installed router, check if the selected
|
928 |
|
|
* (reachable) router should really be preferred to the installed one.
|
929 |
|
|
* We only prefer the new router when the old one is not reachable
|
930 |
|
|
* or when the new one has a really higher preference value.
|
931 |
|
|
*/
|
932 |
|
|
if (!selected_dr) {
|
933 |
|
|
if (!installed_dr || !TAILQ_NEXT(installed_dr, dr_entry))
|
934 |
|
|
selected_dr = TAILQ_FIRST(&nd_defrouter);
|
935 |
|
|
else
|
936 |
|
|
selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
|
937 |
|
|
} else if (installed_dr &&
|
938 |
|
|
(rt = nd6_lookup(&installed_dr->rtaddr, 0,
|
939 |
|
|
installed_dr->ifp)) &&
|
940 |
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
941 |
|
|
ND6_IS_LLINFO_PROBREACH(ln) &&
|
942 |
|
|
rtpref(selected_dr) <= rtpref(installed_dr)) {
|
943 |
|
|
selected_dr = installed_dr;
|
944 |
|
|
}
|
945 |
|
|
|
946 |
|
|
/*
|
947 |
|
|
* If the selected router is different than the installed one,
|
948 |
|
|
* remove the installed router and install the selected one.
|
949 |
|
|
* Note that the selected router is never NULL here.
|
950 |
|
|
*/
|
951 |
|
|
if (installed_dr != selected_dr) {
|
952 |
|
|
if (installed_dr)
|
953 |
|
|
defrouter_delreq(installed_dr);
|
954 |
|
|
defrouter_addreq(selected_dr);
|
955 |
|
|
}
|
956 |
|
|
|
957 |
|
|
splx(s);
|
958 |
|
|
return;
|
959 |
|
|
}
|
960 |
|
|
|
961 |
|
|
/*
|
962 |
|
|
* for default router selection
|
963 |
|
|
* regards router-preference field as a 2-bit signed integer
|
964 |
|
|
*/
|
965 |
|
|
static int
|
966 |
|
|
rtpref(struct nd_defrouter *dr)
|
967 |
|
|
{
|
968 |
|
|
#ifdef RTPREF
|
969 |
|
|
switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
|
970 |
|
|
case ND_RA_FLAG_RTPREF_HIGH:
|
971 |
|
|
return RTPREF_HIGH;
|
972 |
|
|
case ND_RA_FLAG_RTPREF_MEDIUM:
|
973 |
|
|
case ND_RA_FLAG_RTPREF_RSV:
|
974 |
|
|
return RTPREF_MEDIUM;
|
975 |
|
|
case ND_RA_FLAG_RTPREF_LOW:
|
976 |
|
|
return RTPREF_LOW;
|
977 |
|
|
default:
|
978 |
|
|
/*
|
979 |
|
|
* This case should never happen. If it did, it would mean a
|
980 |
|
|
* serious bug of kernel internal. We thus always bark here.
|
981 |
|
|
* Or, can we even panic?
|
982 |
|
|
*/
|
983 |
|
|
log(LOG_ERR, "rtpref: impossible RA flag %x", dr->flags);
|
984 |
|
|
return RTPREF_INVALID;
|
985 |
|
|
}
|
986 |
|
|
/* NOT REACH HERE */
|
987 |
|
|
#else
|
988 |
|
|
return RTPREF_MEDIUM;
|
989 |
|
|
#endif
|
990 |
|
|
}
|
991 |
|
|
|
992 |
|
|
static struct nd_defrouter *
|
993 |
|
|
defrtrlist_update(new)
|
994 |
|
|
struct nd_defrouter *new;
|
995 |
|
|
{
|
996 |
|
|
struct nd_defrouter *dr, *n;
|
997 |
|
|
#ifdef __NetBSD__
|
998 |
|
|
int s = splsoftnet();
|
999 |
|
|
#else
|
1000 |
|
|
int s = splnet();
|
1001 |
|
|
#endif
|
1002 |
|
|
|
1003 |
|
|
if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
|
1004 |
|
|
/* entry exists */
|
1005 |
|
|
if (new->rtlifetime == 0) {
|
1006 |
|
|
defrtrlist_del(dr);
|
1007 |
|
|
dr = NULL;
|
1008 |
|
|
} else {
|
1009 |
|
|
int oldpref = rtpref(dr);
|
1010 |
|
|
|
1011 |
|
|
/* override */
|
1012 |
|
|
dr->flags = new->flags; /* xxx flag check */
|
1013 |
|
|
dr->rtlifetime = new->rtlifetime;
|
1014 |
|
|
dr->expire = new->expire;
|
1015 |
|
|
|
1016 |
|
|
/*
|
1017 |
|
|
* If the preference does not change, there's no need
|
1018 |
|
|
* to sort the entries.
|
1019 |
|
|
*/
|
1020 |
|
|
if (rtpref(new) == oldpref) {
|
1021 |
|
|
splx(s);
|
1022 |
|
|
return(dr);
|
1023 |
|
|
}
|
1024 |
|
|
|
1025 |
|
|
/*
|
1026 |
|
|
* preferred router may be changed, so relocate
|
1027 |
|
|
* this router.
|
1028 |
|
|
* XXX: calling TAILQ_REMOVE directly is a bad manner.
|
1029 |
|
|
* However, since defrtrlist_del() has many side
|
1030 |
|
|
* effects, we intentionally do so here.
|
1031 |
|
|
* defrouter_select() below will handle routing
|
1032 |
|
|
* changes later.
|
1033 |
|
|
*/
|
1034 |
|
|
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
|
1035 |
|
|
n = dr;
|
1036 |
|
|
goto insert;
|
1037 |
|
|
}
|
1038 |
|
|
splx(s);
|
1039 |
|
|
return(dr);
|
1040 |
|
|
}
|
1041 |
|
|
|
1042 |
|
|
/* entry does not exist */
|
1043 |
|
|
if (new->rtlifetime == 0) {
|
1044 |
|
|
splx(s);
|
1045 |
|
|
return(NULL);
|
1046 |
|
|
}
|
1047 |
|
|
|
1048 |
|
|
n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
|
1049 |
|
|
if (n == NULL) {
|
1050 |
|
|
splx(s);
|
1051 |
|
|
return(NULL);
|
1052 |
|
|
}
|
1053 |
|
|
bzero(n, sizeof(*n));
|
1054 |
|
|
*n = *new;
|
1055 |
|
|
|
1056 |
|
|
insert:
|
1057 |
|
|
/*
|
1058 |
|
|
* Insert the new router in the Default Router List;
|
1059 |
|
|
* The Default Router List should be in the descending order
|
1060 |
|
|
* of router-preferece. Routers with the same preference are
|
1061 |
|
|
* sorted in the arriving time order.
|
1062 |
|
|
*/
|
1063 |
|
|
|
1064 |
|
|
/* insert at the end of the group */
|
1065 |
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
1066 |
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
1067 |
|
|
if (rtpref(n) > rtpref(dr))
|
1068 |
|
|
break;
|
1069 |
|
|
}
|
1070 |
|
|
if (dr)
|
1071 |
|
|
TAILQ_INSERT_BEFORE(dr, n, dr_entry);
|
1072 |
|
|
else
|
1073 |
|
|
TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
|
1074 |
|
|
|
1075 |
|
|
defrouter_select();
|
1076 |
|
|
|
1077 |
|
|
splx(s);
|
1078 |
|
|
|
1079 |
|
|
return(n);
|
1080 |
|
|
}
|
1081 |
|
|
|
1082 |
|
|
static struct nd_pfxrouter *
|
1083 |
|
|
pfxrtr_lookup(pr, dr)
|
1084 |
|
|
struct nd_prefix *pr;
|
1085 |
|
|
struct nd_defrouter *dr;
|
1086 |
|
|
{
|
1087 |
|
|
struct nd_pfxrouter *search;
|
1088 |
|
|
|
1089 |
|
|
for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
|
1090 |
|
|
if (search->router == dr)
|
1091 |
|
|
break;
|
1092 |
|
|
}
|
1093 |
|
|
|
1094 |
|
|
return(search);
|
1095 |
|
|
}
|
1096 |
|
|
|
1097 |
|
|
static void
|
1098 |
|
|
pfxrtr_add(pr, dr)
|
1099 |
|
|
struct nd_prefix *pr;
|
1100 |
|
|
struct nd_defrouter *dr;
|
1101 |
|
|
{
|
1102 |
|
|
struct nd_pfxrouter *new;
|
1103 |
|
|
|
1104 |
|
|
new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
|
1105 |
|
|
if (new == NULL)
|
1106 |
|
|
return;
|
1107 |
|
|
bzero(new, sizeof(*new));
|
1108 |
|
|
new->router = dr;
|
1109 |
|
|
|
1110 |
|
|
LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
|
1111 |
|
|
|
1112 |
|
|
pfxlist_onlink_check();
|
1113 |
|
|
}
|
1114 |
|
|
|
1115 |
|
|
static void
|
1116 |
|
|
pfxrtr_del(pfr)
|
1117 |
|
|
struct nd_pfxrouter *pfr;
|
1118 |
|
|
{
|
1119 |
|
|
LIST_REMOVE(pfr, pfr_entry);
|
1120 |
|
|
free(pfr, M_IP6NDP);
|
1121 |
|
|
}
|
1122 |
|
|
|
1123 |
|
|
struct nd_prefix *
|
1124 |
|
|
nd6_prefix_lookup(pr)
|
1125 |
|
|
struct nd_prefix *pr;
|
1126 |
|
|
{
|
1127 |
|
|
struct nd_prefix *search;
|
1128 |
|
|
|
1129 |
|
|
for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
|
1130 |
|
|
if (pr->ndpr_ifp == search->ndpr_ifp &&
|
1131 |
|
|
pr->ndpr_plen == search->ndpr_plen &&
|
1132 |
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
1133 |
|
|
&search->ndpr_prefix.sin6_addr,
|
1134 |
|
|
pr->ndpr_plen)
|
1135 |
|
|
) {
|
1136 |
|
|
break;
|
1137 |
|
|
}
|
1138 |
|
|
}
|
1139 |
|
|
|
1140 |
|
|
return(search);
|
1141 |
|
|
}
|
1142 |
|
|
|
1143 |
|
|
int
|
1144 |
|
|
nd6_prelist_add(pr, dr, newp)
|
1145 |
|
|
struct nd_prefix *pr, **newp;
|
1146 |
|
|
struct nd_defrouter *dr;
|
1147 |
|
|
{
|
1148 |
|
|
struct nd_prefix *new = NULL;
|
1149 |
|
|
int i, s;
|
1150 |
|
|
|
1151 |
|
|
new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
|
1152 |
|
|
if (new == NULL)
|
1153 |
|
|
return ENOMEM;
|
1154 |
|
|
bzero(new, sizeof(*new));
|
1155 |
|
|
*new = *pr;
|
1156 |
|
|
if (newp != NULL)
|
1157 |
|
|
*newp = new;
|
1158 |
|
|
|
1159 |
|
|
/* initilization */
|
1160 |
|
|
LIST_INIT(&new->ndpr_advrtrs);
|
1161 |
|
|
in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
|
1162 |
|
|
/* make prefix in the canonical form */
|
1163 |
|
|
for (i = 0; i < 4; i++)
|
1164 |
|
|
new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
|
1165 |
|
|
new->ndpr_mask.s6_addr32[i];
|
1166 |
|
|
|
1167 |
|
|
#ifdef __NetBSD__
|
1168 |
|
|
s = splsoftnet();
|
1169 |
|
|
#else
|
1170 |
|
|
s = splnet();
|
1171 |
|
|
#endif
|
1172 |
|
|
/* link ndpr_entry to nd_prefix list */
|
1173 |
|
|
LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
|
1174 |
|
|
splx(s);
|
1175 |
|
|
|
1176 |
|
|
/* ND_OPT_PI_FLAG_ONLINK processing */
|
1177 |
|
|
if (new->ndpr_raf_onlink) {
|
1178 |
|
|
int e;
|
1179 |
|
|
|
1180 |
|
|
if ((e = nd6_prefix_onlink(new)) != 0) {
|
1181 |
|
|
nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
|
1182 |
|
|
"the prefix %s/%d on-link on %s (errno=%d)\n",
|
1183 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1184 |
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
1185 |
|
|
/* proceed anyway. XXX: is it correct? */
|
1186 |
|
|
}
|
1187 |
|
|
}
|
1188 |
|
|
|
1189 |
|
|
if (dr)
|
1190 |
|
|
pfxrtr_add(new, dr);
|
1191 |
|
|
|
1192 |
|
|
return 0;
|
1193 |
|
|
}
|
1194 |
|
|
|
1195 |
|
|
void
|
1196 |
|
|
prelist_remove(pr)
|
1197 |
|
|
struct nd_prefix *pr;
|
1198 |
|
|
{
|
1199 |
|
|
struct nd_pfxrouter *pfr, *next;
|
1200 |
|
|
int e, s;
|
1201 |
|
|
|
1202 |
|
|
/* make sure to invalidate the prefix until it is really freed. */
|
1203 |
|
|
pr->ndpr_vltime = 0;
|
1204 |
|
|
pr->ndpr_pltime = 0;
|
1205 |
|
|
#if 0
|
1206 |
|
|
/*
|
1207 |
|
|
* Though these flags are now meaningless, we'd rather keep the value
|
1208 |
|
|
* not to confuse users when executing "ndp -p".
|
1209 |
|
|
*/
|
1210 |
|
|
pr->ndpr_raf_onlink = 0;
|
1211 |
|
|
pr->ndpr_raf_auto = 0;
|
1212 |
|
|
#endif
|
1213 |
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
|
1214 |
|
|
(e = nd6_prefix_offlink(pr)) != 0) {
|
1215 |
|
|
nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
|
1216 |
|
|
"on %s, errno=%d\n",
|
1217 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1218 |
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
1219 |
|
|
/* what should we do? */
|
1220 |
|
|
}
|
1221 |
|
|
|
1222 |
|
|
if (pr->ndpr_refcnt > 0)
|
1223 |
|
|
return; /* notice here? */
|
1224 |
|
|
|
1225 |
|
|
#ifdef __NetBSD__
|
1226 |
|
|
s = splsoftnet();
|
1227 |
|
|
#else
|
1228 |
|
|
s = splnet();
|
1229 |
|
|
#endif
|
1230 |
|
|
|
1231 |
|
|
/* unlink ndpr_entry from nd_prefix list */
|
1232 |
|
|
LIST_REMOVE(pr, ndpr_entry);
|
1233 |
|
|
|
1234 |
|
|
/* free list of routers that adversed the prefix */
|
1235 |
|
|
for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
|
1236 |
|
|
next = pfr->pfr_next;
|
1237 |
|
|
|
1238 |
|
|
free(pfr, M_IP6NDP);
|
1239 |
|
|
}
|
1240 |
|
|
splx(s);
|
1241 |
|
|
|
1242 |
|
|
free(pr, M_IP6NDP);
|
1243 |
|
|
|
1244 |
|
|
pfxlist_onlink_check();
|
1245 |
|
|
}
|
1246 |
|
|
|
1247 |
|
|
int
|
1248 |
|
|
prelist_update(new, dr, m)
|
1249 |
|
|
struct nd_prefix *new;
|
1250 |
|
|
struct nd_defrouter *dr; /* may be NULL */
|
1251 |
|
|
struct mbuf *m;
|
1252 |
|
|
{
|
1253 |
|
|
struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
|
1254 |
|
|
struct ifaddr *ifa;
|
1255 |
|
|
struct ifnet *ifp = new->ndpr_ifp;
|
1256 |
|
|
struct nd_prefix *pr;
|
1257 |
|
|
#ifdef __NetBSD__
|
1258 |
|
|
int s = splsoftnet();
|
1259 |
|
|
#else
|
1260 |
|
|
int s = splnet();
|
1261 |
|
|
#endif
|
1262 |
|
|
int error = 0;
|
1263 |
|
|
int newprefix = 0;
|
1264 |
|
|
int auth;
|
1265 |
|
|
struct in6_addrlifetime lt6_tmp;
|
1266 |
|
|
|
1267 |
|
|
auth = 0;
|
1268 |
|
|
if (m) {
|
1269 |
|
|
/*
|
1270 |
|
|
* Authenticity for NA consists authentication for
|
1271 |
|
|
* both IP header and IP datagrams, doesn't it ?
|
1272 |
|
|
*/
|
1273 |
|
|
#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
|
1274 |
|
|
auth = (m->m_flags & M_AUTHIPHDR
|
1275 |
|
|
&& m->m_flags & M_AUTHIPDGM) ? 1 : 0;
|
1276 |
|
|
#endif
|
1277 |
|
|
}
|
1278 |
|
|
|
1279 |
|
|
if ((pr = nd6_prefix_lookup(new)) != NULL) {
|
1280 |
|
|
/*
|
1281 |
|
|
* nd6_prefix_lookup() ensures that pr and new have the same
|
1282 |
|
|
* prefix on a same interface.
|
1283 |
|
|
*/
|
1284 |
|
|
|
1285 |
|
|
/*
|
1286 |
|
|
* Update prefix information. Note that the on-link (L) bit
|
1287 |
|
|
* and the autonomous (A) bit should NOT be changed from 1
|
1288 |
|
|
* to 0.
|
1289 |
|
|
*/
|
1290 |
|
|
if (new->ndpr_raf_onlink == 1)
|
1291 |
|
|
pr->ndpr_raf_onlink = 1;
|
1292 |
|
|
if (new->ndpr_raf_auto == 1)
|
1293 |
|
|
pr->ndpr_raf_auto = 1;
|
1294 |
|
|
if (new->ndpr_raf_onlink) {
|
1295 |
|
|
pr->ndpr_vltime = new->ndpr_vltime;
|
1296 |
|
|
pr->ndpr_pltime = new->ndpr_pltime;
|
1297 |
|
|
pr->ndpr_preferred = new->ndpr_preferred;
|
1298 |
|
|
pr->ndpr_expire = new->ndpr_expire;
|
1299 |
|
|
pr->ndpr_lastupdate = new->ndpr_lastupdate;
|
1300 |
|
|
}
|
1301 |
|
|
|
1302 |
|
|
if (new->ndpr_raf_onlink &&
|
1303 |
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
1304 |
|
|
int e;
|
1305 |
|
|
|
1306 |
|
|
if ((e = nd6_prefix_onlink(pr)) != 0) {
|
1307 |
|
|
nd6log((LOG_ERR,
|
1308 |
|
|
"prelist_update: failed to make "
|
1309 |
|
|
"the prefix %s/%d on-link on %s "
|
1310 |
|
|
"(errno=%d)\n",
|
1311 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1312 |
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
1313 |
|
|
/* proceed anyway. XXX: is it correct? */
|
1314 |
|
|
}
|
1315 |
|
|
}
|
1316 |
|
|
|
1317 |
|
|
if (dr && pfxrtr_lookup(pr, dr) == NULL)
|
1318 |
|
|
pfxrtr_add(pr, dr);
|
1319 |
|
|
} else {
|
1320 |
|
|
struct nd_prefix *newpr = NULL;
|
1321 |
|
|
|
1322 |
|
|
newprefix = 1;
|
1323 |
|
|
|
1324 |
|
|
if (new->ndpr_vltime == 0)
|
1325 |
|
|
goto end;
|
1326 |
|
|
if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
|
1327 |
|
|
goto end;
|
1328 |
|
|
|
1329 |
|
|
error = nd6_prelist_add(new, dr, &newpr);
|
1330 |
|
|
if (error != 0 || newpr == NULL) {
|
1331 |
|
|
nd6log((LOG_NOTICE, "prelist_update: "
|
1332 |
|
|
"nd6_prelist_add failed for %s/%d on %s "
|
1333 |
|
|
"errno=%d, returnpr=%p\n",
|
1334 |
|
|
ip6_sprintf(&new->ndpr_prefix.sin6_addr),
|
1335 |
|
|
new->ndpr_plen, if_name(new->ndpr_ifp),
|
1336 |
|
|
error, newpr));
|
1337 |
|
|
goto end; /* we should just give up in this case. */
|
1338 |
|
|
}
|
1339 |
|
|
|
1340 |
|
|
/*
|
1341 |
|
|
* XXX: from the ND point of view, we can ignore a prefix
|
1342 |
|
|
* with the on-link bit being zero. However, we need a
|
1343 |
|
|
* prefix structure for references from autoconfigured
|
1344 |
|
|
* addresses. Thus, we explicitly make sure that the prefix
|
1345 |
|
|
* itself expires now.
|
1346 |
|
|
*/
|
1347 |
|
|
if (newpr->ndpr_raf_onlink == 0) {
|
1348 |
|
|
newpr->ndpr_vltime = 0;
|
1349 |
|
|
newpr->ndpr_pltime = 0;
|
1350 |
|
|
in6_init_prefix_ltimes(newpr);
|
1351 |
|
|
}
|
1352 |
|
|
|
1353 |
|
|
pr = newpr;
|
1354 |
|
|
}
|
1355 |
|
|
|
1356 |
|
|
/*
|
1357 |
|
|
* Address autoconfiguration based on Section 5.5.3 of RFC 2462.
|
1358 |
|
|
* Note that pr must be non NULL at this point.
|
1359 |
|
|
*/
|
1360 |
|
|
|
1361 |
|
|
/* 5.5.3 (a). Ignore the prefix without the A bit set. */
|
1362 |
|
|
if (!new->ndpr_raf_auto)
|
1363 |
|
|
goto end;
|
1364 |
|
|
|
1365 |
|
|
/*
|
1366 |
|
|
* 5.5.3 (b). the link-local prefix should have been ignored in
|
1367 |
|
|
* nd6_ra_input.
|
1368 |
|
|
*/
|
1369 |
|
|
|
1370 |
|
|
/*
|
1371 |
|
|
* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
|
1372 |
|
|
* This should have been done in nd6_ra_input.
|
1373 |
|
|
*/
|
1374 |
|
|
|
1375 |
|
|
/*
|
1376 |
|
|
* 5.5.3 (d). If the prefix advertised does not match the prefix of an
|
1377 |
|
|
* address already in the list, and the Valid Lifetime is not 0,
|
1378 |
|
|
* form an address. Note that even a manually configured address
|
1379 |
|
|
* should reject autoconfiguration of a new address.
|
1380 |
|
|
*/
|
1381 |
|
|
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
|
1382 |
|
|
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
|
1383 |
|
|
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
|
1384 |
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
|
1385 |
|
|
#else
|
1386 |
|
|
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
|
1387 |
|
|
#endif
|
1388 |
|
|
{
|
1389 |
|
|
struct in6_ifaddr *ifa6;
|
1390 |
|
|
int ifa_plen;
|
1391 |
|
|
u_int32_t storedlifetime;
|
1392 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
1393 |
|
|
long time_second = time.tv_sec;
|
1394 |
|
|
#endif
|
1395 |
|
|
|
1396 |
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
1397 |
|
|
continue;
|
1398 |
|
|
|
1399 |
|
|
ifa6 = (struct in6_ifaddr *)ifa;
|
1400 |
|
|
|
1401 |
|
|
/*
|
1402 |
|
|
* Spec is not clear here, but I believe we should concentrate
|
1403 |
|
|
* on unicast (i.e. not anycast) addresses.
|
1404 |
|
|
* XXX: other ia6_flags? detached or duplicated?
|
1405 |
|
|
*/
|
1406 |
|
|
if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
|
1407 |
|
|
continue;
|
1408 |
|
|
|
1409 |
|
|
ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL);
|
1410 |
|
|
if (ifa_plen != new->ndpr_plen ||
|
1411 |
|
|
!in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr,
|
1412 |
|
|
&new->ndpr_prefix.sin6_addr,
|
1413 |
|
|
ifa_plen))
|
1414 |
|
|
continue;
|
1415 |
|
|
|
1416 |
|
|
if (ia6_match == NULL) /* remember the first one */
|
1417 |
|
|
ia6_match = ifa6;
|
1418 |
|
|
|
1419 |
|
|
if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
1420 |
|
|
continue;
|
1421 |
|
|
|
1422 |
|
|
/*
|
1423 |
|
|
* An already autoconfigured address matched. Now that we
|
1424 |
|
|
* are sure there is at least one matched address, we can
|
1425 |
|
|
* proceed to 5.5.3. (e): update the lifetimes according to the
|
1426 |
|
|
* "two hours" rule and the privacy extension.
|
1427 |
|
|
*/
|
1428 |
|
|
#define TWOHOUR (120*60)
|
1429 |
|
|
/*
|
1430 |
|
|
* RFC2462 introduces the notion of StoredLifetime to the
|
1431 |
|
|
* "two hours" rule as follows:
|
1432 |
|
|
* the Lifetime associated with the previously autoconfigured
|
1433 |
|
|
* address.
|
1434 |
|
|
* Our interpretation of this definition is "the remaining
|
1435 |
|
|
* lifetime to expiration at the evaluation time". One might
|
1436 |
|
|
* be wondering if this interpretation is really conform to the
|
1437 |
|
|
* RFC, because the text can read that "Lifetimes" are never
|
1438 |
|
|
* decreased, and our definition of the "storedlifetime" below
|
1439 |
|
|
* essentially reduces the "Valid Lifetime" advertised in the
|
1440 |
|
|
* previous RA. But, this is due to the wording of the text,
|
1441 |
|
|
* and our interpretation is the same as an author's intention.
|
1442 |
|
|
* See the discussion in the IETF ipngwg ML in August 2001,
|
1443 |
|
|
* with the Subject "StoredLifetime in RFC 2462".
|
1444 |
|
|
*/
|
1445 |
|
|
lt6_tmp = ifa6->ia6_lifetime;
|
1446 |
|
|
if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
|
1447 |
|
|
storedlifetime = ND6_INFINITE_LIFETIME;
|
1448 |
|
|
else if (time_second - ifa6->ia6_updatetime >
|
1449 |
|
|
lt6_tmp.ia6t_vltime) {
|
1450 |
|
|
/*
|
1451 |
|
|
* The case of "invalid" address. We should usually
|
1452 |
|
|
* not see this case.
|
1453 |
|
|
*/
|
1454 |
|
|
storedlifetime = 0;
|
1455 |
|
|
} else
|
1456 |
|
|
storedlifetime = lt6_tmp.ia6t_vltime -
|
1457 |
|
|
(time_second - ifa6->ia6_updatetime);
|
1458 |
|
|
if (TWOHOUR < new->ndpr_vltime ||
|
1459 |
|
|
storedlifetime < new->ndpr_vltime) {
|
1460 |
|
|
lt6_tmp.ia6t_vltime = new->ndpr_vltime;
|
1461 |
|
|
} else if (storedlifetime <= TWOHOUR
|
1462 |
|
|
#if 0
|
1463 |
|
|
/*
|
1464 |
|
|
* This condition is logically redundant, so we just
|
1465 |
|
|
* omit it.
|
1466 |
|
|
* See IPng 6712, 6717, and 6721.
|
1467 |
|
|
*/
|
1468 |
|
|
&& new->ndpr_vltime <= storedlifetime
|
1469 |
|
|
#endif
|
1470 |
|
|
) {
|
1471 |
|
|
if (auth) {
|
1472 |
|
|
lt6_tmp.ia6t_vltime = new->ndpr_vltime;
|
1473 |
|
|
}
|
1474 |
|
|
} else {
|
1475 |
|
|
/*
|
1476 |
|
|
* new->ndpr_vltime <= TWOHOUR &&
|
1477 |
|
|
* TWOHOUR < storedlifetime
|
1478 |
|
|
*/
|
1479 |
|
|
lt6_tmp.ia6t_vltime = TWOHOUR;
|
1480 |
|
|
}
|
1481 |
|
|
|
1482 |
|
|
/* The 2 hour rule is not imposed for preferred lifetime. */
|
1483 |
|
|
lt6_tmp.ia6t_pltime = new->ndpr_pltime;
|
1484 |
|
|
|
1485 |
|
|
in6_init_address_ltimes(pr, <6_tmp);
|
1486 |
|
|
|
1487 |
|
|
/*
|
1488 |
|
|
* We need to treat lifetimes for temporary addresses
|
1489 |
|
|
* differently, according to
|
1490 |
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.3 (1);
|
1491 |
|
|
* we only update the lifetimes when they are in the maximum
|
1492 |
|
|
* intervals.
|
1493 |
|
|
*/
|
1494 |
|
|
if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
|
1495 |
|
|
u_int32_t maxvltime, maxpltime;
|
1496 |
|
|
|
1497 |
|
|
if (ip6_temp_valid_lifetime >
|
1498 |
|
|
(u_int32_t)(time_second - ifa6->ia6_createtime)) {
|
1499 |
|
|
maxvltime = ip6_temp_valid_lifetime -
|
1500 |
|
|
(time_second - ifa6->ia6_createtime);
|
1501 |
|
|
} else
|
1502 |
|
|
maxvltime = 0;
|
1503 |
|
|
if (ip6_temp_preferred_lifetime >
|
1504 |
|
|
(u_int32_t)((time_second - ifa6->ia6_createtime) +
|
1505 |
|
|
ip6_desync_factor)) {
|
1506 |
|
|
maxpltime = ip6_temp_preferred_lifetime -
|
1507 |
|
|
(time_second - ifa6->ia6_createtime) -
|
1508 |
|
|
ip6_desync_factor;
|
1509 |
|
|
} else
|
1510 |
|
|
maxpltime = 0;
|
1511 |
|
|
|
1512 |
|
|
if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
|
1513 |
|
|
lt6_tmp.ia6t_vltime > maxvltime) {
|
1514 |
|
|
lt6_tmp.ia6t_vltime = maxvltime;
|
1515 |
|
|
}
|
1516 |
|
|
if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
|
1517 |
|
|
lt6_tmp.ia6t_pltime > maxpltime) {
|
1518 |
|
|
lt6_tmp.ia6t_pltime = maxpltime;
|
1519 |
|
|
}
|
1520 |
|
|
}
|
1521 |
|
|
|
1522 |
|
|
ifa6->ia6_lifetime = lt6_tmp;
|
1523 |
|
|
ifa6->ia6_updatetime = time_second;
|
1524 |
|
|
}
|
1525 |
|
|
if (ia6_match == NULL && new->ndpr_vltime) {
|
1526 |
|
|
/*
|
1527 |
|
|
* No address matched and the valid lifetime is non-zero.
|
1528 |
|
|
* Create a new address.
|
1529 |
|
|
*/
|
1530 |
|
|
if ((ia6 = in6_ifadd(new)) != NULL) {
|
1531 |
|
|
/*
|
1532 |
|
|
* note that we should use pr (not new) for reference.
|
1533 |
|
|
*/
|
1534 |
|
|
pr->ndpr_refcnt++;
|
1535 |
|
|
ia6->ia6_ndpr = pr;
|
1536 |
|
|
|
1537 |
|
|
/*
|
1538 |
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00 3.3 (2).
|
1539 |
|
|
* When a new public address is created as described
|
1540 |
|
|
* in RFC2462, also create a new temporary address.
|
1541 |
|
|
*
|
1542 |
|
|
* draft-ietf-ipngwg-temp-addresses-v2-00 3.5.
|
1543 |
|
|
* When an interface connects to a new link, a new
|
1544 |
|
|
* randomized interface identifier should be generated
|
1545 |
|
|
* immediately together with a new set of temporary
|
1546 |
|
|
* addresses. Thus, we specifiy 1 as the 2nd arg of
|
1547 |
|
|
* in6_tmpifadd().
|
1548 |
|
|
*/
|
1549 |
|
|
if (ip6_use_tempaddr) {
|
1550 |
|
|
int e;
|
1551 |
|
|
if ((e = in6_tmpifadd(ia6, 1)) != 0) {
|
1552 |
|
|
nd6log((LOG_NOTICE, "prelist_update: "
|
1553 |
|
|
"failed to create a temporary "
|
1554 |
|
|
"address, errno=%d\n",
|
1555 |
|
|
e));
|
1556 |
|
|
}
|
1557 |
|
|
}
|
1558 |
|
|
|
1559 |
|
|
/*
|
1560 |
|
|
* A newly added address might affect the status
|
1561 |
|
|
* of other addresses, so we check and update it.
|
1562 |
|
|
* XXX: what if address duplication happens?
|
1563 |
|
|
*/
|
1564 |
|
|
pfxlist_onlink_check();
|
1565 |
|
|
} else {
|
1566 |
|
|
/* just set an error. do not bark here. */
|
1567 |
|
|
error = EADDRNOTAVAIL; /* XXX: might be unused. */
|
1568 |
|
|
}
|
1569 |
|
|
}
|
1570 |
|
|
|
1571 |
|
|
end:
|
1572 |
|
|
splx(s);
|
1573 |
|
|
return error;
|
1574 |
|
|
}
|
1575 |
|
|
|
1576 |
|
|
/*
|
1577 |
|
|
* A supplement function used in the on-link detection below;
|
1578 |
|
|
* detect if a given prefix has a (probably) reachable advertising router.
|
1579 |
|
|
* XXX: lengthy function name...
|
1580 |
|
|
*/
|
1581 |
|
|
static struct nd_pfxrouter *
|
1582 |
|
|
find_pfxlist_reachable_router(pr)
|
1583 |
|
|
struct nd_prefix *pr;
|
1584 |
|
|
{
|
1585 |
|
|
struct nd_pfxrouter *pfxrtr;
|
1586 |
|
|
struct rtentry *rt;
|
1587 |
|
|
struct llinfo_nd6 *ln;
|
1588 |
|
|
|
1589 |
|
|
for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
|
1590 |
|
|
pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
|
1591 |
|
|
if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
|
1592 |
|
|
pfxrtr->router->ifp)) &&
|
1593 |
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
1594 |
|
|
ND6_IS_LLINFO_PROBREACH(ln))
|
1595 |
|
|
break; /* found */
|
1596 |
|
|
}
|
1597 |
|
|
|
1598 |
|
|
return(pfxrtr);
|
1599 |
|
|
|
1600 |
|
|
}
|
1601 |
|
|
|
1602 |
|
|
/*
|
1603 |
|
|
* Check if each prefix in the prefix list has at least one available router
|
1604 |
|
|
* that advertised the prefix (a router is "available" if its neighbor cache
|
1605 |
|
|
* entry is reachable or probably reachable).
|
1606 |
|
|
* If the check fails, the prefix may be off-link, because, for example,
|
1607 |
|
|
* we have moved from the network but the lifetime of the prefix has not
|
1608 |
|
|
* expired yet. So we should not use the prefix if there is another prefix
|
1609 |
|
|
* that has an available router.
|
1610 |
|
|
* But, if there is no prefix that has an available router, we still regards
|
1611 |
|
|
* all the prefixes as on-link. This is because we can't tell if all the
|
1612 |
|
|
* routers are simply dead or if we really moved from the network and there
|
1613 |
|
|
* is no router around us.
|
1614 |
|
|
*/
|
1615 |
|
|
void
|
1616 |
|
|
pfxlist_onlink_check()
|
1617 |
|
|
{
|
1618 |
|
|
struct nd_prefix *pr;
|
1619 |
|
|
struct in6_ifaddr *ifa;
|
1620 |
|
|
|
1621 |
|
|
/*
|
1622 |
|
|
* Check if there is a prefix that has a reachable advertising
|
1623 |
|
|
* router.
|
1624 |
|
|
*/
|
1625 |
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
1626 |
|
|
if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
|
1627 |
|
|
break;
|
1628 |
|
|
}
|
1629 |
|
|
|
1630 |
|
|
if (pr != NULL || TAILQ_FIRST(&nd_defrouter) != NULL) {
|
1631 |
|
|
/*
|
1632 |
|
|
* There is at least one prefix that has a reachable router,
|
1633 |
|
|
* or at least a router which probably does not advertise
|
1634 |
|
|
* any prefixes. The latter would be the case when we move
|
1635 |
|
|
* to a new link where we have a router that does not provide
|
1636 |
|
|
* prefixes and we configure an address by hand.
|
1637 |
|
|
* Detach prefixes which have no reachable advertising
|
1638 |
|
|
* router, and attach other prefixes.
|
1639 |
|
|
*/
|
1640 |
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
1641 |
|
|
/* XXX: a link-local prefix should never be detached */
|
1642 |
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
1643 |
|
|
continue;
|
1644 |
|
|
|
1645 |
|
|
/*
|
1646 |
|
|
* we aren't interested in prefixes without the L bit
|
1647 |
|
|
* set.
|
1648 |
|
|
*/
|
1649 |
|
|
if (pr->ndpr_raf_onlink == 0)
|
1650 |
|
|
continue;
|
1651 |
|
|
|
1652 |
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
|
1653 |
|
|
find_pfxlist_reachable_router(pr) == NULL)
|
1654 |
|
|
pr->ndpr_stateflags |= NDPRF_DETACHED;
|
1655 |
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
1656 |
|
|
find_pfxlist_reachable_router(pr) != 0)
|
1657 |
|
|
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
1658 |
|
|
}
|
1659 |
|
|
} else {
|
1660 |
|
|
/* there is no prefix that has a reachable router */
|
1661 |
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
1662 |
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
1663 |
|
|
continue;
|
1664 |
|
|
|
1665 |
|
|
if (pr->ndpr_raf_onlink == 0)
|
1666 |
|
|
continue;
|
1667 |
|
|
|
1668 |
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
|
1669 |
|
|
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
1670 |
|
|
}
|
1671 |
|
|
}
|
1672 |
|
|
|
1673 |
|
|
/*
|
1674 |
|
|
* Remove each interface route associated with a (just) detached
|
1675 |
|
|
* prefix, and reinstall the interface route for a (just) attached
|
1676 |
|
|
* prefix. Note that all attempt of reinstallation does not
|
1677 |
|
|
* necessarily success, when a same prefix is shared among multiple
|
1678 |
|
|
* interfaces. Such cases will be handled in nd6_prefix_onlink,
|
1679 |
|
|
* so we don't have to care about them.
|
1680 |
|
|
*/
|
1681 |
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
1682 |
|
|
int e;
|
1683 |
|
|
|
1684 |
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
1685 |
|
|
continue;
|
1686 |
|
|
|
1687 |
|
|
if (pr->ndpr_raf_onlink == 0)
|
1688 |
|
|
continue;
|
1689 |
|
|
|
1690 |
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
1691 |
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
1692 |
|
|
if ((e = nd6_prefix_offlink(pr)) != 0) {
|
1693 |
|
|
nd6log((LOG_ERR,
|
1694 |
|
|
"pfxlist_onlink_check: failed to "
|
1695 |
|
|
"make %s/%d offlink, errno=%d\n",
|
1696 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1697 |
|
|
pr->ndpr_plen, e));
|
1698 |
|
|
}
|
1699 |
|
|
}
|
1700 |
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
|
1701 |
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
|
1702 |
|
|
pr->ndpr_raf_onlink) {
|
1703 |
|
|
if ((e = nd6_prefix_onlink(pr)) != 0) {
|
1704 |
|
|
nd6log((LOG_ERR,
|
1705 |
|
|
"pfxlist_onlink_check: failed to "
|
1706 |
|
|
"make %s/%d offlink, errno=%d\n",
|
1707 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1708 |
|
|
pr->ndpr_plen, e));
|
1709 |
|
|
}
|
1710 |
|
|
}
|
1711 |
|
|
}
|
1712 |
|
|
|
1713 |
|
|
/*
|
1714 |
|
|
* Changes on the prefix status might affect address status as well.
|
1715 |
|
|
* Make sure that all addresses derived from an attached prefix are
|
1716 |
|
|
* attached, and that all addresses derived from a detached prefix are
|
1717 |
|
|
* detached. Note, however, that a manually configured address should
|
1718 |
|
|
* always be attached.
|
1719 |
|
|
* The precise detection logic is same as the one for prefixes.
|
1720 |
|
|
*/
|
1721 |
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
1722 |
|
|
if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
|
1723 |
|
|
continue;
|
1724 |
|
|
|
1725 |
|
|
if (ifa->ia6_ndpr == NULL) {
|
1726 |
|
|
/*
|
1727 |
|
|
* This can happen when we first configure the address
|
1728 |
|
|
* (i.e. the address exists, but the prefix does not).
|
1729 |
|
|
* XXX: complicated relationships...
|
1730 |
|
|
*/
|
1731 |
|
|
continue;
|
1732 |
|
|
}
|
1733 |
|
|
|
1734 |
|
|
if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
|
1735 |
|
|
break;
|
1736 |
|
|
}
|
1737 |
|
|
if (ifa) {
|
1738 |
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
1739 |
|
|
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
1740 |
|
|
continue;
|
1741 |
|
|
|
1742 |
|
|
if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
|
1743 |
|
|
continue;
|
1744 |
|
|
|
1745 |
|
|
if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
|
1746 |
|
|
ifa->ia6_flags &= ~IN6_IFF_DETACHED;
|
1747 |
|
|
else
|
1748 |
|
|
ifa->ia6_flags |= IN6_IFF_DETACHED;
|
1749 |
|
|
}
|
1750 |
|
|
}
|
1751 |
|
|
else {
|
1752 |
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
1753 |
|
|
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
1754 |
|
|
continue;
|
1755 |
|
|
|
1756 |
|
|
ifa->ia6_flags &= ~IN6_IFF_DETACHED;
|
1757 |
|
|
}
|
1758 |
|
|
}
|
1759 |
|
|
|
1760 |
|
|
#ifdef MIP6
|
1761 |
|
|
if (MIP6_IS_MN) {
|
1762 |
|
|
int coa_changed = 0;
|
1763 |
|
|
|
1764 |
|
|
hif_save_location();
|
1765 |
|
|
coa_changed = mip6_select_coa2();
|
1766 |
|
|
(void)mip6_process_pfxlist_status_change(&hif_coa);
|
1767 |
|
|
if (coa_changed == 1)
|
1768 |
|
|
mip6_process_movement();
|
1769 |
|
|
else
|
1770 |
|
|
hif_restore_location();
|
1771 |
|
|
}
|
1772 |
|
|
#endif /* MIP6 */
|
1773 |
|
|
}
|
1774 |
|
|
|
1775 |
|
|
int
|
1776 |
|
|
nd6_prefix_onlink(pr)
|
1777 |
|
|
struct nd_prefix *pr;
|
1778 |
|
|
{
|
1779 |
|
|
struct ifaddr *ifa;
|
1780 |
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
1781 |
|
|
struct sockaddr_in6 mask6;
|
1782 |
|
|
struct nd_prefix *opr;
|
1783 |
|
|
u_long rtflags;
|
1784 |
|
|
int error = 0;
|
1785 |
|
|
struct rtentry *rt = NULL;
|
1786 |
|
|
|
1787 |
|
|
/* sanity check */
|
1788 |
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
1789 |
|
|
nd6log((LOG_ERR,
|
1790 |
|
|
"nd6_prefix_onlink: %s/%d is already on-link\n",
|
1791 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen);
|
1792 |
|
|
return(EEXIST));
|
1793 |
|
|
}
|
1794 |
|
|
|
1795 |
|
|
/*
|
1796 |
|
|
* Add the interface route associated with the prefix. Before
|
1797 |
|
|
* installing the route, check if there's the same prefix on another
|
1798 |
|
|
* interface, and the prefix has already installed the interface route.
|
1799 |
|
|
* Although such a configuration is expected to be rare, we explicitly
|
1800 |
|
|
* allow it.
|
1801 |
|
|
*/
|
1802 |
|
|
for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
|
1803 |
|
|
if (opr == pr)
|
1804 |
|
|
continue;
|
1805 |
|
|
|
1806 |
|
|
if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
|
1807 |
|
|
continue;
|
1808 |
|
|
|
1809 |
|
|
if (opr->ndpr_plen == pr->ndpr_plen &&
|
1810 |
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
1811 |
|
|
&opr->ndpr_prefix.sin6_addr,
|
1812 |
|
|
pr->ndpr_plen))
|
1813 |
|
|
return(0);
|
1814 |
|
|
}
|
1815 |
|
|
|
1816 |
|
|
/*
|
1817 |
|
|
* We prefer link-local addresses as the associated interface address.
|
1818 |
|
|
*/
|
1819 |
|
|
/* search for a link-local addr */
|
1820 |
|
|
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
|
1821 |
|
|
IN6_IFF_NOTREADY|
|
1822 |
|
|
IN6_IFF_ANYCAST);
|
1823 |
|
|
if (ifa == NULL) {
|
1824 |
|
|
/* XXX: freebsd does not have ifa_ifwithaf */
|
1825 |
|
|
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
|
1826 |
|
|
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
|
1827 |
|
|
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
|
1828 |
|
|
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
|
1829 |
|
|
#else
|
1830 |
|
|
for (ifa = ifp->if_addrlist.tqh_first;
|
1831 |
|
|
ifa;
|
1832 |
|
|
ifa = ifa->ifa_list.tqe_next)
|
1833 |
|
|
#endif
|
1834 |
|
|
{
|
1835 |
|
|
if (ifa->ifa_addr->sa_family == AF_INET6)
|
1836 |
|
|
break;
|
1837 |
|
|
}
|
1838 |
|
|
/* should we care about ia6_flags? */
|
1839 |
|
|
}
|
1840 |
|
|
if (ifa == NULL) {
|
1841 |
|
|
/*
|
1842 |
|
|
* This can still happen, when, for example, we receive an RA
|
1843 |
|
|
* containing a prefix with the L bit set and the A bit clear,
|
1844 |
|
|
* after removing all IPv6 addresses on the receiving
|
1845 |
|
|
* interface. This should, of course, be rare though.
|
1846 |
|
|
*/
|
1847 |
|
|
nd6log((LOG_NOTICE,
|
1848 |
|
|
"nd6_prefix_onlink: failed to find any ifaddr"
|
1849 |
|
|
" to add route for a prefix(%s/%d) on %s\n",
|
1850 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1851 |
|
|
pr->ndpr_plen, if_name(ifp)));
|
1852 |
|
|
return(0);
|
1853 |
|
|
}
|
1854 |
|
|
|
1855 |
|
|
/*
|
1856 |
|
|
* in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
|
1857 |
|
|
* ifa->ifa_rtrequest = nd6_rtrequest;
|
1858 |
|
|
*/
|
1859 |
|
|
bzero(&mask6, sizeof(mask6));
|
1860 |
|
|
mask6.sin6_len = sizeof(mask6);
|
1861 |
|
|
mask6.sin6_addr = pr->ndpr_mask;
|
1862 |
|
|
/* rtrequest() will probably set RTF_UP, but we're not sure. */
|
1863 |
|
|
rtflags = ifa->ifa_flags | RTF_UP;
|
1864 |
|
|
if (nd6_need_cache(ifp)) {
|
1865 |
|
|
/* explicitly set in case ifa_flags does not set the flag. */
|
1866 |
|
|
rtflags |= RTF_CLONING;
|
1867 |
|
|
} else {
|
1868 |
|
|
/*
|
1869 |
|
|
* explicitly clear the cloning bit in case ifa_flags sets it.
|
1870 |
|
|
*/
|
1871 |
|
|
rtflags &= ~RTF_CLONING;
|
1872 |
|
|
}
|
1873 |
|
|
error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
|
1874 |
|
|
ifa->ifa_addr, (struct sockaddr *)&mask6,
|
1875 |
|
|
rtflags, &rt);
|
1876 |
|
|
if (error == 0) {
|
1877 |
|
|
if (rt != NULL) /* this should be non NULL, though */
|
1878 |
|
|
nd6_rtmsg(RTM_ADD, rt);
|
1879 |
|
|
pr->ndpr_stateflags |= NDPRF_ONLINK;
|
1880 |
|
|
}
|
1881 |
|
|
else {
|
1882 |
|
|
nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
|
1883 |
|
|
" prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
|
1884 |
|
|
"errno = %d\n",
|
1885 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
1886 |
|
|
pr->ndpr_plen, if_name(ifp),
|
1887 |
|
|
ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
|
1888 |
|
|
ip6_sprintf(&mask6.sin6_addr), rtflags, error));
|
1889 |
|
|
}
|
1890 |
|
|
|
1891 |
|
|
if (rt != NULL)
|
1892 |
|
|
rt->rt_refcnt--;
|
1893 |
|
|
|
1894 |
|
|
return(error);
|
1895 |
|
|
}
|
1896 |
|
|
|
1897 |
|
|
int
|
1898 |
|
|
nd6_prefix_offlink(pr)
|
1899 |
|
|
struct nd_prefix *pr;
|
1900 |
|
|
{
|
1901 |
|
|
int error = 0;
|
1902 |
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
1903 |
|
|
struct nd_prefix *opr;
|
1904 |
|
|
struct sockaddr_in6 sa6, mask6;
|
1905 |
|
|
struct rtentry *rt = NULL;
|
1906 |
|
|
|
1907 |
|
|
/* sanity check */
|
1908 |
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
1909 |
|
|
nd6log((LOG_ERR,
|
1910 |
|
|
"nd6_prefix_offlink: %s/%d is already off-link\n",
|
1911 |
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
|
1912 |
|
|
return(EEXIST);
|
1913 |
|
|
}
|
1914 |
|
|
|
1915 |
|
|
bzero(&sa6, sizeof(sa6));
|
1916 |
|
|
sa6.sin6_family = AF_INET6;
|
1917 |
|
|
sa6.sin6_len = sizeof(sa6);
|
1918 |
|
|
bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
|
1919 |
|
|
sizeof(struct in6_addr));
|
1920 |
|
|
bzero(&mask6, sizeof(mask6));
|
1921 |
|
|
mask6.sin6_family = AF_INET6;
|
1922 |
|
|
mask6.sin6_len = sizeof(sa6);
|
1923 |
|
|
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
|
1924 |
|
|
error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
|
1925 |
|
|
(struct sockaddr *)&mask6, 0, &rt);
|
1926 |
|
|
if (error == 0) {
|
1927 |
|
|
pr->ndpr_stateflags &= ~NDPRF_ONLINK;
|
1928 |
|
|
|
1929 |
|
|
/* report the route deletion to the routing socket. */
|
1930 |
|
|
if (rt != NULL)
|
1931 |
|
|
nd6_rtmsg(RTM_DELETE, rt);
|
1932 |
|
|
|
1933 |
|
|
/*
|
1934 |
|
|
* There might be the same prefix on another interface,
|
1935 |
|
|
* the prefix which could not be on-link just because we have
|
1936 |
|
|
* the interface route (see comments in nd6_prefix_onlink).
|
1937 |
|
|
* If there's one, try to make the prefix on-link on the
|
1938 |
|
|
* interface.
|
1939 |
|
|
*/
|
1940 |
|
|
for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
|
1941 |
|
|
if (opr == pr)
|
1942 |
|
|
continue;
|
1943 |
|
|
|
1944 |
|
|
if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
|
1945 |
|
|
continue;
|
1946 |
|
|
|
1947 |
|
|
/*
|
1948 |
|
|
* KAME specific: detached prefixes should not be
|
1949 |
|
|
* on-link.
|
1950 |
|
|
*/
|
1951 |
|
|
if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
|
1952 |
|
|
continue;
|
1953 |
|
|
|
1954 |
|
|
if (opr->ndpr_plen == pr->ndpr_plen &&
|
1955 |
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
1956 |
|
|
&opr->ndpr_prefix.sin6_addr,
|
1957 |
|
|
pr->ndpr_plen)) {
|
1958 |
|
|
int e;
|
1959 |
|
|
|
1960 |
|
|
if ((e = nd6_prefix_onlink(opr)) != 0) {
|
1961 |
|
|
nd6log((LOG_ERR,
|
1962 |
|
|
"nd6_prefix_offlink: failed to "
|
1963 |
|
|
"recover a prefix %s/%d from %s "
|
1964 |
|
|
"to %s (errno = %d)\n",
|
1965 |
|
|
ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
|
1966 |
|
|
opr->ndpr_plen, if_name(ifp),
|
1967 |
|
|
if_name(opr->ndpr_ifp), e));
|
1968 |
|
|
}
|
1969 |
|
|
}
|
1970 |
|
|
}
|
1971 |
|
|
}
|
1972 |
|
|
else {
|
1973 |
|
|
/* XXX: can we still set the NDPRF_ONLINK flag? */
|
1974 |
|
|
nd6log((LOG_ERR,
|
1975 |
|
|
"nd6_prefix_offlink: failed to delete route: "
|
1976 |
|
|
"%s/%d on %s (errno = %d)\n",
|
1977 |
|
|
ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
|
1978 |
|
|
error));
|
1979 |
|
|
}
|
1980 |
|
|
|
1981 |
|
|
if (rt != NULL) {
|
1982 |
|
|
if (rt->rt_refcnt <= 0) {
|
1983 |
|
|
/* XXX: we should free the entry ourselves. */
|
1984 |
|
|
rt->rt_refcnt++;
|
1985 |
|
|
rtfree(rt);
|
1986 |
|
|
}
|
1987 |
|
|
}
|
1988 |
|
|
|
1989 |
|
|
return(error);
|
1990 |
|
|
}
|
1991 |
|
|
|
1992 |
|
|
static struct in6_ifaddr *
|
1993 |
|
|
in6_ifadd(pr)
|
1994 |
|
|
struct nd_prefix *pr;
|
1995 |
|
|
{
|
1996 |
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
1997 |
|
|
struct ifaddr *ifa;
|
1998 |
|
|
struct in6_aliasreq ifra;
|
1999 |
|
|
struct in6_ifaddr *ia, *ib;
|
2000 |
|
|
int error, plen0;
|
2001 |
|
|
struct in6_addr mask;
|
2002 |
|
|
int prefixlen = pr->ndpr_plen;
|
2003 |
|
|
|
2004 |
|
|
in6_prefixlen2mask(&mask, prefixlen);
|
2005 |
|
|
|
2006 |
|
|
/*
|
2007 |
|
|
* find a link-local address (will be interface ID).
|
2008 |
|
|
* Is it really mandatory? Theoretically, a global or a site-local
|
2009 |
|
|
* address can be configured without a link-local address, if we
|
2010 |
|
|
* have a unique interface identifier...
|
2011 |
|
|
*
|
2012 |
|
|
* it is not mandatory to have a link-local address, we can generate
|
2013 |
|
|
* interface identifier on the fly. we do this because:
|
2014 |
|
|
* (1) it should be the easiest way to find interface identifier.
|
2015 |
|
|
* (2) RFC2462 5.4 suggesting the use of the same interface identifier
|
2016 |
|
|
* for multiple addresses on a single interface, and possible shortcut
|
2017 |
|
|
* of DAD. we omitted DAD for this reason in the past.
|
2018 |
|
|
* (3) a user can prevent autoconfiguration of global address
|
2019 |
|
|
* by removing link-local address by hand (this is partly because we
|
2020 |
|
|
* don't have other way to control the use of IPv6 on a interface.
|
2021 |
|
|
* this has been our design choice - cf. NRL's "ifconfig auto").
|
2022 |
|
|
* (4) it is easier to manage when an interface has addresses
|
2023 |
|
|
* with the same interface identifier, than to have multiple addresses
|
2024 |
|
|
* with different interface identifiers.
|
2025 |
|
|
*/
|
2026 |
|
|
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
|
2027 |
|
|
if (ifa)
|
2028 |
|
|
ib = (struct in6_ifaddr *)ifa;
|
2029 |
|
|
else
|
2030 |
|
|
return NULL;
|
2031 |
|
|
|
2032 |
|
|
#if 0 /* don't care link local addr state, and always do DAD */
|
2033 |
|
|
/* if link-local address is not eligible, do not autoconfigure. */
|
2034 |
|
|
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
|
2035 |
|
|
printf("in6_ifadd: link-local address not ready\n");
|
2036 |
|
|
return NULL;
|
2037 |
|
|
}
|
2038 |
|
|
#endif
|
2039 |
|
|
|
2040 |
|
|
/* prefixlen + ifidlen must be equal to 128 */
|
2041 |
|
|
plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
|
2042 |
|
|
if (prefixlen != plen0) {
|
2043 |
|
|
nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
|
2044 |
|
|
"(prefix=%d ifid=%d)\n",
|
2045 |
|
|
if_name(ifp), prefixlen, 128 - plen0));
|
2046 |
|
|
return NULL;
|
2047 |
|
|
}
|
2048 |
|
|
|
2049 |
|
|
/* make ifaddr */
|
2050 |
|
|
|
2051 |
|
|
bzero(&ifra, sizeof(ifra));
|
2052 |
|
|
/*
|
2053 |
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
2054 |
|
|
* for safety.
|
2055 |
|
|
*/
|
2056 |
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
2057 |
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
2058 |
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
2059 |
|
|
/* prefix */
|
2060 |
|
|
bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
|
2061 |
|
|
sizeof(ifra.ifra_addr.sin6_addr));
|
2062 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
|
2063 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
|
2064 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
|
2065 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
|
2066 |
|
|
|
2067 |
|
|
/* interface ID */
|
2068 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
|
2069 |
|
|
(ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
|
2070 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
|
2071 |
|
|
(ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
|
2072 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
|
2073 |
|
|
(ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
|
2074 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
|
2075 |
|
|
(ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
|
2076 |
|
|
|
2077 |
|
|
/* new prefix mask. */
|
2078 |
|
|
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
2079 |
|
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
2080 |
|
|
bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
|
2081 |
|
|
sizeof(ifra.ifra_prefixmask.sin6_addr));
|
2082 |
|
|
|
2083 |
|
|
/*
|
2084 |
|
|
* lifetime.
|
2085 |
|
|
* XXX: in6_init_address_ltimes would override these values later.
|
2086 |
|
|
* We should reconsider this logic.
|
2087 |
|
|
*/
|
2088 |
|
|
ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
|
2089 |
|
|
ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
|
2090 |
|
|
|
2091 |
|
|
/* XXX: scope zone ID? */
|
2092 |
|
|
|
2093 |
|
|
ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
|
2094 |
|
|
|
2095 |
|
|
/* allocate ifaddr structure, link into chain, etc. */
|
2096 |
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
|
2097 |
|
|
nd6log((LOG_ERR,
|
2098 |
|
|
"in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
|
2099 |
|
|
ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
|
2100 |
|
|
error));
|
2101 |
|
|
return(NULL); /* ifaddr must not have been allocated. */
|
2102 |
|
|
}
|
2103 |
|
|
|
2104 |
|
|
ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
|
2105 |
|
|
|
2106 |
|
|
return(ia); /* this is always non-NULL */
|
2107 |
|
|
}
|
2108 |
|
|
|
2109 |
|
|
int
|
2110 |
|
|
in6_tmpifadd(ia0, forcegen)
|
2111 |
|
|
const struct in6_ifaddr *ia0; /* corresponding public address */
|
2112 |
|
|
int forcegen;
|
2113 |
|
|
{
|
2114 |
|
|
struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
|
2115 |
|
|
struct in6_ifaddr *newia, *ia;
|
2116 |
|
|
struct in6_aliasreq ifra;
|
2117 |
|
|
int i, error;
|
2118 |
|
|
int trylimit = 3; /* XXX: adhoc value */
|
2119 |
|
|
u_int32_t randid[2];
|
2120 |
|
|
u_int32_t vltime0, pltime0;
|
2121 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
2122 |
|
|
time_t time_second = (time_t)time.tv_sec;
|
2123 |
|
|
#endif
|
2124 |
|
|
|
2125 |
|
|
bzero(&ifra, sizeof(ifra));
|
2126 |
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
2127 |
|
|
ifra.ifra_addr = ia0->ia_addr;
|
2128 |
|
|
/* copy prefix mask */
|
2129 |
|
|
ifra.ifra_prefixmask = ia0->ia_prefixmask;
|
2130 |
|
|
/* clear the old IFID */
|
2131 |
|
|
for (i = 0; i < 4; i++) {
|
2132 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[i]
|
2133 |
|
|
&= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
|
2134 |
|
|
}
|
2135 |
|
|
|
2136 |
|
|
again:
|
2137 |
|
|
if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
|
2138 |
|
|
(const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8],
|
2139 |
|
|
forcegen)) {
|
2140 |
|
|
nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
|
2141 |
|
|
"random IFID\n"));
|
2142 |
|
|
return(EINVAL);
|
2143 |
|
|
}
|
2144 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2]
|
2145 |
|
|
|= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
|
2146 |
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3]
|
2147 |
|
|
|= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
|
2148 |
|
|
|
2149 |
|
|
/*
|
2150 |
|
|
* in6_get_tmpifid() quite likely provided a unique interface ID.
|
2151 |
|
|
* However, we may still have a chance to see collision, because
|
2152 |
|
|
* there may be a time lag between generation of the ID and generation
|
2153 |
|
|
* of the address. So, we'll do one more sanity check.
|
2154 |
|
|
*/
|
2155 |
|
|
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
|
2156 |
|
|
if (SA6_ARE_ADDR_EQUAL(&ia->ia_addr,
|
2157 |
|
|
&ifra.ifra_addr)) {
|
2158 |
|
|
if (trylimit-- == 0) {
|
2159 |
|
|
/*
|
2160 |
|
|
* Give up. Something strange should have
|
2161 |
|
|
* happened.
|
2162 |
|
|
*/
|
2163 |
|
|
nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
|
2164 |
|
|
"find a unique random IFID\n"));
|
2165 |
|
|
return(EEXIST);
|
2166 |
|
|
}
|
2167 |
|
|
forcegen = 1;
|
2168 |
|
|
goto again;
|
2169 |
|
|
}
|
2170 |
|
|
}
|
2171 |
|
|
|
2172 |
|
|
/*
|
2173 |
|
|
* The Valid Lifetime is the lower of the Valid Lifetime of the
|
2174 |
|
|
* public address or TEMP_VALID_LIFETIME.
|
2175 |
|
|
* The Preferred Lifetime is the lower of the Preferred Lifetime
|
2176 |
|
|
* of the public address or TEMP_PREFERRED_LIFETIME -
|
2177 |
|
|
* DESYNC_FACTOR.
|
2178 |
|
|
*/
|
2179 |
|
|
if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
|
2180 |
|
|
vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
|
2181 |
|
|
(ia0->ia6_lifetime.ia6t_vltime -
|
2182 |
|
|
(time_second - ia0->ia6_updatetime));
|
2183 |
|
|
if (vltime0 > ip6_temp_valid_lifetime)
|
2184 |
|
|
vltime0 = ip6_temp_valid_lifetime;
|
2185 |
|
|
} else
|
2186 |
|
|
vltime0 = ip6_temp_valid_lifetime;
|
2187 |
|
|
if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
|
2188 |
|
|
pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
|
2189 |
|
|
(ia0->ia6_lifetime.ia6t_pltime -
|
2190 |
|
|
(time_second - ia0->ia6_updatetime));
|
2191 |
|
|
if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
|
2192 |
|
|
pltime0 = ip6_temp_preferred_lifetime -
|
2193 |
|
|
ip6_desync_factor;
|
2194 |
|
|
}
|
2195 |
|
|
} else
|
2196 |
|
|
pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
|
2197 |
|
|
ifra.ifra_lifetime.ia6t_vltime = vltime0;
|
2198 |
|
|
ifra.ifra_lifetime.ia6t_pltime = pltime0;
|
2199 |
|
|
|
2200 |
|
|
/*
|
2201 |
|
|
* A temporary address is created only if this calculated Preferred
|
2202 |
|
|
* Lifetime is greater than REGEN_ADVANCE time units.
|
2203 |
|
|
*/
|
2204 |
|
|
if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
|
2205 |
|
|
return(0);
|
2206 |
|
|
|
2207 |
|
|
/* XXX: scope zone ID? */
|
2208 |
|
|
|
2209 |
|
|
ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
|
2210 |
|
|
|
2211 |
|
|
/* allocate ifaddr structure, link into chain, etc. */
|
2212 |
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0)
|
2213 |
|
|
return(error);
|
2214 |
|
|
|
2215 |
|
|
newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
|
2216 |
|
|
if (newia == NULL) { /* XXX: can it happen? */
|
2217 |
|
|
nd6log((LOG_ERR,
|
2218 |
|
|
"in6_tmpifadd: ifa update succeeded, but we got "
|
2219 |
|
|
"no ifaddr\n"));
|
2220 |
|
|
return(EINVAL); /* XXX */
|
2221 |
|
|
}
|
2222 |
|
|
newia->ia6_ndpr = ia0->ia6_ndpr;
|
2223 |
|
|
newia->ia6_ndpr->ndpr_refcnt++;
|
2224 |
|
|
|
2225 |
|
|
/*
|
2226 |
|
|
* A newly added address might affect the status of other addresses.
|
2227 |
|
|
* XXX: when the temporary address is generated with a new public
|
2228 |
|
|
* address, the onlink check is redundant. However, it would be safe
|
2229 |
|
|
* to do the check explicitly everywhere a new address is generated,
|
2230 |
|
|
* and, in fact, we surely need the check when we create a new
|
2231 |
|
|
* temporary address due to deprecation of an old temporary address.
|
2232 |
|
|
*/
|
2233 |
|
|
pfxlist_onlink_check();
|
2234 |
|
|
|
2235 |
|
|
return(0);
|
2236 |
|
|
}
|
2237 |
|
|
|
2238 |
|
|
int
|
2239 |
|
|
in6_init_prefix_ltimes(struct nd_prefix *ndpr)
|
2240 |
|
|
{
|
2241 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
2242 |
|
|
long time_second = time.tv_sec;
|
2243 |
|
|
#endif
|
2244 |
|
|
|
2245 |
|
|
/* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */
|
2246 |
|
|
if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
|
2247 |
|
|
nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
|
2248 |
|
|
"(%d) is greater than valid lifetime(%d)\n",
|
2249 |
|
|
(u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
|
2250 |
|
|
return (EINVAL);
|
2251 |
|
|
}
|
2252 |
|
|
if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
|
2253 |
|
|
ndpr->ndpr_preferred = 0;
|
2254 |
|
|
else
|
2255 |
|
|
ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
|
2256 |
|
|
if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
|
2257 |
|
|
ndpr->ndpr_expire = 0;
|
2258 |
|
|
else
|
2259 |
|
|
ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
|
2260 |
|
|
|
2261 |
|
|
return 0;
|
2262 |
|
|
}
|
2263 |
|
|
|
2264 |
|
|
static void
|
2265 |
|
|
in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
|
2266 |
|
|
{
|
2267 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
2268 |
|
|
long time_second = time.tv_sec;
|
2269 |
|
|
#endif
|
2270 |
|
|
|
2271 |
|
|
/* Valid lifetime must not be updated unless explicitly specified. */
|
2272 |
|
|
/* init ia6t_expire */
|
2273 |
|
|
if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
|
2274 |
|
|
lt6->ia6t_expire = 0;
|
2275 |
|
|
else {
|
2276 |
|
|
lt6->ia6t_expire = time_second;
|
2277 |
|
|
lt6->ia6t_expire += lt6->ia6t_vltime;
|
2278 |
|
|
}
|
2279 |
|
|
|
2280 |
|
|
/* init ia6t_preferred */
|
2281 |
|
|
if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
|
2282 |
|
|
lt6->ia6t_preferred = 0;
|
2283 |
|
|
else {
|
2284 |
|
|
lt6->ia6t_preferred = time_second;
|
2285 |
|
|
lt6->ia6t_preferred += lt6->ia6t_pltime;
|
2286 |
|
|
}
|
2287 |
|
|
}
|
2288 |
|
|
|
2289 |
|
|
/*
|
2290 |
|
|
* Delete all the routing table entries that use the specified gateway.
|
2291 |
|
|
* XXX: this function causes search through all entries of routing table, so
|
2292 |
|
|
* it shouldn't be called when acting as a router.
|
2293 |
|
|
*/
|
2294 |
|
|
void
|
2295 |
|
|
rt6_flush(gateway, ifp)
|
2296 |
|
|
struct in6_addr *gateway;
|
2297 |
|
|
struct ifnet *ifp;
|
2298 |
|
|
{
|
2299 |
|
|
struct radix_node_head *rnh = rt_tables[AF_INET6];
|
2300 |
|
|
#ifdef __NetBSD__
|
2301 |
|
|
int s = splsoftnet();
|
2302 |
|
|
#else
|
2303 |
|
|
int s = splnet();
|
2304 |
|
|
#endif
|
2305 |
|
|
|
2306 |
|
|
/* We'll care only link-local addresses */
|
2307 |
|
|
if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
|
2308 |
|
|
splx(s);
|
2309 |
|
|
return;
|
2310 |
|
|
}
|
2311 |
|
|
/* XXX: hack for KAME's link-local address kludge */
|
2312 |
|
|
gateway->s6_addr16[1] = htons(ifp->if_index);
|
2313 |
|
|
|
2314 |
|
|
rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
|
2315 |
|
|
splx(s);
|
2316 |
|
|
}
|
2317 |
|
|
|
2318 |
|
|
static int
|
2319 |
|
|
rt6_deleteroute(rn, arg)
|
2320 |
|
|
struct radix_node *rn;
|
2321 |
|
|
void *arg;
|
2322 |
|
|
{
|
2323 |
|
|
#define SIN6(s) ((struct sockaddr_in6 *)s)
|
2324 |
|
|
struct rtentry *rt = (struct rtentry *)rn;
|
2325 |
|
|
struct in6_addr *gate = (struct in6_addr *)arg;
|
2326 |
|
|
|
2327 |
|
|
if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
|
2328 |
|
|
return(0);
|
2329 |
|
|
|
2330 |
|
|
if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
|
2331 |
|
|
return(0);
|
2332 |
|
|
|
2333 |
|
|
/*
|
2334 |
|
|
* Do not delete a static route.
|
2335 |
|
|
* XXX: this seems to be a bit ad-hoc. Should we consider the
|
2336 |
|
|
* 'cloned' bit instead?
|
2337 |
|
|
*/
|
2338 |
|
|
if ((rt->rt_flags & RTF_STATIC) != 0)
|
2339 |
|
|
return(0);
|
2340 |
|
|
|
2341 |
|
|
/*
|
2342 |
|
|
* We delete only host route. This means, in particular, we don't
|
2343 |
|
|
* delete default route.
|
2344 |
|
|
*/
|
2345 |
|
|
if ((rt->rt_flags & RTF_HOST) == 0)
|
2346 |
|
|
return(0);
|
2347 |
|
|
|
2348 |
|
|
return(rtrequest(RTM_DELETE, rt_key(rt),
|
2349 |
|
|
rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
|
2350 |
|
|
#undef SIN6
|
2351 |
|
|
}
|
2352 |
|
|
|
2353 |
|
|
int
|
2354 |
|
|
nd6_setdefaultiface(ifindex)
|
2355 |
|
|
int ifindex;
|
2356 |
|
|
{
|
2357 |
|
|
int error = 0;
|
2358 |
|
|
|
2359 |
|
|
if (ifindex < 0 || if_index < ifindex)
|
2360 |
|
|
return(EINVAL);
|
2361 |
|
|
|
2362 |
|
|
if (nd6_defifindex != ifindex) {
|
2363 |
|
|
nd6_defifindex = ifindex;
|
2364 |
|
|
if (nd6_defifindex > 0) {
|
2365 |
|
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
|
2366 |
|
|
nd6_defifp = ifnet_byindex[nd6_defifindex];
|
2367 |
|
|
#else
|
2368 |
|
|
nd6_defifp = ifindex2ifnet[nd6_defifindex];
|
2369 |
|
|
#endif
|
2370 |
|
|
} else
|
2371 |
|
|
nd6_defifp = NULL;
|
2372 |
|
|
|
2373 |
|
|
/*
|
2374 |
|
|
* Rescan default router list, refresh default route(s).
|
2375 |
|
|
*/
|
2376 |
|
|
defrouter_select();
|
2377 |
|
|
|
2378 |
|
|
/*
|
2379 |
|
|
* Our current implementation assumes one-to-one maping between
|
2380 |
|
|
* interfaces and links, so it would be natural to use the
|
2381 |
|
|
* default interface as the default link.
|
2382 |
|
|
*/
|
2383 |
|
|
scope6_setdefault(nd6_defifp);
|
2384 |
|
|
}
|
2385 |
|
|
|
2386 |
|
|
return(error);
|
2387 |
|
|
}
|