Deleted Added
full compact
nd6_rtr.c (53541) nd6_rtr.c (54263)
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/netinet6/nd6_rtr.c 53541 1999-11-22 02:45:11Z shin $
29 * $FreeBSD: head/sys/netinet6/nd6_rtr.c 54263 1999-12-07 17:39:16Z shin $
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/mbuf.h>
36#include <sys/socket.h>
37#include <sys/sockio.h>
38#include <sys/time.h>
39#include <sys/kernel.h>
40#include <sys/errno.h>
41#include <sys/syslog.h>
42
43#include <net/if.h>
44#include <net/if_types.h>
45#include <net/if_dl.h>
46#include <net/route.h>
47#include <net/radix.h>
48
49#include <netinet/in.h>
50#include <netinet6/in6_var.h>
51#include <netinet6/ip6.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/nd6.h>
54#include <netinet6/icmp6.h>
55
56#include <net/net_osdep.h>
57
58#define SDL(s) ((struct sockaddr_dl *)s)
59
60static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
61static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *));
62static struct nd_prefix *prefix_lookup __P((struct nd_prefix *));
63static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *,
64 struct in6_addr *, int));
65static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
66 struct nd_defrouter *));
67static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
68static void pfxrtr_del __P((struct nd_pfxrouter *));
69static void pfxlist_onlink_check __P((void));
70static void nd6_detach_prefix __P((struct nd_prefix *));
71static void nd6_attach_prefix __P((struct nd_prefix *));
72
73static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
74 struct in6_addrlifetime *lt6));
75
76static int rt6_deleteroute __P((struct radix_node *, void *));
77
78extern int nd6_recalc_reachtm_interval;
79
80/*
81 * Receive Router Solicitation Message - just for routers.
82 * Router solicitation/advertisement is mostly managed by userland program
83 * (rtadvd) so here we have no function like nd6_ra_output().
84 *
85 * Based on RFC 2461
86 */
87void
88nd6_rs_input(m, off, icmp6len)
89 struct mbuf *m;
90 int off, icmp6len;
91{
92 struct ifnet *ifp = m->m_pkthdr.rcvif;
93 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
94 struct nd_router_solicit *nd_rs
95 = (struct nd_router_solicit *)((caddr_t)ip6 + off);
96 struct in6_addr saddr6 = ip6->ip6_src;
97 char *lladdr = NULL;
98 int lladdrlen = 0;
99 union nd_opts ndopts;
100
101 /* If I'm not a router, ignore it. */
102 if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
103 return;
104
105 /* Sanity checks */
106 if (ip6->ip6_hlim != 255) {
107 log(LOG_ERR,
108 "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
109 return;
110 }
111
112 /*
113 * Don't update the neighbor cache, if src = ::.
114 * This indicates that the src has no IP address assigned yet.
115 */
116 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
117 return;
118
119 icmp6len -= sizeof(*nd_rs);
120 nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
121 if (nd6_options(&ndopts) < 0) {
122 log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
123 return;
124 }
125
126 if (ndopts.nd_opts_src_lladdr) {
127 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
128 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
129 }
130
131 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
132 log(LOG_INFO,
133 "nd6_rs_input: lladdrlen mismatch for %s "
134 "(if %d, RS packet %d)\n",
135 ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
136 }
137
138 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
139}
140
141/*
142 * Receive Router Advertisement Message.
143 *
144 * Based on RFC 2461
145 * TODO: on-link bit on prefix information
146 * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
147 */
148void
149nd6_ra_input(m, off, icmp6len)
150 struct mbuf *m;
151 int off, icmp6len;
152{
153 struct ifnet *ifp = m->m_pkthdr.rcvif;
154 struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
155 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
156 struct nd_router_advert *nd_ra =
157 (struct nd_router_advert *)((caddr_t)ip6 + off);
158 struct in6_addr saddr6 = ip6->ip6_src;
159 union nd_opts ndopts;
160 struct nd_defrouter *dr;
161
162 if (ip6_accept_rtadv == 0)
163 return;
164
165 if (ip6->ip6_hlim != 255) {
166 log(LOG_ERR,
167 "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
168 return;
169 }
170
171 if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
172 log(LOG_ERR,
173 "nd6_ra_input: src %s is not link-local\n",
174 ip6_sprintf(&saddr6));
175 return;
176 }
177
178 icmp6len -= sizeof(*nd_ra);
179 nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
180 if (nd6_options(&ndopts) < 0) {
181 log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
182 return;
183 }
184
185 {
186 struct nd_defrouter dr0;
187 u_int32_t advreachable = nd_ra->nd_ra_reachable;
188
189 dr0.rtaddr = saddr6;
190 dr0.flags = nd_ra->nd_ra_flags_reserved;
191 dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
192 dr0.expire = time_second + dr0.rtlifetime;
193 dr0.ifp = ifp;
194 /* unspecified or not? (RFC 2461 6.3.4) */
195 if (advreachable) {
196 NTOHL(advreachable);
197 if (advreachable <= MAX_REACHABLE_TIME &&
198 ndi->basereachable != advreachable) {
199 ndi->basereachable = advreachable;
200 ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
201 ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
202 }
203 }
204 if (nd_ra->nd_ra_retransmit)
205 ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
206 if (nd_ra->nd_ra_curhoplimit)
207 ndi->chlim = nd_ra->nd_ra_curhoplimit;
208 dr = defrtrlist_update(&dr0);
209 }
210
211 /*
212 * prefix
213 */
214 if (ndopts.nd_opts_pi) {
215 struct nd_opt_hdr *pt;
216 struct nd_opt_prefix_info *pi;
217 struct nd_prefix pr;
218
219 for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
220 pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
221 pt = (struct nd_opt_hdr *)((caddr_t)pt +
222 (pt->nd_opt_len << 3))) {
223 if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
224 continue;
225 pi = (struct nd_opt_prefix_info *)pt;
226
227 if (pi->nd_opt_pi_len != 4) {
228 log(LOG_INFO, "nd6_ra_input: invalid option "
229 "len %d for prefix information option, "
230 "ignored\n", pi->nd_opt_pi_len);
231 continue;
232 }
233
234 if (128 < pi->nd_opt_pi_prefix_len) {
235 log(LOG_INFO, "nd6_ra_input: invalid prefix "
236 "len %d for prefix information option, "
237 "ignored\n", pi->nd_opt_pi_prefix_len);
238 continue;
239 }
240
241 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
242 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
243 log(LOG_INFO, "nd6_ra_input: invalid prefix "
244 "%s, ignored\n",
245 ip6_sprintf(&pi->nd_opt_pi_prefix));
246 continue;
247 }
248
249 /* aggregatable unicast address, rfc2374 */
250 if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
251 && pi->nd_opt_pi_prefix_len != 64) {
252 log(LOG_INFO, "nd6_ra_input: invalid prefixlen "
253 "%d for rfc2374 prefix %s, ignored\n",
254 pi->nd_opt_pi_prefix_len,
255 ip6_sprintf(&pi->nd_opt_pi_prefix));
256 continue;
257 }
258
259 bzero(&pr, sizeof(pr));
260 pr.ndpr_prefix.sin6_family = AF_INET6;
261 pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
262 pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
263 pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
264
265 pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
266 ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
267 pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
268 ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
269 pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
270 pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
271 pr.ndpr_pltime =
272 ntohl(pi->nd_opt_pi_preferred_time);
273
274 if (in6_init_prefix_ltimes(&pr))
275 continue; /* prefix lifetime init failed */
276
277 (void)prelist_update(&pr, dr, m);
278 }
279 }
280
281 /*
282 * MTU
283 */
284 if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
285 u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
286
287 /* lower bound */
288 if (mtu < IPV6_MMTU) {
289 log(LOG_INFO, "nd6_ra_input: bogus mtu option "
290 "mtu=%d sent from %s, ignoring\n",
291 mtu, ip6_sprintf(&ip6->ip6_src));
292 goto skip;
293 }
294
295 /* upper bound */
296 if (ndi->maxmtu) {
297 if (mtu <= ndi->maxmtu) {
298 int change = (ndi->linkmtu != mtu);
299
300 ndi->linkmtu = mtu;
301 if (change) /* in6_maxmtu may change */
302 in6_setmaxmtu();
303 } else {
304 log(LOG_INFO, "nd6_ra_input: bogus mtu "
305 "mtu=%d sent from %s; "
306 "exceeds maxmtu %d, ignoring\n",
307 mtu, ip6_sprintf(&ip6->ip6_src),
308 ndi->maxmtu);
309 }
310 } else {
311 log(LOG_INFO, "nd6_ra_input: mtu option "
312 "mtu=%d sent from %s; maxmtu unknown, "
313 "ignoring\n",
314 mtu, ip6_sprintf(&ip6->ip6_src));
315 }
316 }
317
318 skip:
319
320 /*
321 * Src linkaddress
322 */
323 {
324 char *lladdr = NULL;
325 int lladdrlen = 0;
326
327 if (ndopts.nd_opts_src_lladdr) {
328 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
329 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
330 }
331
332 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
333 log(LOG_INFO,
334 "nd6_ra_input: lladdrlen mismatch for %s "
335 "(if %d, RA packet %d)\n",
336 ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
337 }
338
339 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
340 }
341}
342
343/*
344 * default router list proccessing sub routines
345 */
346void
347defrouter_addreq(new)
348 struct nd_defrouter *new;
349{
350 struct sockaddr_in6 def, mask, gate;
351 int s;
352
353 Bzero(&def, sizeof(def));
354 Bzero(&mask, sizeof(mask));
355 Bzero(&gate, sizeof(gate));
356
357 def.sin6_len = mask.sin6_len = gate.sin6_len
358 = sizeof(struct sockaddr_in6);
359 def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
360 gate.sin6_addr = new->rtaddr;
361
362 s = splnet();
363 (void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
364 (struct sockaddr *)&gate, (struct sockaddr *)&mask,
365 RTF_GATEWAY, NULL);
366 splx(s);
367 return;
368}
369
370struct nd_defrouter *
371defrouter_lookup(addr, ifp)
372 struct in6_addr *addr;
373 struct ifnet *ifp;
374{
375 struct nd_defrouter *dr;
376
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/mbuf.h>
36#include <sys/socket.h>
37#include <sys/sockio.h>
38#include <sys/time.h>
39#include <sys/kernel.h>
40#include <sys/errno.h>
41#include <sys/syslog.h>
42
43#include <net/if.h>
44#include <net/if_types.h>
45#include <net/if_dl.h>
46#include <net/route.h>
47#include <net/radix.h>
48
49#include <netinet/in.h>
50#include <netinet6/in6_var.h>
51#include <netinet6/ip6.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/nd6.h>
54#include <netinet6/icmp6.h>
55
56#include <net/net_osdep.h>
57
58#define SDL(s) ((struct sockaddr_dl *)s)
59
60static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
61static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *));
62static struct nd_prefix *prefix_lookup __P((struct nd_prefix *));
63static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *,
64 struct in6_addr *, int));
65static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
66 struct nd_defrouter *));
67static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
68static void pfxrtr_del __P((struct nd_pfxrouter *));
69static void pfxlist_onlink_check __P((void));
70static void nd6_detach_prefix __P((struct nd_prefix *));
71static void nd6_attach_prefix __P((struct nd_prefix *));
72
73static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
74 struct in6_addrlifetime *lt6));
75
76static int rt6_deleteroute __P((struct radix_node *, void *));
77
78extern int nd6_recalc_reachtm_interval;
79
80/*
81 * Receive Router Solicitation Message - just for routers.
82 * Router solicitation/advertisement is mostly managed by userland program
83 * (rtadvd) so here we have no function like nd6_ra_output().
84 *
85 * Based on RFC 2461
86 */
87void
88nd6_rs_input(m, off, icmp6len)
89 struct mbuf *m;
90 int off, icmp6len;
91{
92 struct ifnet *ifp = m->m_pkthdr.rcvif;
93 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
94 struct nd_router_solicit *nd_rs
95 = (struct nd_router_solicit *)((caddr_t)ip6 + off);
96 struct in6_addr saddr6 = ip6->ip6_src;
97 char *lladdr = NULL;
98 int lladdrlen = 0;
99 union nd_opts ndopts;
100
101 /* If I'm not a router, ignore it. */
102 if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
103 return;
104
105 /* Sanity checks */
106 if (ip6->ip6_hlim != 255) {
107 log(LOG_ERR,
108 "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
109 return;
110 }
111
112 /*
113 * Don't update the neighbor cache, if src = ::.
114 * This indicates that the src has no IP address assigned yet.
115 */
116 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
117 return;
118
119 icmp6len -= sizeof(*nd_rs);
120 nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
121 if (nd6_options(&ndopts) < 0) {
122 log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
123 return;
124 }
125
126 if (ndopts.nd_opts_src_lladdr) {
127 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
128 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
129 }
130
131 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
132 log(LOG_INFO,
133 "nd6_rs_input: lladdrlen mismatch for %s "
134 "(if %d, RS packet %d)\n",
135 ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
136 }
137
138 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
139}
140
141/*
142 * Receive Router Advertisement Message.
143 *
144 * Based on RFC 2461
145 * TODO: on-link bit on prefix information
146 * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
147 */
148void
149nd6_ra_input(m, off, icmp6len)
150 struct mbuf *m;
151 int off, icmp6len;
152{
153 struct ifnet *ifp = m->m_pkthdr.rcvif;
154 struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
155 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
156 struct nd_router_advert *nd_ra =
157 (struct nd_router_advert *)((caddr_t)ip6 + off);
158 struct in6_addr saddr6 = ip6->ip6_src;
159 union nd_opts ndopts;
160 struct nd_defrouter *dr;
161
162 if (ip6_accept_rtadv == 0)
163 return;
164
165 if (ip6->ip6_hlim != 255) {
166 log(LOG_ERR,
167 "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
168 return;
169 }
170
171 if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
172 log(LOG_ERR,
173 "nd6_ra_input: src %s is not link-local\n",
174 ip6_sprintf(&saddr6));
175 return;
176 }
177
178 icmp6len -= sizeof(*nd_ra);
179 nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
180 if (nd6_options(&ndopts) < 0) {
181 log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
182 return;
183 }
184
185 {
186 struct nd_defrouter dr0;
187 u_int32_t advreachable = nd_ra->nd_ra_reachable;
188
189 dr0.rtaddr = saddr6;
190 dr0.flags = nd_ra->nd_ra_flags_reserved;
191 dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
192 dr0.expire = time_second + dr0.rtlifetime;
193 dr0.ifp = ifp;
194 /* unspecified or not? (RFC 2461 6.3.4) */
195 if (advreachable) {
196 NTOHL(advreachable);
197 if (advreachable <= MAX_REACHABLE_TIME &&
198 ndi->basereachable != advreachable) {
199 ndi->basereachable = advreachable;
200 ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
201 ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
202 }
203 }
204 if (nd_ra->nd_ra_retransmit)
205 ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
206 if (nd_ra->nd_ra_curhoplimit)
207 ndi->chlim = nd_ra->nd_ra_curhoplimit;
208 dr = defrtrlist_update(&dr0);
209 }
210
211 /*
212 * prefix
213 */
214 if (ndopts.nd_opts_pi) {
215 struct nd_opt_hdr *pt;
216 struct nd_opt_prefix_info *pi;
217 struct nd_prefix pr;
218
219 for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
220 pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
221 pt = (struct nd_opt_hdr *)((caddr_t)pt +
222 (pt->nd_opt_len << 3))) {
223 if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
224 continue;
225 pi = (struct nd_opt_prefix_info *)pt;
226
227 if (pi->nd_opt_pi_len != 4) {
228 log(LOG_INFO, "nd6_ra_input: invalid option "
229 "len %d for prefix information option, "
230 "ignored\n", pi->nd_opt_pi_len);
231 continue;
232 }
233
234 if (128 < pi->nd_opt_pi_prefix_len) {
235 log(LOG_INFO, "nd6_ra_input: invalid prefix "
236 "len %d for prefix information option, "
237 "ignored\n", pi->nd_opt_pi_prefix_len);
238 continue;
239 }
240
241 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
242 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
243 log(LOG_INFO, "nd6_ra_input: invalid prefix "
244 "%s, ignored\n",
245 ip6_sprintf(&pi->nd_opt_pi_prefix));
246 continue;
247 }
248
249 /* aggregatable unicast address, rfc2374 */
250 if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
251 && pi->nd_opt_pi_prefix_len != 64) {
252 log(LOG_INFO, "nd6_ra_input: invalid prefixlen "
253 "%d for rfc2374 prefix %s, ignored\n",
254 pi->nd_opt_pi_prefix_len,
255 ip6_sprintf(&pi->nd_opt_pi_prefix));
256 continue;
257 }
258
259 bzero(&pr, sizeof(pr));
260 pr.ndpr_prefix.sin6_family = AF_INET6;
261 pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
262 pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
263 pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
264
265 pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
266 ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
267 pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
268 ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
269 pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
270 pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
271 pr.ndpr_pltime =
272 ntohl(pi->nd_opt_pi_preferred_time);
273
274 if (in6_init_prefix_ltimes(&pr))
275 continue; /* prefix lifetime init failed */
276
277 (void)prelist_update(&pr, dr, m);
278 }
279 }
280
281 /*
282 * MTU
283 */
284 if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
285 u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
286
287 /* lower bound */
288 if (mtu < IPV6_MMTU) {
289 log(LOG_INFO, "nd6_ra_input: bogus mtu option "
290 "mtu=%d sent from %s, ignoring\n",
291 mtu, ip6_sprintf(&ip6->ip6_src));
292 goto skip;
293 }
294
295 /* upper bound */
296 if (ndi->maxmtu) {
297 if (mtu <= ndi->maxmtu) {
298 int change = (ndi->linkmtu != mtu);
299
300 ndi->linkmtu = mtu;
301 if (change) /* in6_maxmtu may change */
302 in6_setmaxmtu();
303 } else {
304 log(LOG_INFO, "nd6_ra_input: bogus mtu "
305 "mtu=%d sent from %s; "
306 "exceeds maxmtu %d, ignoring\n",
307 mtu, ip6_sprintf(&ip6->ip6_src),
308 ndi->maxmtu);
309 }
310 } else {
311 log(LOG_INFO, "nd6_ra_input: mtu option "
312 "mtu=%d sent from %s; maxmtu unknown, "
313 "ignoring\n",
314 mtu, ip6_sprintf(&ip6->ip6_src));
315 }
316 }
317
318 skip:
319
320 /*
321 * Src linkaddress
322 */
323 {
324 char *lladdr = NULL;
325 int lladdrlen = 0;
326
327 if (ndopts.nd_opts_src_lladdr) {
328 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
329 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
330 }
331
332 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
333 log(LOG_INFO,
334 "nd6_ra_input: lladdrlen mismatch for %s "
335 "(if %d, RA packet %d)\n",
336 ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
337 }
338
339 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
340 }
341}
342
343/*
344 * default router list proccessing sub routines
345 */
346void
347defrouter_addreq(new)
348 struct nd_defrouter *new;
349{
350 struct sockaddr_in6 def, mask, gate;
351 int s;
352
353 Bzero(&def, sizeof(def));
354 Bzero(&mask, sizeof(mask));
355 Bzero(&gate, sizeof(gate));
356
357 def.sin6_len = mask.sin6_len = gate.sin6_len
358 = sizeof(struct sockaddr_in6);
359 def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
360 gate.sin6_addr = new->rtaddr;
361
362 s = splnet();
363 (void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
364 (struct sockaddr *)&gate, (struct sockaddr *)&mask,
365 RTF_GATEWAY, NULL);
366 splx(s);
367 return;
368}
369
370struct nd_defrouter *
371defrouter_lookup(addr, ifp)
372 struct in6_addr *addr;
373 struct ifnet *ifp;
374{
375 struct nd_defrouter *dr;
376
377 for(dr = nd_defrouter.lh_first; dr; dr = dr->dr_next)
377 LIST_FOREACH(dr, &nd_defrouter, dr_entry)
378 if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
379 return(dr);
380
381 return(NULL); /* search failed */
382}
383
384void
385defrouter_delreq(dr, dofree)
386 struct nd_defrouter *dr;
387 int dofree;
388{
389 struct sockaddr_in6 def, mask, gate;
390
391 Bzero(&def, sizeof(def));
392 Bzero(&mask, sizeof(mask));
393 Bzero(&gate, sizeof(gate));
394
395 def.sin6_len = mask.sin6_len = gate.sin6_len
396 = sizeof(struct sockaddr_in6);
397 def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
398 gate.sin6_addr = dr->rtaddr;
399
400 rtrequest(RTM_DELETE, (struct sockaddr *)&def,
401 (struct sockaddr *)&gate,
402 (struct sockaddr *)&mask,
403 RTF_GATEWAY, (struct rtentry **)0);
404
405 if (dofree)
406 free(dr, M_IP6NDP);
407
378 if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
379 return(dr);
380
381 return(NULL); /* search failed */
382}
383
384void
385defrouter_delreq(dr, dofree)
386 struct nd_defrouter *dr;
387 int dofree;
388{
389 struct sockaddr_in6 def, mask, gate;
390
391 Bzero(&def, sizeof(def));
392 Bzero(&mask, sizeof(mask));
393 Bzero(&gate, sizeof(gate));
394
395 def.sin6_len = mask.sin6_len = gate.sin6_len
396 = sizeof(struct sockaddr_in6);
397 def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
398 gate.sin6_addr = dr->rtaddr;
399
400 rtrequest(RTM_DELETE, (struct sockaddr *)&def,
401 (struct sockaddr *)&gate,
402 (struct sockaddr *)&mask,
403 RTF_GATEWAY, (struct rtentry **)0);
404
405 if (dofree)
406 free(dr, M_IP6NDP);
407
408 if (nd_defrouter.lh_first)
409 defrouter_addreq(nd_defrouter.lh_first);
408 if (!LIST_EMPTY(&nd_defrouter))
409 defrouter_addreq(LIST_FIRST(&nd_defrouter));
410
411 /*
412 * xxx update the Destination Cache entries for all
413 * destinations using that neighbor as a router (7.2.5)
414 */
415}
416
417void
418defrtrlist_del(dr)
419 struct nd_defrouter *dr;
420{
421 struct nd_defrouter *deldr = NULL;
422 struct nd_prefix *pr;
423
424 /*
425 * Flush all the routing table entries that use the router
426 * as a next hop.
427 */
428 if (!ip6_forwarding && ip6_accept_rtadv) {
429 /* above is a good condition? */
430 rt6_flush(&dr->rtaddr, dr->ifp);
431 }
432
410
411 /*
412 * xxx update the Destination Cache entries for all
413 * destinations using that neighbor as a router (7.2.5)
414 */
415}
416
417void
418defrtrlist_del(dr)
419 struct nd_defrouter *dr;
420{
421 struct nd_defrouter *deldr = NULL;
422 struct nd_prefix *pr;
423
424 /*
425 * Flush all the routing table entries that use the router
426 * as a next hop.
427 */
428 if (!ip6_forwarding && ip6_accept_rtadv) {
429 /* above is a good condition? */
430 rt6_flush(&dr->rtaddr, dr->ifp);
431 }
432
433 if (dr == nd_defrouter.lh_first)
433 if (dr == LIST_FIRST(&nd_defrouter))
434 deldr = dr; /* The router is primary. */
435
436 LIST_REMOVE(dr, dr_entry);
437
438 /*
439 * Also delete all the pointers to the router in each prefix lists.
440 */
434 deldr = dr; /* The router is primary. */
435
436 LIST_REMOVE(dr, dr_entry);
437
438 /*
439 * Also delete all the pointers to the router in each prefix lists.
440 */
441 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
441 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
442 struct nd_pfxrouter *pfxrtr;
443 if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
444 pfxrtr_del(pfxrtr);
445 }
446 pfxlist_onlink_check();
447
448 /*
449 * If the router is the primary one, delete the default route
450 * entry in the routing table.
451 */
452 if (deldr)
453 defrouter_delreq(deldr, 0);
454 free(dr, M_IP6NDP);
455}
456
457static struct nd_defrouter *
458defrtrlist_update(new)
459 struct nd_defrouter *new;
460{
461 struct nd_defrouter *dr, *n;
462 int s = splnet();
463
464 if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
465 /* entry exists */
466 if (new->rtlifetime == 0) {
467 defrtrlist_del(dr);
468 dr = NULL;
469 } else {
470 /* override */
471 dr->flags = new->flags; /* xxx flag check */
472 dr->rtlifetime = new->rtlifetime;
473 dr->expire = new->expire;
474 }
475 splx(s);
476 return(dr);
477 }
478
479 /* entry does not exist */
480 if (new->rtlifetime == 0) {
481 splx(s);
482 return(NULL);
483 }
484
485 n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
486 if (n == NULL) {
487 splx(s);
488 return(NULL);
489 }
490 bzero(n, sizeof(*n));
491 *n = *new;
442 struct nd_pfxrouter *pfxrtr;
443 if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
444 pfxrtr_del(pfxrtr);
445 }
446 pfxlist_onlink_check();
447
448 /*
449 * If the router is the primary one, delete the default route
450 * entry in the routing table.
451 */
452 if (deldr)
453 defrouter_delreq(deldr, 0);
454 free(dr, M_IP6NDP);
455}
456
457static struct nd_defrouter *
458defrtrlist_update(new)
459 struct nd_defrouter *new;
460{
461 struct nd_defrouter *dr, *n;
462 int s = splnet();
463
464 if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
465 /* entry exists */
466 if (new->rtlifetime == 0) {
467 defrtrlist_del(dr);
468 dr = NULL;
469 } else {
470 /* override */
471 dr->flags = new->flags; /* xxx flag check */
472 dr->rtlifetime = new->rtlifetime;
473 dr->expire = new->expire;
474 }
475 splx(s);
476 return(dr);
477 }
478
479 /* entry does not exist */
480 if (new->rtlifetime == 0) {
481 splx(s);
482 return(NULL);
483 }
484
485 n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
486 if (n == NULL) {
487 splx(s);
488 return(NULL);
489 }
490 bzero(n, sizeof(*n));
491 *n = *new;
492 if (nd_defrouter.lh_first == NULL) {
492 if (LIST_EMPTY(&nd_defrouter)) {
493 LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry);
494 defrouter_addreq(n);
495 } else {
493 LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry);
494 defrouter_addreq(n);
495 } else {
496 LIST_INSERT_AFTER(nd_defrouter.lh_first, n, dr_entry);
496 LIST_INSERT_AFTER(LIST_FIRST(&nd_defrouter), n, dr_entry);
497 defrouter_addreq(n);
498 }
499 splx(s);
500
501 return(n);
502}
503
504static struct nd_pfxrouter *
505pfxrtr_lookup(pr, dr)
506 struct nd_prefix *pr;
507 struct nd_defrouter *dr;
508{
509 struct nd_pfxrouter *search;
497 defrouter_addreq(n);
498 }
499 splx(s);
500
501 return(n);
502}
503
504static struct nd_pfxrouter *
505pfxrtr_lookup(pr, dr)
506 struct nd_prefix *pr;
507 struct nd_defrouter *dr;
508{
509 struct nd_pfxrouter *search;
510
511 for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
510
511 LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) {
512 if (search->router == dr)
513 break;
514 }
515
516 return(search);
517}
518
519static void
520pfxrtr_add(pr, dr)
521 struct nd_prefix *pr;
522 struct nd_defrouter *dr;
523{
524 struct nd_pfxrouter *new;
525
526 new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
527 if (new == NULL)
528 return;
529 bzero(new, sizeof(*new));
530 new->router = dr;
531
532 LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
533
534 pfxlist_onlink_check();
535}
536
537static void
538pfxrtr_del(pfr)
539 struct nd_pfxrouter *pfr;
540{
541 LIST_REMOVE(pfr, pfr_entry);
542 free(pfr, M_IP6NDP);
543}
544
545static struct nd_prefix *
546prefix_lookup(pr)
547 struct nd_prefix *pr;
548{
549 struct nd_prefix *search;
550
512 if (search->router == dr)
513 break;
514 }
515
516 return(search);
517}
518
519static void
520pfxrtr_add(pr, dr)
521 struct nd_prefix *pr;
522 struct nd_defrouter *dr;
523{
524 struct nd_pfxrouter *new;
525
526 new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
527 if (new == NULL)
528 return;
529 bzero(new, sizeof(*new));
530 new->router = dr;
531
532 LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
533
534 pfxlist_onlink_check();
535}
536
537static void
538pfxrtr_del(pfr)
539 struct nd_pfxrouter *pfr;
540{
541 LIST_REMOVE(pfr, pfr_entry);
542 free(pfr, M_IP6NDP);
543}
544
545static struct nd_prefix *
546prefix_lookup(pr)
547 struct nd_prefix *pr;
548{
549 struct nd_prefix *search;
550
551 for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
551 LIST_FOREACH(search, &nd_prefix, ndpr_entry) {
552 if (pr->ndpr_ifp == search->ndpr_ifp &&
553 pr->ndpr_plen == search->ndpr_plen &&
554 in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
555 &search->ndpr_prefix.sin6_addr,
556 pr->ndpr_plen)
557 ) {
558 break;
559 }
560 }
561
562 return(search);
563}
564
565static int
566prelist_add(pr, dr)
567 struct nd_prefix *pr;
568 struct nd_defrouter *dr;
569{
570 struct nd_prefix *new;
571 int i, s;
572
573 new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
574 if (new == NULL)
575 return ENOMEM;
576 bzero(new, sizeof(*new));
577 *new = *pr;
578
579 /* initilization */
580 new->ndpr_statef_onlink = pr->ndpr_statef_onlink;
581 LIST_INIT(&new->ndpr_advrtrs);
582 in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
583 /* make prefix in the canonical form */
584 for (i = 0; i < 4; i++)
585 new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
586 new->ndpr_mask.s6_addr32[i];
587
588 /* xxx ND_OPT_PI_FLAG_ONLINK processing */
589
590 s = splnet();
591 /* link ndpr_entry to nd_prefix list */
592 LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
593 splx(s);
594
595 if (dr)
596 pfxrtr_add(new, dr);
597
598 return 0;
599}
600
601void
602prelist_remove(pr)
603 struct nd_prefix *pr;
604{
605 struct nd_pfxrouter *pfr, *next;
606 int s;
607
608 s = splnet();
609 /* unlink ndpr_entry from nd_prefix list */
610 LIST_REMOVE(pr, ndpr_entry);
611 splx(s);
612
613 /* free list of routers that adversed the prefix */
552 if (pr->ndpr_ifp == search->ndpr_ifp &&
553 pr->ndpr_plen == search->ndpr_plen &&
554 in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
555 &search->ndpr_prefix.sin6_addr,
556 pr->ndpr_plen)
557 ) {
558 break;
559 }
560 }
561
562 return(search);
563}
564
565static int
566prelist_add(pr, dr)
567 struct nd_prefix *pr;
568 struct nd_defrouter *dr;
569{
570 struct nd_prefix *new;
571 int i, s;
572
573 new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
574 if (new == NULL)
575 return ENOMEM;
576 bzero(new, sizeof(*new));
577 *new = *pr;
578
579 /* initilization */
580 new->ndpr_statef_onlink = pr->ndpr_statef_onlink;
581 LIST_INIT(&new->ndpr_advrtrs);
582 in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
583 /* make prefix in the canonical form */
584 for (i = 0; i < 4; i++)
585 new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
586 new->ndpr_mask.s6_addr32[i];
587
588 /* xxx ND_OPT_PI_FLAG_ONLINK processing */
589
590 s = splnet();
591 /* link ndpr_entry to nd_prefix list */
592 LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
593 splx(s);
594
595 if (dr)
596 pfxrtr_add(new, dr);
597
598 return 0;
599}
600
601void
602prelist_remove(pr)
603 struct nd_prefix *pr;
604{
605 struct nd_pfxrouter *pfr, *next;
606 int s;
607
608 s = splnet();
609 /* unlink ndpr_entry from nd_prefix list */
610 LIST_REMOVE(pr, ndpr_entry);
611 splx(s);
612
613 /* free list of routers that adversed the prefix */
614 for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
615 next = pfr->pfr_next;
614 for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr; pfr = next) {
615 next = LIST_NEXT(pfr, pfr_entry);
616
617 free(pfr, M_IP6NDP);
618 }
619 free(pr, M_IP6NDP);
620
621 pfxlist_onlink_check();
622}
623
624/*
625 * NOTE: We set address lifetime to keep
626 * address lifetime <= prefix lifetime
627 * invariant. This is to simplify on-link determination code.
628 * If onlink determination is udated, this routine may have to be updated too.
629 */
630int
631prelist_update(new, dr, m)
632 struct nd_prefix *new;
633 struct nd_defrouter *dr; /* may be NULL */
634 struct mbuf *m;
635{
636 struct in6_ifaddr *ia6 = NULL;
637 struct nd_prefix *pr;
638 int s = splnet();
639 int error = 0;
640 int auth;
641 struct in6_addrlifetime *lt6;
642
643 auth = 0;
644 if (m) {
645 /*
646 * Authenticity for NA consists authentication for
647 * both IP header and IP datagrams, doesn't it ?
648 */
649#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
650 auth = (m->m_flags & M_AUTHIPHDR
651 && m->m_flags & M_AUTHIPDGM) ? 1 : 0;
652#endif
653 }
654
655 if ((pr = prefix_lookup(new)) != NULL) {
656 if (pr->ndpr_ifp != new->ndpr_ifp) {
657 error = EADDRNOTAVAIL;
658 goto end;
659 }
660 /* update prefix information */
661 pr->ndpr_flags = new->ndpr_flags;
662 pr->ndpr_vltime = new->ndpr_vltime;
663 pr->ndpr_pltime = new->ndpr_pltime;
664 pr->ndpr_preferred = new->ndpr_preferred;
665 pr->ndpr_expire = new->ndpr_expire;
666
667 /*
668 * RFC 2462 5.5.3 (d) or (e)
669 * We got a prefix which we have seen in the past.
670 */
671 if (!new->ndpr_raf_auto)
672 goto noautoconf1;
673
674 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
675 ia6 = NULL;
676 else
677 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
678
679 if (ia6 == NULL) {
680 /*
681 * Special case:
682 * (1) We have seen the prefix advertised before, but
683 * we have never performed autoconfig for this prefix.
684 * This is because Autonomous bit was 0 previously, or
685 * autoconfig failed due to some other reasons.
686 * (2) We have seen the prefix advertised before and
687 * we have performed autoconfig in the past, but
688 * we seem to have no interface address right now.
689 * This is because the interface address have expired.
690 *
691 * This prefix is fresh, with respect to autoconfig
692 * process.
693 *
694 * Add an address based on RFC 2462 5.5.3 (d).
695 */
696 ia6 = in6_ifadd(pr->ndpr_ifp,
697 &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr,
698 new->ndpr_plen);
699 if (!ia6) {
700 error = EADDRNOTAVAIL;
701 log(LOG_ERR, "prelist_update: failed to add a "
702 "new address\n");
703 goto noautoconf1;
704 }
705
706 lt6 = &ia6->ia6_lifetime;
707
708 /* address lifetime <= prefix lifetime */
709 lt6->ia6t_vltime = new->ndpr_vltime;
710 lt6->ia6t_pltime = new->ndpr_pltime;
711 in6_init_address_ltimes(new, lt6);
712 } else {
713#define TWOHOUR (120*60)
714 /*
715 * We have seen the prefix before, and we have added
716 * interface address in the past. We still have
717 * the interface address assigned.
718 *
719 * update address lifetime based on RFC 2462
720 * 5.5.3 (e).
721 */
722 int update = 0;
723
724 lt6 = &ia6->ia6_lifetime;
725
726 /*
727 * update to RFC 2462 5.5.3 (e) from Jim Bound,
728 * (ipng 6712)
729 */
730 if (TWOHOUR < new->ndpr_vltime
731 || lt6->ia6t_vltime < new->ndpr_vltime) {
732 lt6->ia6t_vltime = new->ndpr_vltime;
733 update++;
734 } else if (auth) {
735 lt6->ia6t_vltime = new->ndpr_vltime;
736 update++;
737 }
738
739 /* jim bound rule is not imposed for pref lifetime */
740 lt6->ia6t_pltime = new->ndpr_pltime;
741
742 update++;
743 if (update)
744 in6_init_address_ltimes(new, lt6);
745 }
746
747 noautoconf1:
748
749 if (dr && pfxrtr_lookup(pr, dr) == NULL)
750 pfxrtr_add(pr, dr);
751 } else {
752 int error_tmp;
753
754 if (new->ndpr_vltime == 0) goto end;
755
756 bzero(&new->ndpr_addr, sizeof(struct in6_addr));
757
758 /*
759 * RFC 2462 5.5.3 (d)
760 * We got a fresh prefix. Perform some sanity checks
761 * and add an interface address by appending interface ID
762 * to the advertised prefix.
763 */
764 if (!new->ndpr_raf_auto)
765 goto noautoconf2;
766
767 ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr,
768 &new->ndpr_addr, new->ndpr_plen);
769 if (!ia6) {
770 error = EADDRNOTAVAIL;
771 log(LOG_ERR, "prelist_update: "
772 "failed to add a new address\n");
773 goto noautoconf2;
774 }
775 /* set onlink bit if an interface route is configured */
776 new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0;
777
778 lt6 = &ia6->ia6_lifetime;
779
780 /* address lifetime <= prefix lifetime */
781 lt6->ia6t_vltime = new->ndpr_vltime;
782 lt6->ia6t_pltime = new->ndpr_pltime;
783 in6_init_address_ltimes(new, lt6);
784
785 noautoconf2:
786 error_tmp = prelist_add(new, dr);
787 error = error_tmp ? error_tmp : error;
788 }
789
790 end:
791 splx(s);
792 return error;
793}
794
795/*
796 * Check if each prefix in the prefix list has at least one available router
797 * that advertised the prefix.
798 * If the check fails, the prefix may be off-link because, for example,
799 * we have moved from the network but the lifetime of the prefix has not
800 * been expired yet. So we should not use the prefix if there is another
801 * prefix that has an available router.
802 * But if there is no prefix that has an availble router, we still regards
803 * all the prefixes as on-link. This is because we can't tell if all the
804 * routers are simply dead or if we really moved from the network and there
805 * is no router around us.
806 */
807static void
808pfxlist_onlink_check()
809{
810 struct nd_prefix *pr;
811
616
617 free(pfr, M_IP6NDP);
618 }
619 free(pr, M_IP6NDP);
620
621 pfxlist_onlink_check();
622}
623
624/*
625 * NOTE: We set address lifetime to keep
626 * address lifetime <= prefix lifetime
627 * invariant. This is to simplify on-link determination code.
628 * If onlink determination is udated, this routine may have to be updated too.
629 */
630int
631prelist_update(new, dr, m)
632 struct nd_prefix *new;
633 struct nd_defrouter *dr; /* may be NULL */
634 struct mbuf *m;
635{
636 struct in6_ifaddr *ia6 = NULL;
637 struct nd_prefix *pr;
638 int s = splnet();
639 int error = 0;
640 int auth;
641 struct in6_addrlifetime *lt6;
642
643 auth = 0;
644 if (m) {
645 /*
646 * Authenticity for NA consists authentication for
647 * both IP header and IP datagrams, doesn't it ?
648 */
649#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
650 auth = (m->m_flags & M_AUTHIPHDR
651 && m->m_flags & M_AUTHIPDGM) ? 1 : 0;
652#endif
653 }
654
655 if ((pr = prefix_lookup(new)) != NULL) {
656 if (pr->ndpr_ifp != new->ndpr_ifp) {
657 error = EADDRNOTAVAIL;
658 goto end;
659 }
660 /* update prefix information */
661 pr->ndpr_flags = new->ndpr_flags;
662 pr->ndpr_vltime = new->ndpr_vltime;
663 pr->ndpr_pltime = new->ndpr_pltime;
664 pr->ndpr_preferred = new->ndpr_preferred;
665 pr->ndpr_expire = new->ndpr_expire;
666
667 /*
668 * RFC 2462 5.5.3 (d) or (e)
669 * We got a prefix which we have seen in the past.
670 */
671 if (!new->ndpr_raf_auto)
672 goto noautoconf1;
673
674 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
675 ia6 = NULL;
676 else
677 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
678
679 if (ia6 == NULL) {
680 /*
681 * Special case:
682 * (1) We have seen the prefix advertised before, but
683 * we have never performed autoconfig for this prefix.
684 * This is because Autonomous bit was 0 previously, or
685 * autoconfig failed due to some other reasons.
686 * (2) We have seen the prefix advertised before and
687 * we have performed autoconfig in the past, but
688 * we seem to have no interface address right now.
689 * This is because the interface address have expired.
690 *
691 * This prefix is fresh, with respect to autoconfig
692 * process.
693 *
694 * Add an address based on RFC 2462 5.5.3 (d).
695 */
696 ia6 = in6_ifadd(pr->ndpr_ifp,
697 &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr,
698 new->ndpr_plen);
699 if (!ia6) {
700 error = EADDRNOTAVAIL;
701 log(LOG_ERR, "prelist_update: failed to add a "
702 "new address\n");
703 goto noautoconf1;
704 }
705
706 lt6 = &ia6->ia6_lifetime;
707
708 /* address lifetime <= prefix lifetime */
709 lt6->ia6t_vltime = new->ndpr_vltime;
710 lt6->ia6t_pltime = new->ndpr_pltime;
711 in6_init_address_ltimes(new, lt6);
712 } else {
713#define TWOHOUR (120*60)
714 /*
715 * We have seen the prefix before, and we have added
716 * interface address in the past. We still have
717 * the interface address assigned.
718 *
719 * update address lifetime based on RFC 2462
720 * 5.5.3 (e).
721 */
722 int update = 0;
723
724 lt6 = &ia6->ia6_lifetime;
725
726 /*
727 * update to RFC 2462 5.5.3 (e) from Jim Bound,
728 * (ipng 6712)
729 */
730 if (TWOHOUR < new->ndpr_vltime
731 || lt6->ia6t_vltime < new->ndpr_vltime) {
732 lt6->ia6t_vltime = new->ndpr_vltime;
733 update++;
734 } else if (auth) {
735 lt6->ia6t_vltime = new->ndpr_vltime;
736 update++;
737 }
738
739 /* jim bound rule is not imposed for pref lifetime */
740 lt6->ia6t_pltime = new->ndpr_pltime;
741
742 update++;
743 if (update)
744 in6_init_address_ltimes(new, lt6);
745 }
746
747 noautoconf1:
748
749 if (dr && pfxrtr_lookup(pr, dr) == NULL)
750 pfxrtr_add(pr, dr);
751 } else {
752 int error_tmp;
753
754 if (new->ndpr_vltime == 0) goto end;
755
756 bzero(&new->ndpr_addr, sizeof(struct in6_addr));
757
758 /*
759 * RFC 2462 5.5.3 (d)
760 * We got a fresh prefix. Perform some sanity checks
761 * and add an interface address by appending interface ID
762 * to the advertised prefix.
763 */
764 if (!new->ndpr_raf_auto)
765 goto noautoconf2;
766
767 ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr,
768 &new->ndpr_addr, new->ndpr_plen);
769 if (!ia6) {
770 error = EADDRNOTAVAIL;
771 log(LOG_ERR, "prelist_update: "
772 "failed to add a new address\n");
773 goto noautoconf2;
774 }
775 /* set onlink bit if an interface route is configured */
776 new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0;
777
778 lt6 = &ia6->ia6_lifetime;
779
780 /* address lifetime <= prefix lifetime */
781 lt6->ia6t_vltime = new->ndpr_vltime;
782 lt6->ia6t_pltime = new->ndpr_pltime;
783 in6_init_address_ltimes(new, lt6);
784
785 noautoconf2:
786 error_tmp = prelist_add(new, dr);
787 error = error_tmp ? error_tmp : error;
788 }
789
790 end:
791 splx(s);
792 return error;
793}
794
795/*
796 * Check if each prefix in the prefix list has at least one available router
797 * that advertised the prefix.
798 * If the check fails, the prefix may be off-link because, for example,
799 * we have moved from the network but the lifetime of the prefix has not
800 * been expired yet. So we should not use the prefix if there is another
801 * prefix that has an available router.
802 * But if there is no prefix that has an availble router, we still regards
803 * all the prefixes as on-link. This is because we can't tell if all the
804 * routers are simply dead or if we really moved from the network and there
805 * is no router around us.
806 */
807static void
808pfxlist_onlink_check()
809{
810 struct nd_prefix *pr;
811
812 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
813 if (pr->ndpr_advrtrs.lh_first) /* pr has an available router */
812 LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
813 if (!LIST_EMPTY(&pr->ndpr_advrtrs)) /* pr has an available router */
814 break;
815
816 if (pr) {
817 /*
818 * There is at least one prefix that has a router. First,
819 * detach prefixes which has no advertising router and then
820 * attach other prefixes. The order is important since an
821 * attached prefix and a detached prefix may have a same
822 * interface route.
823 */
814 break;
815
816 if (pr) {
817 /*
818 * There is at least one prefix that has a router. First,
819 * detach prefixes which has no advertising router and then
820 * attach other prefixes. The order is important since an
821 * attached prefix and a detached prefix may have a same
822 * interface route.
823 */
824 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
825 if (pr->ndpr_advrtrs.lh_first == NULL &&
824 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
825 if (LIST_EMPTY(&pr->ndpr_advrtrs) &&
826 pr->ndpr_statef_onlink) {
827 pr->ndpr_statef_onlink = 0;
828 nd6_detach_prefix(pr);
829 }
830 }
826 pr->ndpr_statef_onlink) {
827 pr->ndpr_statef_onlink = 0;
828 nd6_detach_prefix(pr);
829 }
830 }
831 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
832 if (pr->ndpr_advrtrs.lh_first &&
831 LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
832 if (!LIST_EMPTY(&pr->ndpr_advrtrs) &&
833 pr->ndpr_statef_onlink == 0)
834 nd6_attach_prefix(pr);
835 }
836 } else {
837 /* there is no prefix that has a router */
833 pr->ndpr_statef_onlink == 0)
834 nd6_attach_prefix(pr);
835 }
836 } else {
837 /* there is no prefix that has a router */
838 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next)
838 LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
839 if (pr->ndpr_statef_onlink == 0)
840 nd6_attach_prefix(pr);
841 }
842}
843
844static void
845nd6_detach_prefix(pr)
846 struct nd_prefix *pr;
847{
848 struct in6_ifaddr *ia6;
849 struct sockaddr_in6 sa6, mask6;
850
851 /*
852 * Delete the interface route associated with the prefix.
853 */
854 bzero(&sa6, sizeof(sa6));
855 sa6.sin6_family = AF_INET6;
856 sa6.sin6_len = sizeof(sa6);
857 bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
858 sizeof(struct in6_addr));
859 bzero(&mask6, sizeof(mask6));
860 mask6.sin6_family = AF_INET6;
861 mask6.sin6_len = sizeof(sa6);
862 bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
863 {
864 int e;
865
866 e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
867 (struct sockaddr *)&mask6, 0, NULL);
868 if (e) {
869 log(LOG_ERR,
870 "nd6_detach_prefix: failed to delete route: "
871 "%s/%d (errno = %d)\n",
872 ip6_sprintf(&sa6.sin6_addr),
873 pr->ndpr_plen,
874 e);
875 }
876 }
877
878 /*
879 * Mark the address derived from the prefix detached so that
880 * it won't be used as a source address for a new connection.
881 */
882 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
883 ia6 = NULL;
884 else
885 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
886 if (ia6)
887 ia6->ia6_flags |= IN6_IFF_DETACHED;
888}
889
890static void
891nd6_attach_prefix(pr)
892 struct nd_prefix *pr;
893{
894 struct ifaddr *ifa;
895 struct in6_ifaddr *ia6;
896
897 /*
898 * Add the interface route associated with the prefix(if necessary)
899 * Should we consider if the L bit is set in pr->ndpr_flags?
900 */
901 ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix,
902 pr->ndpr_ifp);
903 if (ifa == NULL) {
904 log(LOG_ERR,
905 "nd6_attach_prefix: failed to find any ifaddr"
906 " to add route for a prefix(%s/%d)\n",
907 ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen);
908 } else {
909 int e;
910 struct sockaddr_in6 mask6;
911
912 bzero(&mask6, sizeof(mask6));
913 mask6.sin6_family = AF_INET6;
914 mask6.sin6_len = sizeof(mask6);
915 mask6.sin6_addr = pr->ndpr_mask;
916 e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
917 ifa->ifa_addr, (struct sockaddr *)&mask6,
918 ifa->ifa_flags, NULL);
919 if (e == 0)
920 pr->ndpr_statef_onlink = 1;
921 else {
922 log(LOG_ERR,
923 "nd6_attach_prefix: failed to add route for"
924 " a prefix(%s/%d), errno = %d\n",
925 ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e);
926 }
927 }
928
929 /*
930 * Now the address derived from the prefix can be used as a source
931 * for a new connection, so clear the detached flag.
932 */
933 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
934 ia6 = NULL;
935 else
936 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
937 if (ia6) {
938 ia6->ia6_flags &= ~IN6_IFF_DETACHED;
939 if (pr->ndpr_statef_onlink)
940 ia6->ia_flags |= IFA_ROUTE;
941 }
942}
943
944static struct in6_ifaddr *
945in6_ifadd(ifp, in6, addr, prefixlen)
946 struct ifnet *ifp;
947 struct in6_addr *in6;
948 struct in6_addr *addr;
949 int prefixlen; /* prefix len of the new prefix in "in6" */
950{
951 struct ifaddr *ifa;
952 struct in6_ifaddr *ia, *ib, *oia;
953 int s, error;
954 struct in6_addr mask;
955
956 in6_len2mask(&mask, prefixlen);
957
958 /* find link-local address (will be interface ID) */
959 ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
960 if (ifa)
961 ib = (struct in6_ifaddr *)ifa;
962 else
963 return NULL;
964
965 /* prefixlen + ifidlen must be equal to 128 */
966 if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) {
967 log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
968 "(prefix=%d ifid=%d)\n", if_name(ifp),
969 prefixlen,
970 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr));
971 return NULL;
972 }
973
974 /* make ifaddr */
975 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT);
976 if (ia == NULL) {
977 printf("ENOBUFS in in6_ifadd %d\n", __LINE__);
978 return NULL;
979 }
980
981 bzero((caddr_t)ia, sizeof(*ia));
982 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
983 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
984 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
985 ia->ia_ifp = ifp;
986
987 /* link to in6_ifaddr */
988 if ((oia = in6_ifaddr) != NULL) {
989 for( ; oia->ia_next; oia = oia->ia_next)
990 continue;
991 oia->ia_next = ia;
992 } else
993 in6_ifaddr = ia;
994
995 /* link to if_addrlist */
839 if (pr->ndpr_statef_onlink == 0)
840 nd6_attach_prefix(pr);
841 }
842}
843
844static void
845nd6_detach_prefix(pr)
846 struct nd_prefix *pr;
847{
848 struct in6_ifaddr *ia6;
849 struct sockaddr_in6 sa6, mask6;
850
851 /*
852 * Delete the interface route associated with the prefix.
853 */
854 bzero(&sa6, sizeof(sa6));
855 sa6.sin6_family = AF_INET6;
856 sa6.sin6_len = sizeof(sa6);
857 bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
858 sizeof(struct in6_addr));
859 bzero(&mask6, sizeof(mask6));
860 mask6.sin6_family = AF_INET6;
861 mask6.sin6_len = sizeof(sa6);
862 bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
863 {
864 int e;
865
866 e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
867 (struct sockaddr *)&mask6, 0, NULL);
868 if (e) {
869 log(LOG_ERR,
870 "nd6_detach_prefix: failed to delete route: "
871 "%s/%d (errno = %d)\n",
872 ip6_sprintf(&sa6.sin6_addr),
873 pr->ndpr_plen,
874 e);
875 }
876 }
877
878 /*
879 * Mark the address derived from the prefix detached so that
880 * it won't be used as a source address for a new connection.
881 */
882 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
883 ia6 = NULL;
884 else
885 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
886 if (ia6)
887 ia6->ia6_flags |= IN6_IFF_DETACHED;
888}
889
890static void
891nd6_attach_prefix(pr)
892 struct nd_prefix *pr;
893{
894 struct ifaddr *ifa;
895 struct in6_ifaddr *ia6;
896
897 /*
898 * Add the interface route associated with the prefix(if necessary)
899 * Should we consider if the L bit is set in pr->ndpr_flags?
900 */
901 ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix,
902 pr->ndpr_ifp);
903 if (ifa == NULL) {
904 log(LOG_ERR,
905 "nd6_attach_prefix: failed to find any ifaddr"
906 " to add route for a prefix(%s/%d)\n",
907 ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen);
908 } else {
909 int e;
910 struct sockaddr_in6 mask6;
911
912 bzero(&mask6, sizeof(mask6));
913 mask6.sin6_family = AF_INET6;
914 mask6.sin6_len = sizeof(mask6);
915 mask6.sin6_addr = pr->ndpr_mask;
916 e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
917 ifa->ifa_addr, (struct sockaddr *)&mask6,
918 ifa->ifa_flags, NULL);
919 if (e == 0)
920 pr->ndpr_statef_onlink = 1;
921 else {
922 log(LOG_ERR,
923 "nd6_attach_prefix: failed to add route for"
924 " a prefix(%s/%d), errno = %d\n",
925 ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e);
926 }
927 }
928
929 /*
930 * Now the address derived from the prefix can be used as a source
931 * for a new connection, so clear the detached flag.
932 */
933 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
934 ia6 = NULL;
935 else
936 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
937 if (ia6) {
938 ia6->ia6_flags &= ~IN6_IFF_DETACHED;
939 if (pr->ndpr_statef_onlink)
940 ia6->ia_flags |= IFA_ROUTE;
941 }
942}
943
944static struct in6_ifaddr *
945in6_ifadd(ifp, in6, addr, prefixlen)
946 struct ifnet *ifp;
947 struct in6_addr *in6;
948 struct in6_addr *addr;
949 int prefixlen; /* prefix len of the new prefix in "in6" */
950{
951 struct ifaddr *ifa;
952 struct in6_ifaddr *ia, *ib, *oia;
953 int s, error;
954 struct in6_addr mask;
955
956 in6_len2mask(&mask, prefixlen);
957
958 /* find link-local address (will be interface ID) */
959 ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
960 if (ifa)
961 ib = (struct in6_ifaddr *)ifa;
962 else
963 return NULL;
964
965 /* prefixlen + ifidlen must be equal to 128 */
966 if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) {
967 log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
968 "(prefix=%d ifid=%d)\n", if_name(ifp),
969 prefixlen,
970 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr));
971 return NULL;
972 }
973
974 /* make ifaddr */
975 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT);
976 if (ia == NULL) {
977 printf("ENOBUFS in in6_ifadd %d\n", __LINE__);
978 return NULL;
979 }
980
981 bzero((caddr_t)ia, sizeof(*ia));
982 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
983 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
984 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
985 ia->ia_ifp = ifp;
986
987 /* link to in6_ifaddr */
988 if ((oia = in6_ifaddr) != NULL) {
989 for( ; oia->ia_next; oia = oia->ia_next)
990 continue;
991 oia->ia_next = ia;
992 } else
993 in6_ifaddr = ia;
994
995 /* link to if_addrlist */
996 if (ifp->if_addrlist.tqh_first != NULL) {
996 if (!TAILQ_EMPTY(&ifp->if_addrlist)) {
997 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
998 ifa_list);
999 }
1000
1001 /* new address */
1002 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
1003 ia->ia_addr.sin6_family = AF_INET6;
1004 /* prefix */
1005 bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr));
1006 ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
1007 ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
1008 ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
1009 ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
1010 /* interface ID */
1011 ia->ia_addr.sin6_addr.s6_addr32[0]
1012 |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1013 ia->ia_addr.sin6_addr.s6_addr32[1]
1014 |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1015 ia->ia_addr.sin6_addr.s6_addr32[2]
1016 |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1017 ia->ia_addr.sin6_addr.s6_addr32[3]
1018 |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1019
1020 /* new prefix */
1021 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1022 ia->ia_prefixmask.sin6_family = AF_INET6;
1023 bcopy(&mask, &ia->ia_prefixmask.sin6_addr,
1024 sizeof(ia->ia_prefixmask.sin6_addr));
1025
1026 /* same routine */
1027 ia->ia_ifa.ifa_rtrequest =
1028 (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest;
1029 ia->ia_ifa.ifa_flags |= RTF_CLONING;
1030 ia->ia_ifa.ifa_metric = ifp->if_metric;
1031
1032 /* add interface route */
1033 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) {
1034 log(LOG_NOTICE, "in6_ifadd: failed to add an interface route "
1035 "for %s/%d on %s, errno = %d\n",
1036 ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen,
1037 if_name(ifp), error);
1038 } else
1039 ia->ia_flags |= IFA_ROUTE;
1040
1041 *addr = ia->ia_addr.sin6_addr;
1042
1043 if (ifp->if_flags & IFF_MULTICAST) {
1044 int error; /* not used */
1045 struct in6_addr sol6;
1046
1047 /* join solicited node multicast address */
1048 bzero(&sol6, sizeof(sol6));
1049 sol6.s6_addr16[0] = htons(0xff02);
1050 sol6.s6_addr16[1] = htons(ifp->if_index);
1051 sol6.s6_addr32[1] = 0;
1052 sol6.s6_addr32[2] = htonl(1);
1053 sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
1054 sol6.s6_addr8[12] = 0xff;
1055 (void)in6_addmulti(&sol6, ifp, &error);
1056 }
1057
1058 ia->ia6_flags |= IN6_IFF_TENTATIVE;
1059
1060 /*
1061 * To make the interface up. Only AF_INET6 in ia is used...
1062 */
1063 s = splimp();
1064 if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) {
1065 splx(s);
1066 return NULL;
1067 }
1068 splx(s);
1069
1070 /* Perform DAD, if needed. */
1071 nd6_dad_start((struct ifaddr *)ia, NULL);
1072
1073 return ia;
1074}
1075
1076int
1077in6_ifdel(ifp, in6)
1078 struct ifnet *ifp;
1079 struct in6_addr *in6;
1080{
1081 struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL;
1082 struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL;
1083
1084 if (!ifp)
1085 return -1;
1086
1087 ia = in6ifa_ifpwithaddr(ifp, in6);
1088 if (!ia)
1089 return -1;
1090
1091 if (ifp->if_flags & IFF_MULTICAST) {
1092 /*
1093 * delete solicited multicast addr for deleting host id
1094 */
1095 struct in6_multi *in6m;
1096 struct in6_addr llsol;
1097 bzero(&llsol, sizeof(struct in6_addr));
1098 llsol.s6_addr16[0] = htons(0xff02);
1099 llsol.s6_addr16[1] = htons(ifp->if_index);
1100 llsol.s6_addr32[1] = 0;
1101 llsol.s6_addr32[2] = htonl(1);
1102 llsol.s6_addr32[3] =
1103 ia->ia_addr.sin6_addr.s6_addr32[3];
1104 llsol.s6_addr8[12] = 0xff;
1105
1106 IN6_LOOKUP_MULTI(llsol, ifp, in6m);
1107 if (in6m)
1108 in6_delmulti(in6m);
1109 }
1110
1111 if (ia->ia_flags & IFA_ROUTE) {
1112 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
1113 ia->ia_flags &= ~IFA_ROUTE;
1114 }
1115
1116 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1117
1118 /* lladdr is never deleted */
1119 oia = ia;
1120 if (oia == (ia = in6_ifaddr))
1121 in6_ifaddr = ia->ia_next;
1122 else {
1123 while (ia->ia_next && (ia->ia_next != oia))
1124 ia = ia->ia_next;
1125 if (ia->ia_next)
1126 ia->ia_next = oia->ia_next;
1127 else
1128 return -1;
1129 }
1130
1131 IFAFREE((&oia->ia_ifa));
1132/* xxx
1133 rtrequest(RTM_DELETE,
1134 (struct sockaddr *)&ia->ia_addr,
1135 (struct sockaddr *)0
1136 (struct sockaddr *)&ia->ia_prefixmask,
1137 RTF_UP|RTF_CLONING,
1138 (struct rtentry **)0);
1139*/
1140 return 0;
1141}
1142
1143int
1144in6_init_prefix_ltimes(struct nd_prefix *ndpr)
1145{
1146
1147 /* check if preferred lifetime > valid lifetime */
1148 if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
1149 log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
1150 "(%d) is greater than valid lifetime(%d)\n",
1151 (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime);
1152 return (EINVAL);
1153 }
1154 if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
1155 ndpr->ndpr_preferred = 0;
1156 else
1157 ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
1158 if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
1159 ndpr->ndpr_expire = 0;
1160 else
1161 ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
1162
1163 return 0;
1164}
1165
1166static void
1167in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
1168{
1169
1170 /* init ia6t_expire */
1171 if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
1172 lt6->ia6t_expire = 0;
1173 else {
1174 lt6->ia6t_expire = time_second;
1175 lt6->ia6t_expire += lt6->ia6t_vltime;
1176 }
1177 /* init ia6t_preferred */
1178 if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
1179 lt6->ia6t_preferred = 0;
1180 else {
1181 lt6->ia6t_preferred = time_second;
1182 lt6->ia6t_preferred += lt6->ia6t_pltime;
1183 }
1184 /* ensure addr lifetime <= prefix lifetime */
1185 if (new->ndpr_expire && lt6->ia6t_expire &&
1186 new->ndpr_expire < lt6->ia6t_expire)
1187 lt6->ia6t_expire = new->ndpr_expire;
1188 if (new->ndpr_preferred && lt6->ia6t_preferred
1189 && new->ndpr_preferred < lt6->ia6t_preferred)
1190 lt6->ia6t_preferred = new->ndpr_preferred;
1191}
1192
1193/*
1194 * Delete all the routing table entries that use the specified gateway.
1195 * XXX: this function causes search through all entries of routing table, so
1196 * it shouldn't be called when acting as a router.
1197 */
1198void
1199rt6_flush(gateway, ifp)
1200 struct in6_addr *gateway;
1201 struct ifnet *ifp;
1202{
1203 struct radix_node_head *rnh = rt_tables[AF_INET6];
1204 int s = splnet();
1205
1206 /* We'll care only link-local addresses */
1207 if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
1208 splx(s);
1209 return;
1210 }
1211 /* XXX: hack for KAME's link-local address kludge */
1212 gateway->s6_addr16[1] = htons(ifp->if_index);
1213
1214 rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
1215 splx(s);
1216}
1217
1218static int
1219rt6_deleteroute(rn, arg)
1220 struct radix_node *rn;
1221 void *arg;
1222{
1223#define SIN6(s) ((struct sockaddr_in6 *)s)
1224 struct rtentry *rt = (struct rtentry *)rn;
1225 struct in6_addr *gate = (struct in6_addr *)arg;
1226
1227 if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
1228 return(0);
1229
1230 if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
1231 return(0);
1232
1233 /*
1234 * We delete only host route. This means, in particular, we don't
1235 * delete default route.
1236 */
1237 if ((rt->rt_flags & RTF_HOST) == 0)
1238 return(0);
1239
1240 return(rtrequest(RTM_DELETE, rt_key(rt),
1241 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
1242#undef SIN6
1243}
997 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
998 ifa_list);
999 }
1000
1001 /* new address */
1002 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
1003 ia->ia_addr.sin6_family = AF_INET6;
1004 /* prefix */
1005 bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr));
1006 ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
1007 ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
1008 ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
1009 ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
1010 /* interface ID */
1011 ia->ia_addr.sin6_addr.s6_addr32[0]
1012 |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1013 ia->ia_addr.sin6_addr.s6_addr32[1]
1014 |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1015 ia->ia_addr.sin6_addr.s6_addr32[2]
1016 |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1017 ia->ia_addr.sin6_addr.s6_addr32[3]
1018 |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1019
1020 /* new prefix */
1021 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1022 ia->ia_prefixmask.sin6_family = AF_INET6;
1023 bcopy(&mask, &ia->ia_prefixmask.sin6_addr,
1024 sizeof(ia->ia_prefixmask.sin6_addr));
1025
1026 /* same routine */
1027 ia->ia_ifa.ifa_rtrequest =
1028 (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest;
1029 ia->ia_ifa.ifa_flags |= RTF_CLONING;
1030 ia->ia_ifa.ifa_metric = ifp->if_metric;
1031
1032 /* add interface route */
1033 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) {
1034 log(LOG_NOTICE, "in6_ifadd: failed to add an interface route "
1035 "for %s/%d on %s, errno = %d\n",
1036 ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen,
1037 if_name(ifp), error);
1038 } else
1039 ia->ia_flags |= IFA_ROUTE;
1040
1041 *addr = ia->ia_addr.sin6_addr;
1042
1043 if (ifp->if_flags & IFF_MULTICAST) {
1044 int error; /* not used */
1045 struct in6_addr sol6;
1046
1047 /* join solicited node multicast address */
1048 bzero(&sol6, sizeof(sol6));
1049 sol6.s6_addr16[0] = htons(0xff02);
1050 sol6.s6_addr16[1] = htons(ifp->if_index);
1051 sol6.s6_addr32[1] = 0;
1052 sol6.s6_addr32[2] = htonl(1);
1053 sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
1054 sol6.s6_addr8[12] = 0xff;
1055 (void)in6_addmulti(&sol6, ifp, &error);
1056 }
1057
1058 ia->ia6_flags |= IN6_IFF_TENTATIVE;
1059
1060 /*
1061 * To make the interface up. Only AF_INET6 in ia is used...
1062 */
1063 s = splimp();
1064 if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) {
1065 splx(s);
1066 return NULL;
1067 }
1068 splx(s);
1069
1070 /* Perform DAD, if needed. */
1071 nd6_dad_start((struct ifaddr *)ia, NULL);
1072
1073 return ia;
1074}
1075
1076int
1077in6_ifdel(ifp, in6)
1078 struct ifnet *ifp;
1079 struct in6_addr *in6;
1080{
1081 struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL;
1082 struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL;
1083
1084 if (!ifp)
1085 return -1;
1086
1087 ia = in6ifa_ifpwithaddr(ifp, in6);
1088 if (!ia)
1089 return -1;
1090
1091 if (ifp->if_flags & IFF_MULTICAST) {
1092 /*
1093 * delete solicited multicast addr for deleting host id
1094 */
1095 struct in6_multi *in6m;
1096 struct in6_addr llsol;
1097 bzero(&llsol, sizeof(struct in6_addr));
1098 llsol.s6_addr16[0] = htons(0xff02);
1099 llsol.s6_addr16[1] = htons(ifp->if_index);
1100 llsol.s6_addr32[1] = 0;
1101 llsol.s6_addr32[2] = htonl(1);
1102 llsol.s6_addr32[3] =
1103 ia->ia_addr.sin6_addr.s6_addr32[3];
1104 llsol.s6_addr8[12] = 0xff;
1105
1106 IN6_LOOKUP_MULTI(llsol, ifp, in6m);
1107 if (in6m)
1108 in6_delmulti(in6m);
1109 }
1110
1111 if (ia->ia_flags & IFA_ROUTE) {
1112 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
1113 ia->ia_flags &= ~IFA_ROUTE;
1114 }
1115
1116 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1117
1118 /* lladdr is never deleted */
1119 oia = ia;
1120 if (oia == (ia = in6_ifaddr))
1121 in6_ifaddr = ia->ia_next;
1122 else {
1123 while (ia->ia_next && (ia->ia_next != oia))
1124 ia = ia->ia_next;
1125 if (ia->ia_next)
1126 ia->ia_next = oia->ia_next;
1127 else
1128 return -1;
1129 }
1130
1131 IFAFREE((&oia->ia_ifa));
1132/* xxx
1133 rtrequest(RTM_DELETE,
1134 (struct sockaddr *)&ia->ia_addr,
1135 (struct sockaddr *)0
1136 (struct sockaddr *)&ia->ia_prefixmask,
1137 RTF_UP|RTF_CLONING,
1138 (struct rtentry **)0);
1139*/
1140 return 0;
1141}
1142
1143int
1144in6_init_prefix_ltimes(struct nd_prefix *ndpr)
1145{
1146
1147 /* check if preferred lifetime > valid lifetime */
1148 if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
1149 log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
1150 "(%d) is greater than valid lifetime(%d)\n",
1151 (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime);
1152 return (EINVAL);
1153 }
1154 if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
1155 ndpr->ndpr_preferred = 0;
1156 else
1157 ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
1158 if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
1159 ndpr->ndpr_expire = 0;
1160 else
1161 ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
1162
1163 return 0;
1164}
1165
1166static void
1167in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
1168{
1169
1170 /* init ia6t_expire */
1171 if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
1172 lt6->ia6t_expire = 0;
1173 else {
1174 lt6->ia6t_expire = time_second;
1175 lt6->ia6t_expire += lt6->ia6t_vltime;
1176 }
1177 /* init ia6t_preferred */
1178 if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
1179 lt6->ia6t_preferred = 0;
1180 else {
1181 lt6->ia6t_preferred = time_second;
1182 lt6->ia6t_preferred += lt6->ia6t_pltime;
1183 }
1184 /* ensure addr lifetime <= prefix lifetime */
1185 if (new->ndpr_expire && lt6->ia6t_expire &&
1186 new->ndpr_expire < lt6->ia6t_expire)
1187 lt6->ia6t_expire = new->ndpr_expire;
1188 if (new->ndpr_preferred && lt6->ia6t_preferred
1189 && new->ndpr_preferred < lt6->ia6t_preferred)
1190 lt6->ia6t_preferred = new->ndpr_preferred;
1191}
1192
1193/*
1194 * Delete all the routing table entries that use the specified gateway.
1195 * XXX: this function causes search through all entries of routing table, so
1196 * it shouldn't be called when acting as a router.
1197 */
1198void
1199rt6_flush(gateway, ifp)
1200 struct in6_addr *gateway;
1201 struct ifnet *ifp;
1202{
1203 struct radix_node_head *rnh = rt_tables[AF_INET6];
1204 int s = splnet();
1205
1206 /* We'll care only link-local addresses */
1207 if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
1208 splx(s);
1209 return;
1210 }
1211 /* XXX: hack for KAME's link-local address kludge */
1212 gateway->s6_addr16[1] = htons(ifp->if_index);
1213
1214 rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
1215 splx(s);
1216}
1217
1218static int
1219rt6_deleteroute(rn, arg)
1220 struct radix_node *rn;
1221 void *arg;
1222{
1223#define SIN6(s) ((struct sockaddr_in6 *)s)
1224 struct rtentry *rt = (struct rtentry *)rn;
1225 struct in6_addr *gate = (struct in6_addr *)arg;
1226
1227 if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
1228 return(0);
1229
1230 if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
1231 return(0);
1232
1233 /*
1234 * We delete only host route. This means, in particular, we don't
1235 * delete default route.
1236 */
1237 if ((rt->rt_flags & RTF_HOST) == 0)
1238 return(0);
1239
1240 return(rtrequest(RTM_DELETE, rt_key(rt),
1241 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
1242#undef SIN6
1243}