]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* $KAME: mip6_md.c,v 1.14 2000/03/25 07:23:53 sumikawa Exp $ */ |
2 | ||
3 | /* | |
4 | * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the project nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | |
30 | */ | |
31 | ||
32 | /* | |
33 | * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB | |
34 | * All rights reserved. | |
35 | * | |
36 | * Author: Mattias Pettersson <mattias.pettersson@era.ericsson.se> | |
37 | * | |
38 | */ | |
39 | ||
40 | #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) | |
41 | #include "opt_inet.h" | |
42 | #endif | |
43 | ||
44 | /* | |
45 | * Mobile IPv6 Movement Detection for Mobile Nodes | |
46 | */ | |
47 | #include <sys/param.h> | |
48 | #include <sys/malloc.h> | |
49 | #include <sys/mbuf.h> | |
50 | #include <sys/socket.h> | |
51 | #include <sys/sockio.h> | |
52 | #include <sys/syslog.h> | |
53 | #include <sys/systm.h> | |
54 | #include <sys/kernel.h> | |
55 | #include <sys/domain.h> | |
56 | #include <sys/protosw.h> | |
57 | ||
58 | #include <net/if.h> | |
59 | #include <net/if_types.h> | |
60 | #include <net/route.h> | |
61 | ||
62 | #include <netinet/in.h> | |
63 | #include <netinet/ip6.h> | |
64 | #include <netinet6/in6_var.h> | |
65 | #include <netinet6/ip6_var.h> | |
66 | #include <netinet6/ip6protosw.h> | |
67 | #include <netinet6/nd6.h> | |
68 | #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) | |
69 | #include <netinet/in_pcb.h> | |
70 | #endif | |
71 | #include <netinet6/in6_pcb.h> | |
72 | #include <netinet6/mip6.h> | |
73 | ||
74 | #include <net/net_osdep.h> | |
75 | ||
76 | struct nd_prefix *mip6_home_prefix; | |
77 | struct nd_prefix *mip6_primary_prefix; | |
78 | struct in6_addr mip6_primary_defrtr; | |
79 | int mip6_md_state = MIP6_MD_UNDEFINED; | |
80 | /* | |
81 | * Mobile IPv6 Home Address route state for the Mobile Node. | |
82 | * route_state NET == MD_HOME == network route. | |
83 | * route_state HOST == MD_FOREIGN|UNDEFINED == host route. | |
84 | */ | |
85 | int mip6_route_state = MIP6_ROUTE_NET; /* According to MD_UNDEFINED state. */ | |
86 | int mip6_max_lost_advints = MIP6_MAX_LOST_ADVINTS; | |
87 | int mip6_nd6_delay = 0; | |
88 | int mip6_nd6_umaxtries = 0; | |
89 | ||
90 | ||
91 | /* | |
92 | ****************************************************************************** | |
93 | * Function: mip6_tell_em | |
94 | * Description: Print state change and tell event-state machine. | |
95 | * Ret value: - | |
96 | ****************************************************************************** | |
97 | */ | |
98 | static void | |
99 | mip6_tell_em(int state, | |
100 | struct nd_prefix *hp, | |
101 | struct nd_prefix *pp, | |
102 | struct nd_defrouter *dr) | |
103 | { | |
104 | #if MIP6_DEBUG | |
105 | mip6_debug("\nNew state: "); | |
106 | switch (state) { | |
107 | case MIP6_MD_HOME: | |
108 | mip6_debug("HOME!\n"); | |
109 | break; | |
110 | case MIP6_MD_FOREIGN: | |
111 | mip6_debug("FOREIGN!\n"); | |
112 | break; | |
113 | case MIP6_MD_UNDEFINED: | |
114 | mip6_debug("UNDEFINED!\n"); | |
115 | break; | |
116 | } | |
117 | mip6_debug("Home Prefix = %s\n", hp ? ip6_sprintf( | |
118 | &hp->ndpr_prefix.sin6_addr) : "NULL"); | |
119 | mip6_debug("Primary Prefix = %s\n", pp ? ip6_sprintf( | |
120 | &pp->ndpr_prefix.sin6_addr) : "NULL"); | |
121 | mip6_debug("Default Router = %s\n", dr ? ip6_sprintf( | |
122 | &dr->rtaddr) : "NULL"); | |
123 | #endif | |
124 | mip6_new_defrtr(state, hp, pp, dr); | |
125 | } | |
126 | ||
127 | ||
128 | /* | |
129 | ****************************************************************************** | |
130 | * Function: mip6_md_init | |
131 | * Description: Scan through the Event-State Machine List. | |
132 | * Create a Home Prefix and a Home Address for the Mobile Node | |
133 | * and add it to the prefix list (or just update it if the prefix | |
134 | * is already existing). Detect which initial Movement Detection | |
135 | * state we are in (HOME, FOREIGN or UNDEFINED) and tell the | |
136 | * event-state machine. | |
137 | * Ret value: - | |
138 | ****************************************************************************** | |
139 | */ | |
140 | void | |
141 | mip6_md_init() | |
142 | { | |
143 | struct nd_prefix *pr, *existing_pr = NULL; | |
144 | struct nd_defrouter *dr; | |
145 | struct in6_ifaddr *ia; | |
146 | struct mip6_esm *esp; /* Entry in the Event State machine list */ | |
147 | int i, s, error; | |
148 | ||
149 | for (esp = mip6_esmq; esp; esp = esp->next) { | |
150 | ||
151 | /* | |
152 | * Add the home prefix statically to the prefix list. | |
153 | * Code taken from prelist_update(), prelist_add() and | |
154 | * in6_ifadd(). | |
155 | */ | |
156 | pr = (struct nd_prefix *)MALLOC(sizeof(*pr), M_TEMP, M_WAITOK); | |
157 | if (pr == NULL) { | |
158 | log(LOG_ERR, "mip6_md_init: no mem for home prefix\n"); | |
159 | } else { | |
160 | bzero(pr, sizeof(*pr)); | |
161 | ||
162 | pr->ndpr_ifp = esp->ifp; | |
163 | pr->ndpr_plen = esp->prefix_len; | |
164 | ||
165 | pr->ndpr_prefix.sin6_family = AF_INET6; | |
166 | pr->ndpr_prefix.sin6_len = sizeof(pr->ndpr_prefix); | |
167 | pr->ndpr_prefix.sin6_addr = esp->home_addr; | |
168 | in6_prefixlen2mask(&pr->ndpr_mask, pr->ndpr_plen); | |
169 | ||
170 | /* make prefix in the canonical form */ | |
171 | for (i = 0; i < 4; i++) | |
172 | pr->ndpr_prefix.sin6_addr.s6_addr32[i] &= | |
173 | pr->ndpr_mask.s6_addr32[i]; | |
174 | ||
175 | /* TODO: link into interface prefix list */ | |
176 | ||
177 | /* Default settings for unadvertised home prefix */ | |
178 | pr->ndpr_raf_onlink = 0; | |
179 | pr->ndpr_raf_auto = 0; | |
180 | ||
181 | /* | |
182 | * If home prefix already exists in prefix list, use that | |
183 | * entry instead. | |
184 | */ | |
185 | if ( (existing_pr = prefix_lookup(pr)) ) { | |
186 | _FREE(pr, M_TEMP); | |
187 | pr = existing_pr; | |
188 | } | |
189 | ||
190 | /* Update (or set) certain fields in the home prefix */ | |
191 | pr->ndpr_vltime = ND6_INFINITE_LIFETIME; | |
192 | pr->ndpr_pltime = ND6_INFINITE_LIFETIME; | |
193 | ||
194 | if (in6_init_prefix_ltimes(pr)) { | |
195 | log(LOG_ERR, "mip6_md_init: bad lifetimes\n"); | |
196 | goto failure; | |
197 | } | |
198 | ||
199 | ||
200 | s = splnet(); /* Must be before goto statement */ | |
201 | ||
202 | if (existing_pr != NULL) { | |
203 | #if MIP6_DEBUG | |
204 | mip6_debug("mip6_md_init: Home prefix already exists, " | |
205 | "no need to create new prefix.\n"); | |
206 | #endif | |
207 | goto skip_initialization; | |
208 | } | |
209 | ||
210 | /* New prefix, fix all initialization. */ | |
211 | ||
212 | pr->ndpr_statef_onlink = 0; /* Should be 0 since there | |
213 | are no adv rtrs for | |
214 | this pfx yet */ | |
215 | LIST_INIT(&pr->ndpr_advrtrs); | |
216 | ||
217 | skip_initialization: | |
218 | ||
219 | /* If an autoconfigured address exists for pr, delete it */ | |
220 | if (existing_pr != NULL) { | |
221 | if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) { | |
222 | ia = in6ifa_ifpwithaddr(pr->ndpr_ifp, | |
223 | &pr->ndpr_addr); | |
224 | if (ia) { | |
225 | error = mip6_delete_ifaddr( | |
226 | &ia->ia_addr.sin6_addr, | |
227 | pr->ndpr_ifp); | |
228 | if (error) | |
229 | printf("%s: address assignment" | |
230 | " error " | |
231 | "(errno = %d).\n", | |
232 | __FUNCTION__, error); | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | pr->ndpr_addr = esp->home_addr; | |
238 | ||
239 | if (existing_pr == NULL) { | |
240 | /* link ndpr_entry to nd_prefix list */ | |
241 | LIST_INSERT_HEAD(&nd_prefix, pr, ndpr_entry); | |
242 | } | |
243 | ||
244 | splx(s); | |
245 | } | |
246 | if (esp != mip6_esmq) { | |
247 | #if MIP6_DEBUG | |
248 | mip6_debug("%s: Only supporting one home address in this " | |
249 | "version.\n", __FUNCTION__); | |
250 | #endif | |
251 | } | |
252 | mip6_home_prefix = pr; | |
253 | ||
254 | dr = TAILQ_FIRST(&nd_defrouter); | |
255 | /* XXXYYY Add check for probably reachable router here as well. Mattias */ | |
256 | if (pr->ndpr_advrtrs.lh_first && dr && | |
257 | pfxrtr_lookup(pr, dr)) { | |
258 | /* If we have home pfxrtrs and defrtr is one of these, then | |
259 | we're home. */ | |
260 | mip6_md_state = MIP6_MD_HOME; | |
261 | /* XXX BUG ALERT: missing curly brace? */ | |
262 | if ((error = mip6_add_ifaddr(&pr->ndpr_addr, pr->ndpr_ifp, 64, | |
263 | IN6_IFF_NODAD)) != 0) | |
264 | printf("%s: address assignment error (errno = %d).\n", | |
265 | __FUNCTION__, error); | |
266 | mip6_route_state = MIP6_ROUTE_NET; | |
267 | mip6_primary_prefix = mip6_home_prefix; | |
268 | mip6_primary_defrtr = dr->rtaddr; | |
269 | ||
270 | mip6_tell_em(MIP6_MD_HOME, mip6_home_prefix, NULL, dr); | |
271 | } | |
272 | else { | |
273 | if (dr) { | |
274 | mip6_md_state = MIP6_MD_FOREIGN; | |
275 | if ((error = mip6_add_ifaddr( | |
276 | &pr->ndpr_addr, pr->ndpr_ifp, 128, | |
277 | IN6_IFF_NODAD)) != 0) | |
278 | printf("%s: address assignment error " | |
279 | "(errno = %d).\n", | |
280 | __FUNCTION__, error); | |
281 | mip6_route_state = MIP6_ROUTE_HOST; | |
282 | ||
283 | for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { | |
284 | if ((pfxrtr_lookup(pr, dr) != NULL) && | |
285 | !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)&& | |
286 | !IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) && | |
287 | !IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { | |
288 | break; | |
289 | } | |
290 | } | |
291 | if (pr) { | |
292 | mip6_primary_prefix = pr; | |
293 | mip6_primary_defrtr = dr->rtaddr; | |
294 | mip6_tell_em(MIP6_MD_FOREIGN, mip6_home_prefix, | |
295 | pr, dr); | |
296 | } | |
297 | else { | |
298 | #if MIP6_DEBUG | |
299 | mip6_debug("%s: At FOREIGN, but no primary " | |
300 | "prefix found!\n", __FUNCTION__); | |
301 | #endif | |
302 | goto undefined; | |
303 | } | |
304 | } | |
305 | else { | |
306 | undefined: | |
307 | mip6_md_state = MIP6_MD_UNDEFINED; | |
308 | if ((error = mip6_add_ifaddr(&pr->ndpr_addr, | |
309 | pr->ndpr_ifp, 64, | |
310 | IN6_IFF_NODAD)) != 0) | |
311 | printf("%s: address assignment error " | |
312 | "(errno = %d).\n", __FUNCTION__, error); | |
313 | mip6_route_state = MIP6_ROUTE_NET; | |
314 | mip6_primary_defrtr = in6addr_any; | |
315 | mip6_primary_prefix = NULL; | |
316 | ||
317 | mip6_tell_em(MIP6_MD_UNDEFINED, mip6_home_prefix, | |
318 | NULL, NULL); | |
319 | } | |
320 | } | |
321 | failure: | |
322 | } | |
323 | } | |
324 | ||
325 | ||
326 | /* | |
327 | ****************************************************************************** | |
328 | * Function: mip6_select_defrtr | |
329 | * Description: Usually called as an extension to defrtrlist_del() when the | |
330 | * previous primary default router times out. Tries to select a | |
331 | * new default router that announces the Home Prefix if available. | |
332 | * Manages the Movement Detection state transitions and | |
333 | * reconfigures the Home Address with host or network route. | |
334 | * Finally informs the event-state machine about any transitions | |
335 | * and new default routers. | |
336 | * Ret value: - | |
337 | ****************************************************************************** | |
338 | */ | |
339 | void | |
340 | mip6_select_defrtr() | |
341 | { | |
342 | struct nd_prefix *pr = NULL/*, *prev_primary_prefix*/; | |
343 | struct nd_defrouter *dr, anydr; | |
344 | struct nd_pfxrouter *pfxrtr; | |
345 | struct rtentry *rt = NULL; | |
346 | struct llinfo_nd6 *ln = NULL; | |
347 | int s = splnet(), error, state; | |
348 | ||
349 | pr = mip6_primary_prefix; | |
350 | /* Only for sanity check */ | |
351 | dr = mip6_primary_prefix ? | |
352 | defrouter_lookup(&mip6_primary_defrtr, | |
353 | mip6_primary_prefix->ndpr_ifp) : NULL; | |
354 | state = mip6_md_state; | |
355 | ||
356 | #if MIP6_DEBUG | |
357 | mip6_debug("\n"); | |
358 | #endif | |
359 | #if MIP6_DEBUG | |
360 | mip6_debug("%s: previous primary dr = %s.\n", __FUNCTION__, | |
361 | ip6_sprintf(&mip6_primary_defrtr)); | |
362 | mip6_debug("%s: dr = %s.\n", __FUNCTION__, | |
363 | dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); | |
364 | #endif | |
365 | ||
366 | if ( (mip6_md_state == MIP6_MD_HOME) || | |
367 | (mip6_md_state == MIP6_MD_UNDEFINED) ) { | |
368 | if ((pr = mip6_home_prefix) == NULL){ | |
369 | log(LOG_ERR, "mip6_select_defrtr: no home prefix\n"); | |
370 | splx(s); | |
371 | return; | |
372 | } | |
373 | ||
374 | if ((pfxrtr = find_pfxlist_reachable_router(pr)) != NULL) { | |
375 | #if MIP6_DEBUG | |
376 | mip6_debug("%s: there are (reachable) pfxrtrs at " | |
377 | "home.\n", __FUNCTION__); | |
378 | #endif | |
379 | if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) && | |
380 | !(IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) || | |
381 | IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr))) { | |
382 | ||
383 | /* Pick first reachable pfxrtr. */ | |
384 | state = MIP6_MD_HOME; | |
385 | ||
386 | dr = pfxrtr->router; | |
387 | ||
388 | /* Place dr first since its prim. */ | |
389 | TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); | |
390 | TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry); | |
391 | ||
392 | #if MIP6_DEBUG | |
393 | mip6_debug("%s: picking %s as default router " | |
394 | "on home subnet.\n", | |
395 | __FUNCTION__, | |
396 | ip6_sprintf(&(dr->rtaddr))); | |
397 | #endif | |
398 | goto found; | |
399 | } | |
400 | } | |
401 | ||
402 | if (pr->ndpr_advrtrs.lh_first == NULL) { | |
403 | #if MIP6_DEBUG | |
404 | mip6_debug("%s: there are no pfxrtrs at home, trying " | |
405 | "non-home instead.\n", __FUNCTION__); | |
406 | #endif | |
407 | } | |
408 | ||
409 | /* | |
410 | * No home prefix defrtr found, just drop through and pick | |
411 | * one by the ordinary procedure below. | |
412 | */ | |
413 | #if MIP6_DEBUG | |
414 | mip6_debug("%s: no home prefix router found.\n", __FUNCTION__); | |
415 | #endif | |
416 | } | |
417 | ||
418 | /* | |
419 | * Go through the Default Router List in search for a (probably) | |
420 | * reachable router that advertises a prefix and with an associated | |
421 | * Care-of Address. This is a merge from defrouter_select(). | |
422 | */ | |
423 | if (TAILQ_FIRST(&nd_defrouter)) { | |
424 | for (dr = TAILQ_FIRST(&nd_defrouter); dr; | |
425 | dr = TAILQ_NEXT(dr, dr_entry)) { | |
426 | ||
427 | if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && | |
428 | (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && | |
429 | ND6_IS_LLINFO_PROBREACH(ln)) { | |
430 | ||
431 | /* | |
432 | * Find a Care-of Address from a prefix | |
433 | * announced by this router. | |
434 | */ | |
435 | for (pr = nd_prefix.lh_first; pr; | |
436 | pr = pr->ndpr_next) { | |
437 | if ((pfxrtr_lookup(pr, dr) != NULL) && | |
438 | !IN6_IS_ADDR_UNSPECIFIED( | |
439 | &pr->ndpr_addr) && | |
440 | !IN6_IS_ADDR_MULTICAST( | |
441 | &pr->ndpr_addr) && | |
442 | !IN6_IS_ADDR_LINKLOCAL( | |
443 | &pr->ndpr_addr)) { | |
444 | state = MIP6_MD_FOREIGN; | |
445 | ||
446 | #if MIP6_DEBUG | |
447 | mip6_debug("%s: new probably reachable defrtr %s on foreign subnet selected.\n", __FUNCTION__, ip6_sprintf(&dr->rtaddr)); | |
448 | #endif | |
449 | ||
450 | /* | |
451 | * Place dr first since | |
452 | * its prim. | |
453 | */ | |
454 | TAILQ_REMOVE(&nd_defrouter, | |
455 | dr, dr_entry); | |
456 | TAILQ_INSERT_HEAD( | |
457 | &nd_defrouter, | |
458 | dr, dr_entry); | |
459 | ||
460 | goto found; | |
461 | } | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
466 | /* | |
467 | * No (probably) reachable router found that matched our requirements. | |
468 | * Go through the Default Router List again in search for any | |
469 | * router that advertises a prefix and with an associated | |
470 | * Care-of Address. This is a merge from defrouter_select(). | |
471 | */ | |
472 | for(dr = TAILQ_FIRST(&nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)){ | |
473 | /* | |
474 | * Find a Care-of Address from a prefix announced by | |
475 | * this router. | |
476 | */ | |
477 | for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { | |
478 | if ((pfxrtr_lookup(pr, dr) != NULL) && | |
479 | !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)&& | |
480 | !IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) && | |
481 | !IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) { | |
482 | state = MIP6_MD_FOREIGN; | |
483 | ||
484 | #if MIP6_DEBUG | |
485 | mip6_debug("%s: new (unreachable?) " | |
486 | "defrtr %s on foreign subnet " | |
487 | "selected.\n", __FUNCTION__, | |
488 | ip6_sprintf(&dr->rtaddr)); | |
489 | #endif | |
490 | ||
491 | /* Place dr first since its prim. */ | |
492 | TAILQ_REMOVE(&nd_defrouter, dr, | |
493 | dr_entry); | |
494 | TAILQ_INSERT_HEAD(&nd_defrouter, dr, | |
495 | dr_entry); | |
496 | goto found; | |
497 | } | |
498 | } | |
499 | } | |
500 | } | |
501 | ||
502 | /* | |
503 | * No new defrtr or no with an associated Care-of Address found | |
504 | * -> State = undefined | |
505 | */ | |
506 | pr = NULL; | |
507 | dr = NULL; | |
508 | state = MIP6_MD_UNDEFINED; | |
509 | #if MIP6_DEBUG | |
510 | mip6_debug("%s: no new good defrtr found.\n", __FUNCTION__); | |
511 | #endif | |
512 | ||
513 | found: | |
514 | /* XXXYYY Hope this merge is correct now... Fingers crossed. Mattias */ | |
515 | #if MIP6_DEBUG | |
516 | mip6_debug("%s: found: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); | |
517 | #endif | |
518 | if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { | |
519 | #if MIP6_DEBUG | |
520 | mip6_debug("%s: TAILQ: dr = %s.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); | |
521 | #endif | |
522 | /* | |
523 | * De-install the previous default gateway and install | |
524 | * a new one. | |
525 | * Note that if there is no reachable router in the list, | |
526 | * the head entry will be used anyway. | |
527 | * XXX: do we have to check the current routing table entry? | |
528 | */ | |
529 | bzero(&anydr, sizeof(anydr)); | |
530 | defrouter_delreq(&anydr, 0); | |
531 | defrouter_addreq(dr); | |
532 | } | |
533 | else { | |
534 | /* | |
535 | * The Default Router List is empty, so install the default | |
536 | * route to an inteface. | |
537 | * XXX: The specification does not say this mechanism should | |
538 | * be restricted to hosts, but this would be not useful | |
539 | * (even harmful) for routers. | |
540 | */ | |
541 | if (!ip6_forwarding) { | |
542 | /* | |
543 | * De-install the current default route | |
544 | * in advance. | |
545 | */ | |
546 | bzero(&anydr, sizeof(anydr)); | |
547 | defrouter_delreq(&anydr, 0); | |
548 | if (nd6_defifp) { | |
549 | /* | |
550 | * Install a route to the default interface | |
551 | * as default route. | |
552 | */ | |
553 | defrouter_addifreq(nd6_defifp); | |
554 | } | |
555 | else /* noisy log? */ | |
556 | log(LOG_INFO, "defrouter_select: " | |
557 | "there's no default router and no default" | |
558 | " interface\n"); | |
559 | } | |
560 | } | |
561 | ||
562 | ||
563 | /* | |
564 | * If we grab a (unreachable) defrouter that actually is a home | |
565 | * prefix router, we should consider ourself at home rather than | |
566 | * default foreign. | |
567 | */ | |
568 | if (dr) { | |
569 | struct nd_pfxrouter *pfxrtr; | |
570 | ||
571 | pfxrtr = pfxrtr_lookup(mip6_home_prefix, dr); | |
572 | if (pfxrtr && dr == pfxrtr->router) { | |
573 | #if MIP6_DEBUG | |
574 | mip6_debug("%s: dr = %s is obviously a home pfxrtr.\n", __FUNCTION__, dr ? ip6_sprintf(&dr->rtaddr) : "NULL"); | |
575 | #endif | |
576 | state = MIP6_MD_HOME; | |
577 | pr = mip6_home_prefix; | |
578 | } | |
579 | } | |
580 | ||
581 | /* | |
582 | * First case: same router as last time. | |
583 | * Second case: coming from UNDEFINED, we might have had a router, but | |
584 | * we didn't have a care-of address. | |
585 | */ | |
586 | if (IN6_ARE_ADDR_EQUAL(&mip6_primary_defrtr, | |
587 | (dr ? &dr->rtaddr : &in6addr_any)) && | |
588 | !(dr && mip6_primary_prefix == NULL)) { | |
589 | #if MIP6_DEBUG | |
590 | mip6_debug("%s: Warning: Primary default router hasn't " | |
591 | "changed! No action taken.\n", __FUNCTION__); | |
592 | #endif | |
593 | return; | |
594 | } | |
595 | ||
596 | /* | |
597 | * Switch between network and host route for the Home Address | |
598 | * in the following cases: | |
599 | * | |
600 | * md_state route_state | |
601 | * | |
602 | * HOME -> FOREIGN NET -> HOST | |
603 | * UNDEFINED -> FOREIGN NET -> HOST | |
604 | * FOREIGN -> HOME HOST -> NET | |
605 | * FOREIGN -> UNDEFINED HOST -> NET | |
606 | */ | |
607 | ||
608 | if ((state == MIP6_MD_HOME || state == MIP6_MD_UNDEFINED) | |
609 | && mip6_route_state == MIP6_ROUTE_HOST) { | |
610 | error = mip6_add_ifaddr(&mip6_home_prefix->ndpr_addr, | |
611 | mip6_home_prefix->ndpr_ifp, 64, | |
612 | IN6_IFF_NODAD); | |
613 | if (error) | |
614 | printf("%s: address assignment error (errno = %d).\n", | |
615 | __FUNCTION__, error); | |
616 | mip6_route_state = MIP6_ROUTE_NET; | |
617 | } | |
618 | else if (state == MIP6_MD_FOREIGN && | |
619 | mip6_route_state == MIP6_ROUTE_NET) { | |
620 | error = mip6_add_ifaddr(&mip6_home_prefix->ndpr_addr, | |
621 | mip6_home_prefix->ndpr_ifp, 128, | |
622 | IN6_IFF_NODAD); | |
623 | if (error) | |
624 | printf("%s: address assignment error (errno = %d).\n", | |
625 | __FUNCTION__, error); | |
626 | mip6_route_state = MIP6_ROUTE_HOST; | |
627 | } | |
628 | ||
629 | /* | |
630 | * If the Mobile Node has changed its primary prefix (probably due to | |
631 | * a move to a different subnet), clear the Neighbor Cache from entries | |
632 | * cloned from the previous primary prefix. This does not happen when | |
633 | * we keep the same prefix but change default router. | |
634 | */ | |
635 | #if MIP6_DEBUG | |
636 | mip6_debug("mip6_primary_prefix = %s\n", mip6_primary_prefix ? ip6_sprintf(&mip6_primary_prefix->ndpr_prefix.sin6_addr) : "NULL"); | |
637 | mip6_debug("pr = %s\n", pr ? ip6_sprintf(&pr->ndpr_prefix.sin6_addr) : "NULL"); | |
638 | #endif | |
639 | if (mip6_primary_prefix && (pr != mip6_primary_prefix)) { | |
640 | register struct llinfo_nd6 *ln; | |
641 | ||
642 | /* Taken from nd6_timer() */ | |
643 | ln = llinfo_nd6.ln_next; | |
644 | /* XXX BSD/OS separates this code -- itojun */ | |
645 | while (ln && ln != &llinfo_nd6) { | |
646 | struct rtentry *rt; | |
647 | struct ifnet *ifp; | |
648 | struct sockaddr_in6 *dst; | |
649 | struct llinfo_nd6 *next = ln->ln_next; | |
650 | ||
651 | if ((rt = ln->ln_rt) == NULL) { | |
652 | ln = next; | |
653 | continue; | |
654 | } | |
655 | if ((ifp = rt->rt_ifp) == NULL) { | |
656 | ln = next; | |
657 | continue; | |
658 | } | |
659 | dst = (struct sockaddr_in6 *)rt_key(rt); | |
660 | /* sanity check */ | |
661 | if (!rt) | |
662 | panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln); | |
663 | if (!dst) | |
664 | panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln); | |
665 | ||
666 | /* Skip if the address belongs to us */ | |
667 | if (ln->ln_expire == 0) { | |
668 | ln = next; | |
669 | continue; | |
670 | } | |
671 | ||
672 | #if MIP6_DEBUG | |
673 | mip6_debug("Checking neighbor %s\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL"); | |
674 | #endif | |
675 | if (in6_are_prefix_equal(&dst->sin6_addr, | |
676 | &mip6_primary_prefix-> | |
677 | ndpr_prefix.sin6_addr, | |
678 | mip6_primary_prefix-> | |
679 | ndpr_plen)) { | |
680 | ||
681 | /* Fake an INCOMPLETE neighbor that we're giving up */ | |
682 | struct mbuf *m = ln->ln_hold; | |
683 | if (m) { | |
684 | m_freem(m); | |
685 | } | |
686 | ln->ln_hold = NULL; | |
687 | ||
688 | #if MIP6_DEBUG | |
689 | mip6_debug("Deleting Neighbor %s.\n", | |
690 | ip6_sprintf(&(satosin6( | |
691 | rt_key(rt))->sin6_addr))); | |
692 | #endif | |
693 | ||
694 | #if IPSEC | |
695 | #ifndef __OpenBSD__ | |
696 | key_sa_routechange(rt_key(rt)); | |
697 | #endif | |
698 | #endif | |
699 | ||
700 | #if MIP6_DEBUG | |
701 | mip6_debug("Ref count = %d, now pfctlinput\n", | |
702 | rt->rt_refcnt); | |
703 | #endif | |
704 | ||
705 | /* New era */ | |
706 | pfctlinput(PRC_REDIRECT_HOST, rt_key(rt)); | |
707 | ||
708 | #if 0 | |
709 | #if MIP6_DEBUG | |
710 | mip6_debug("Ref count = %d, now rt_mip6msg\n", | |
711 | rt->rt_refcnt); | |
712 | #endif | |
713 | ||
714 | rt_mip6msg(RTM_DELETE, ifp, rt); /* Useless? */ | |
715 | #endif /* 0 */ | |
716 | #if MIP6_DEBUG | |
717 | mip6_debug("Ref count = %d, now RTM_DELETE\n", | |
718 | rt->rt_refcnt); | |
719 | #endif | |
720 | nd6_free(rt); | |
721 | } | |
722 | ln = next; | |
723 | /* | |
724 | * XXX Also remove the link-local addresses which | |
725 | * aren't ours? | |
726 | */ | |
727 | } | |
728 | ||
729 | ln = llinfo_nd6.ln_next; | |
730 | while (ln && ln != &llinfo_nd6) { | |
731 | struct rtentry *rt; | |
732 | struct ifnet *ifp; | |
733 | struct sockaddr_dl *sdl; | |
734 | struct sockaddr_in6 *dst; | |
735 | struct llinfo_nd6 *next = ln->ln_next; | |
736 | ||
737 | if ((rt = ln->ln_rt) == NULL) { | |
738 | ln = next; | |
739 | continue; | |
740 | } | |
741 | if ((ifp = rt->rt_ifp) == NULL) { | |
742 | ln = next; | |
743 | continue; | |
744 | } | |
745 | dst = (struct sockaddr_in6 *)rt_key(rt); | |
746 | /* sanity check */ | |
747 | if (!rt) | |
748 | panic("rt=0 in %s(ln=%p)\n", __FUNCTION__, ln); | |
749 | if (!dst) | |
750 | panic("dst=0 in %s(ln=%p)\n", __FUNCTION__, ln); | |
751 | ||
752 | /* Skip if the address belongs to us */ | |
753 | if (ln->ln_expire == 0) { | |
754 | ln = next; | |
755 | continue; | |
756 | } | |
757 | ||
758 | #if MIP6_DEBUG | |
759 | mip6_debug("Checking neighbor %s round 2\n", dst ? ip6_sprintf(&dst->sin6_addr) : "NULL"); | |
760 | #endif | |
761 | if (in6_are_prefix_equal(&dst->sin6_addr, | |
762 | &mip6_primary_prefix-> | |
763 | ndpr_prefix.sin6_addr, | |
764 | mip6_primary_prefix-> | |
765 | ndpr_plen)) { | |
766 | ||
767 | #if MIP6_DEBUG | |
768 | mip6_debug("Deleting Neighbor %s round 2.\n", | |
769 | ip6_sprintf(&(satosin6( | |
770 | rt_key(rt))->sin6_addr))); | |
771 | #endif | |
772 | ||
773 | #if MIP6_DEBUG | |
774 | mip6_debug("Ref count = %d, now RTM_DELETE\n", | |
775 | rt->rt_refcnt); | |
776 | #endif | |
777 | if (rt && rt->rt_gateway && | |
778 | rt->rt_gateway->sa_family == AF_LINK) { | |
779 | sdl = (struct sockaddr_dl *)rt-> | |
780 | rt_gateway; | |
781 | rtrequest(RTM_DELETE, rt_key(rt), | |
782 | (struct sockaddr *)0, | |
783 | rt_mask(rt), 0, | |
784 | (struct rtentry **)0); | |
785 | } | |
786 | } | |
787 | ln = next; | |
788 | /* | |
789 | * XXX Also remove the link-local addresses which | |
790 | * aren't ours? | |
791 | */ | |
792 | } | |
793 | } | |
794 | ||
795 | /* | |
796 | * Make decision permanent. | |
797 | * Primary Default Router is already set above. | |
798 | */ | |
799 | mip6_md_state = state; | |
800 | mip6_primary_prefix = pr; /* Other depend on this */ | |
801 | /* | |
802 | * Save rtaddr for next mip6_select_defrtr session. | |
803 | */ | |
804 | mip6_primary_defrtr = dr ? dr->rtaddr : in6addr_any; | |
805 | ||
806 | /* | |
807 | * Assumptions made below: | |
808 | * - dr is the chosen Default Router | |
809 | * - pr is the new Primary Prefix if we're not home | |
810 | */ | |
811 | switch (mip6_md_state) { | |
812 | case MIP6_MD_HOME: | |
813 | mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, dr); | |
814 | break; | |
815 | ||
816 | case MIP6_MD_FOREIGN: | |
817 | mip6_tell_em(mip6_md_state, mip6_home_prefix, pr, dr); | |
818 | break; | |
819 | case MIP6_MD_UNDEFINED: | |
820 | /* | |
821 | * Note: we pass dr == NULL, but we might have a Default | |
822 | * Router anyway, but with no prefix/Care-of Address | |
823 | * associated. | |
824 | */ | |
825 | mip6_tell_em(mip6_md_state, mip6_home_prefix, NULL, NULL); | |
826 | break; | |
827 | } | |
828 | splx(s); | |
829 | return; | |
830 | } | |
831 | ||
832 | ||
833 | /* | |
834 | ****************************************************************************** | |
835 | * Function: mip6_prelist_update(pr, dr) | |
836 | * Description: A hook to ND's prelist_update(). Checks if the Home Prefix | |
837 | * was announced and in that case tries to force the Mobile Node | |
838 | * to select that default router. If the Mobile Node was in | |
839 | * UNDEFINED state we want to select that router immediately, no | |
840 | * matter what the prefix was. | |
841 | * Ret value: - | |
842 | ****************************************************************************** | |
843 | */ | |
844 | void | |
845 | mip6_prelist_update(pr, dr) | |
846 | struct nd_prefix *pr; | |
847 | struct nd_defrouter *dr; | |
848 | { | |
849 | if (dr == NULL) { | |
850 | return; | |
851 | } | |
852 | if (pr == mip6_home_prefix) { | |
853 | /* It was the Home Prefix that was advertised. */ | |
854 | ||
855 | if (mip6_md_state != MIP6_MD_HOME) { | |
856 | /* | |
857 | * We're not home but here's a router advertising | |
858 | * our home prefix => make it primary defrtr and | |
859 | * we're home! | |
860 | */ | |
861 | #if MIP6_DEBUG | |
862 | mip6_debug("%s: returning home.\n", __FUNCTION__); | |
863 | #endif | |
864 | mip6_md_state = MIP6_MD_HOME; | |
865 | ||
866 | /* State must be home before call. */ | |
867 | if (TAILQ_FIRST(&nd_defrouter) != NULL) { | |
868 | defrouter_select(); | |
869 | } | |
870 | else { | |
871 | #if MIP6_DEBUG | |
872 | mip6_debug("%s: Undef -> Home: no previous " | |
873 | "router available " | |
874 | "at this stage.\n", __FUNCTION__); | |
875 | #endif | |
876 | /* XXXYYY or use defrouter_select()? */ | |
877 | mip6_select_defrtr(); | |
878 | } | |
879 | } | |
880 | } | |
881 | else if (mip6_md_state == MIP6_MD_UNDEFINED) { | |
882 | /* | |
883 | * Take care of transitions from UNDEFINED to FOREIGN, when the | |
884 | * prefix is already known. | |
885 | */ | |
886 | if (TAILQ_FIRST(&nd_defrouter) != NULL) { | |
887 | defrouter_select(); | |
888 | } | |
889 | else { | |
890 | #if MIP6_DEBUG | |
891 | mip6_debug("%s: Strange, no default router available" | |
892 | "at this stage.\n", __FUNCTION__); | |
893 | #endif | |
894 | /* XXXYYY or use defrouter_select()? */ | |
895 | mip6_select_defrtr(); | |
896 | } | |
897 | } | |
898 | } | |
899 | ||
900 | ||
901 | /* | |
902 | ****************************************************************************** | |
903 | * Function: mip6_eager_md() | |
904 | * Description: If eager Movement Detection is chosen, trim parameters to a | |
905 | * really fast hand-off. The disadvantage is that the detection | |
906 | * becomes very exposed to go into state UNDEFINED if one single | |
907 | * packet is lost. | |
908 | * Ret value: - | |
909 | ****************************************************************************** | |
910 | */ | |
911 | void | |
912 | mip6_eager_md(int enable) | |
913 | { | |
914 | mip6_config.eager_md = enable; | |
915 | if (enable) { | |
916 | mip6_max_lost_advints = 1; /* Aggressive values */ | |
917 | if (!mip6_nd6_delay) { | |
918 | mip6_nd6_delay = nd6_delay; /* Store */ | |
919 | mip6_nd6_umaxtries = nd6_umaxtries; /* Store */ | |
920 | } | |
921 | nd6_delay = 1; /* Aggressive values */ | |
922 | nd6_umaxtries = 1; | |
923 | } | |
924 | else { | |
925 | mip6_max_lost_advints = MIP6_MAX_LOST_ADVINTS; | |
926 | if (mip6_nd6_delay) { | |
927 | nd6_delay = mip6_nd6_delay; /* Restore */ | |
928 | nd6_umaxtries = mip6_nd6_umaxtries; /* Restore */ | |
929 | mip6_nd6_delay = 0; | |
930 | mip6_nd6_umaxtries = 0; | |
931 | } | |
932 | } | |
933 | } | |
934 | ||
935 | ||
936 | /* | |
937 | ****************************************************************************** | |
938 | * Function: mip6_expired_defrouter() | |
939 | * Description: If the field advint_expire (which is parallel to field | |
940 | * expire for router lifetime) times out, allow a small number | |
941 | * of lost Router Advertisements before doubting if this | |
942 | * particular default router is still reachable. | |
943 | * Ret value: - | |
944 | ****************************************************************************** | |
945 | */ | |
946 | void | |
947 | mip6_expired_defrouter(struct nd_defrouter *dr) | |
948 | { | |
949 | #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) | |
950 | long time_second = time.tv_sec; | |
951 | #endif | |
952 | ||
953 | if (!dr) | |
954 | return; | |
955 | ||
956 | if (dr->advint_expire && dr->advint_expire < time_second) { | |
957 | if (++(dr->advints_lost) < mip6_max_lost_advints) { | |
958 | /* advints_lost starts at 0. max = 1 (or more). */ | |
959 | dr->advint_expire = time_second + dr->advint / 1000; | |
960 | #if MIP6_DEBUG | |
961 | mip6_debug("Adv Int #%d lost from router %s.\n", | |
962 | dr->advints_lost, ip6_sprintf(&dr->rtaddr)); | |
963 | #endif | |
964 | } | |
965 | else { | |
966 | dr->advint_expire = 0; | |
967 | #if MIP6_DEBUG | |
968 | mip6_debug("Adv Int #%d lost from router %s.\n", | |
969 | dr->advints_lost, ip6_sprintf(&dr->rtaddr)); | |
970 | #endif | |
971 | mip6_probe_defrouter(dr); | |
972 | } | |
973 | } | |
974 | } | |
975 | ||
976 | ||
977 | /* | |
978 | ****************************************************************************** | |
979 | * Function: mip6_probe_defrouter() | |
980 | * Description: Probes a default router to see if it is still reachable. | |
981 | * Ordinary Neigbor Discovery routines (NUD) takes care of the | |
982 | * rest. Puts this router into ND state PROBE. | |
983 | * Ret value: - | |
984 | ****************************************************************************** | |
985 | */ | |
986 | void | |
987 | mip6_probe_defrouter(struct nd_defrouter *dr) | |
988 | { | |
989 | #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) | |
990 | long time_second = time.tv_sec; | |
991 | #endif | |
992 | struct rtentry *rt; | |
993 | struct llinfo_nd6 *ln; | |
994 | ||
995 | if (!dr) | |
996 | return; | |
997 | ||
998 | if (!(rt = nd6_lookup(&dr->rtaddr, 0, NULL))) | |
999 | return; | |
1000 | ||
1001 | if ((rt->rt_flags & RTF_GATEWAY) | |
1002 | || (rt->rt_flags & RTF_LLINFO) == 0 | |
1003 | || !rt->rt_llinfo | |
1004 | || !rt->rt_gateway | |
1005 | || rt->rt_gateway->sa_family != AF_LINK) { | |
1006 | /* This is not a host route. */ | |
1007 | return; | |
1008 | } | |
1009 | ||
1010 | ln = (struct llinfo_nd6 *)rt->rt_llinfo; | |
1011 | if ((ln->ln_state == ND6_LLINFO_INCOMPLETE) | |
1012 | || (ln->ln_state == ND6_LLINFO_PROBE) | |
1013 | || (ln->ln_state == ND6_LLINFO_WAITDELETE) | |
1014 | || (ln->ln_state == ND6_LLINFO_NOSTATE)) | |
1015 | return; | |
1016 | ||
1017 | /* Force state to PROBE, simulate DELAY->PROBE */ | |
1018 | ln->ln_asked = 1; | |
1019 | ln->ln_state = ND6_LLINFO_PROBE; | |
1020 | ln->ln_expire = time_second + | |
1021 | nd_ifinfo[rt->rt_ifp->if_index].retrans / 1000; | |
1022 | nd6_ns_output(rt->rt_ifp, &dr->rtaddr, &dr->rtaddr, | |
1023 | ln, 0); | |
1024 | #if MIP6_DEBUG | |
1025 | mip6_debug("Probing defrouter %s\n", ip6_sprintf(&dr->rtaddr)); | |
1026 | #endif | |
1027 | } | |
1028 | ||
1029 | ||
1030 | /* | |
1031 | ****************************************************************************** | |
1032 | * Function: mip6_probe_pfxrtrs() | |
1033 | * Description: If a new or previously detached prefix is heard, probe (NUD) | |
1034 | * all prefix routers on the current primary prefix in order to | |
1035 | * quickly detect if we have moved. This is only enabled in | |
1036 | * eager Movement Detection. | |
1037 | * Ret value: - | |
1038 | ****************************************************************************** | |
1039 | */ | |
1040 | void | |
1041 | mip6_probe_pfxrtrs() | |
1042 | { | |
1043 | struct nd_pfxrouter *pfr; | |
1044 | if (!mip6_config.eager_md) | |
1045 | return; | |
1046 | ||
1047 | if (!mip6_primary_prefix) | |
1048 | return; | |
1049 | ||
1050 | #if MIP6_DEBUG | |
1051 | mip6_debug("New or detached prefix received, probe old routers:\n"); | |
1052 | #endif | |
1053 | for (pfr = mip6_primary_prefix->ndpr_advrtrs.lh_first; | |
1054 | pfr; pfr = pfr->pfr_next) { | |
1055 | mip6_probe_defrouter(pfr->router); | |
1056 | } | |
1057 | } | |
1058 | ||
1059 | ||
1060 | /* | |
1061 | ****************************************************************************** | |
1062 | * Function: mip6_store_advint(ai, dr) | |
1063 | * Description: If Advertisement Interval option is available in Router | |
1064 | * Advertisements, keep a timer for this expiry parallel to the | |
1065 | * ordinary Router lifetime timer. | |
1066 | * Ret value: - | |
1067 | ****************************************************************************** | |
1068 | */ | |
1069 | void | |
1070 | mip6_store_advint(struct nd_opt_advint *ai, | |
1071 | struct nd_defrouter *dr) | |
1072 | { | |
1073 | #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__) | |
1074 | long time_second = time.tv_sec; | |
1075 | #endif | |
1076 | ||
1077 | /* Check the advertisement interval option */ | |
1078 | if (ai->nd_opt_int_len != 1) { | |
1079 | log(LOG_INFO, "%s: bad Advertisement Interval Option " | |
1080 | "length\n", __FUNCTION__); | |
1081 | } | |
1082 | else if (dr) { | |
1083 | dr->advint = ntohl(ai->nd_opt_int_interval); /* milliseconds */ | |
1084 | ||
1085 | /* Sorry for delay between reception and this setting */ | |
1086 | dr->advint_expire = time_second + dr->advint / 1000; | |
1087 | dr->advints_lost = 0; | |
1088 | } | |
1089 | } | |
1090 | ||
1091 | ||
1092 | /* | |
1093 | ****************************************************************************** | |
1094 | * Function: mip6_delete_ifaddr | |
1095 | * Description: Similar to "ifconfig <ifp> <addr> delete". | |
1096 | * Ret value: - | |
1097 | ****************************************************************************** | |
1098 | */ | |
1099 | int | |
1100 | mip6_delete_ifaddr(struct in6_addr *addr, | |
1101 | struct ifnet *ifp) | |
1102 | { | |
1103 | struct in6_aliasreq *ifra, dummy; | |
1104 | struct sockaddr_in6 *sa6; | |
1105 | struct in6_ifaddr *ia, *oia; | |
1106 | int s; | |
1107 | #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__) | |
1108 | struct ifaddr *ifa; | |
1109 | #endif | |
1110 | ||
1111 | bzero(&dummy, sizeof(dummy)); | |
1112 | ifra = &dummy; | |
1113 | ||
1114 | ifra->ifra_addr.sin6_len = sizeof(ifra->ifra_addr); | |
1115 | ifra->ifra_addr.sin6_family = AF_INET6; | |
1116 | ifra->ifra_addr.sin6_addr = *addr; | |
1117 | ||
1118 | sa6 = &ifra->ifra_addr; | |
1119 | ||
1120 | if (ifp == 0) | |
1121 | return(EOPNOTSUPP); | |
1122 | ||
1123 | s = splnet(); | |
1124 | ||
1125 | /* | |
1126 | * Code recycled from in6_control(). | |
1127 | */ | |
1128 | ||
1129 | /* | |
1130 | * Find address for this interface, if it exists. | |
1131 | */ | |
1132 | if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { | |
1133 | if (sa6->sin6_addr.s6_addr16[1] == 0) { | |
1134 | /* interface ID is not embedded by the user */ | |
1135 | sa6->sin6_addr.s6_addr16[1] = | |
1136 | htons(ifp->if_index); | |
1137 | } | |
1138 | else if (sa6->sin6_addr.s6_addr16[1] != | |
1139 | htons(ifp->if_index)) { | |
1140 | splx(s); | |
1141 | return(EINVAL); /* ifid is contradict */ | |
1142 | } | |
1143 | if (sa6->sin6_scope_id) { | |
1144 | if (sa6->sin6_scope_id != | |
1145 | (u_int32_t)ifp->if_index) { | |
1146 | splx(s); | |
1147 | return(EINVAL); | |
1148 | } | |
1149 | sa6->sin6_scope_id = 0; /* XXX: good way? */ | |
1150 | } | |
1151 | } | |
1152 | ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr); | |
1153 | ||
1154 | /* | |
1155 | * for IPv4, we look for existing in6_ifaddr here to allow | |
1156 | * "ifconfig if0 delete" to remove first IPv4 address on the | |
1157 | * interface. For IPv6, as the spec allow multiple interface | |
1158 | * address from the day one, we consider "remove the first one" | |
1159 | * semantics to be not preferrable. | |
1160 | */ | |
1161 | if (ia == 0) { | |
1162 | splx(s); | |
1163 | return(EADDRNOTAVAIL); | |
1164 | } | |
1165 | /* FALLTHROUGH */ | |
1166 | ||
1167 | if (ia == 0) { | |
1168 | ia = (struct in6_ifaddr *) | |
1169 | MALLOC(sizeof(*ia), M_IFADDR, M_WAITOK); | |
1170 | if (ia == NULL) { | |
1171 | splx(s); | |
1172 | return (ENOBUFS); | |
1173 | } | |
1174 | bzero((caddr_t)ia, sizeof(*ia)); | |
1175 | ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; | |
1176 | ia->ia_ifa.ifa_dstaddr | |
1177 | = (struct sockaddr *)&ia->ia_dstaddr; | |
1178 | ia->ia_ifa.ifa_netmask | |
1179 | = (struct sockaddr *)&ia->ia_prefixmask; | |
1180 | ||
1181 | ia->ia_ifp = ifp; | |
1182 | if ((oia = in6_ifaddr) != NULL) { | |
1183 | for ( ; oia->ia_next; oia = oia->ia_next) | |
1184 | continue; | |
1185 | oia->ia_next = ia; | |
1186 | } else | |
1187 | in6_ifaddr = ia; | |
1188 | ia->ia_ifa.ifa_refcnt++; | |
1189 | ||
1190 | #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined (__APPLE__) | |
1191 | if ((ifa = ifp->if_addrlist) != NULL) { | |
1192 | for ( ; ifa->ifa_next; ifa = ifa->ifa_next) | |
1193 | continue; | |
1194 | ifa->ifa_next = &ia->ia_ifa; | |
1195 | } else | |
1196 | ifp->if_addrlist = &ia->ia_ifa; | |
1197 | #else | |
1198 | TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, | |
1199 | ifa_list); | |
1200 | #endif | |
1201 | ia->ia_ifa.ifa_refcnt++; | |
1202 | } | |
1203 | ||
1204 | in6_purgeaddr(&ia->ia_ifa, ifp); | |
1205 | ||
1206 | splx(s); | |
1207 | return(0); | |
1208 | } | |
1209 | ||
1210 | ||
1211 | #if 0 | |
1212 | /* | |
1213 | ****************************************************************************** | |
1214 | * Function: mip6_delete_ifaddr | |
1215 | * Description: Similar to "ifconfig <ifp> <addr> delete". | |
1216 | * Ret value: - | |
1217 | ****************************************************************************** | |
1218 | */ | |
1219 | void | |
1220 | mip6_delete_ifaddr(struct in6_addr *addr, | |
1221 | struct ifnet *ifp) | |
1222 | { | |
1223 | struct in6_aliasreq in6_addreq; | |
1224 | int s, error = 0; | |
1225 | ||
1226 | bzero(&in6_addreq, sizeof(in6_addreq)); | |
1227 | in6_addreq.ifra_addr.sin6_len = sizeof(in6_addreq.ifra_addr); | |
1228 | in6_addreq.ifra_addr.sin6_family = AF_INET6; | |
1229 | in6_addreq.ifra_addr.sin6_addr = *addr; | |
1230 | ||
1231 | s =splnet(); | |
1232 | error = in6_control(NULL, SIOCDIFADDR_IN6, (caddr_t)&in6_addreq, ifp | |
1233 | #if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !define (__APPLE__) | |
1234 | , NULL | |
1235 | #endif | |
1236 | ); | |
1237 | splx(s); | |
1238 | if (error) { | |
1239 | #if MIP6_DEBUG | |
1240 | mip6_debug("%s: Attempt to delete addr %s failed.\n", __FUNCTION__, | |
1241 | ip6_sprintf(addr)); | |
1242 | #endif | |
1243 | } | |
1244 | } | |
1245 | #endif /* 0 */ | |
1246 | ||
1247 | struct nd_prefix * | |
1248 | mip6_get_home_prefix(void) | |
1249 | { | |
1250 | return(mip6_home_prefix); | |
1251 | } | |
1252 | ||
1253 | ||
1254 | int | |
1255 | mip6_get_md_state(void) | |
1256 | { | |
1257 | return(mip6_md_state); | |
1258 | } | |
1259 | ||
1260 | ||
1261 | /* | |
1262 | ****************************************************************************** | |
1263 | * Function: mip6_md_exit | |
1264 | * Description: Tidy up after the Mobile IPv6 Movement Detection. This is | |
1265 | * used when releasing the kernel module. The Home Prefix is | |
1266 | * deleted (even if we're home) since it's parameters might be | |
1267 | * way wrong. The Home Address is released as well. If at home, | |
1268 | * the prefix and address will be automagically configured as | |
1269 | * specified by ND. | |
1270 | * Ret value: - | |
1271 | ****************************************************************************** | |
1272 | */ | |
1273 | void | |
1274 | mip6_md_exit() | |
1275 | { | |
1276 | struct nd_prefix *pr; | |
1277 | ||
1278 | /* | |
1279 | * XXXYYY Should use mip6_esmq when multiple Home Addresses are | |
1280 | * supported. | |
1281 | */ | |
1282 | pr = mip6_home_prefix; | |
1283 | if (pr && pr->ndpr_ifp && !IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) { | |
1284 | mip6_delete_ifaddr(&pr->ndpr_addr, pr->ndpr_ifp); | |
1285 | ||
1286 | prelist_remove(pr); | |
1287 | mip6_home_prefix = NULL; | |
1288 | ||
1289 | #if MIP6_DEBUG | |
1290 | mip6_debug("Home Prefix and Home Address removed.\n"); | |
1291 | #endif | |
1292 | } | |
1293 | } |