]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/mip6_hooks.c
25a05263f8c86ff3d17285de0476e222ac6e44ee
[apple/xnu.git] / bsd / netinet6 / mip6_hooks.c
1 /* $KAME: mip6_hooks.c,v 1.8 2000/03/25 07:23:51 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 * Hesham Soliman <hesham.soliman@ericsson.com.au>
38 * Martti Kuparinen <martti.kuparinen@ericsson.com>
39 *
40 */
41 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
42 #include "opt_inet.h"
43 #endif
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48 #include <sys/proc.h>
49 #include <sys/mbuf.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <sys/kernel.h>
53 #include <net/if.h>
54 #include <net/if_types.h>
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
57 #include <netinet/ip6.h>
58 #include <netinet6/ip6_var.h>
59 #include <netinet6/nd6.h>
60 #include <netinet6/mip6.h>
61 #include <netinet6/mip6_common.h>
62
63 /*
64 * These are defined in sys/netinet6/
65 */
66 extern int (*mip6_store_dstopt_pre_hook)(struct mbuf *, u_int8_t *,
67 u_int8_t, u_int8_t);
68 extern int (*mip6_rec_ctrl_sig_hook)(struct mbuf *, int);
69 extern int (*mip6_new_packet_hook)(struct mbuf *);
70 extern int (*mip6_icmp6_input_hook)(struct mbuf *, int);
71 extern int (*mip6_output_hook)(struct mbuf *, struct ip6_pktopts **);
72 extern int (*mip6_rec_ra_hook)(struct mbuf *, int);
73
74 /* Home Agent-specific hooks */
75 extern struct in6_addr * (*mip6_global_addr_hook)(struct in6_addr *);
76 extern struct mip6_subopt_hal * (*mip6_hal_dynamic_hook)(struct in6_addr *);
77 extern int (*mip6_write_config_data_ha_hook)(u_long, void *);
78 extern int (*mip6_clear_config_data_ha_hook)(u_long, void *);
79 extern int (*mip6_enable_func_ha_hook)(u_long, caddr_t);
80 extern void (*mip6_icmp6_output_hook)(struct mbuf *);
81
82 /* Mobile Node-specific hooks */
83 extern int (*mip6_route_optimize_hook)(struct mbuf *);
84 extern void (*mip6_select_defrtr_hook)(void);
85 extern struct nd_prefix * (*mip6_get_home_prefix_hook)(void);
86 extern void (*mip6_prelist_update_hook)(struct nd_prefix *,
87 struct nd_defrouter *);
88 extern void (*mip6_expired_defrouter_hook)(struct nd_defrouter *);
89 extern void (*mip6_probe_pfxrtrs_hook)(void);
90 extern void (*mip6_store_advint_hook)(struct nd_opt_advint *,
91 struct nd_defrouter *);
92 extern int (*mip6_get_md_state_hook)(void);
93 extern int (*mip6_rec_ba_hook)(struct mbuf *, int);
94 extern int (*mip6_rec_br_hook)(struct mbuf *, int);
95 extern void (*mip6_stop_bu_hook)(struct in6_addr *);
96 extern int (*mip6_write_config_data_mn_hook)(u_long, void *);
97 extern int (*mip6_clear_config_data_mn_hook)(u_long, caddr_t);
98 extern int (*mip6_enable_func_mn_hook)(u_long, caddr_t);
99 extern void (*mip6_minus_a_case_hook)(struct nd_prefix *);
100 extern struct mip6_esm * (*mip6_esm_find_hook)(struct in6_addr *);
101
102
103 void
104 mip6_minus_a_case(struct nd_prefix *pr)
105 {
106 struct in6_addr addr;
107
108 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) ||
109 IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) ||
110 IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) {
111 return;
112 }
113
114 addr = in6addr_any;
115 mip6_esm_create(pr->ndpr_ifp, NULL, &addr, &pr->ndpr_addr,
116 pr->ndpr_plen, MIP6_STATE_UNDEF, PERMANENT, 0xFFFF);
117 #if MIP6_DEBUG
118 mip6_debug("Late Home Address %s found for autoconfig'd case. Starting"
119 " Mobile IPv6.\n", ip6_sprintf(&pr->ndpr_addr));
120 #endif
121 mip6_minus_a_case_hook = 0;
122 mip6_enable_hooks(MIP6_SPECIFIC_HOOKS);
123 mip6_md_init();
124 }
125
126 struct nd_prefix *
127 mip6_find_auto_home_addr(void)
128 {
129 struct nd_prefix *pr;
130 #if 0
131 struct in6_ifaddr *ia6;
132 #endif
133
134 for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
135 #if MIP6_DEBUG
136 mip6_debug("%s: scanning prefix %s (pr = %p)\n", __FUNCTION__,
137 ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr);
138 #endif
139 if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr) ||
140 IN6_IS_ADDR_MULTICAST(&pr->ndpr_addr) ||
141 IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_addr)) {
142 continue;
143 }
144 #if 0
145 ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
146 if (ia6 && (ia6->ia6_flags | IN6_IFF_DETACHED))
147 continue;
148 else
149 break; /* XXXYYY Remove in v2.0. */
150 #else
151 #if MIP6_DEBUG
152 mip6_debug("%s: skipping detached test on prefix %s "
153 "(pr = %p)\n", __FUNCTION__,
154 ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr);
155 #endif
156 break;
157 #endif
158 #if 0 /* XXXYYY Add in v2.0 */
159 for (pfxrtr = pr->ndpr_advrtrs.lh_first; pfxrtr;
160 pfxrtr = pfxrtr->pfr_next) {
161 if ((pfxrtr->router->flags & ND_RA_FLAG_HA)
162 == ND_RA_FLAG_HA)
163 break;
164 }
165 #endif /* 0 */
166 }
167 if (pr) {
168 #if MIP6_DEBUG
169 mip6_debug("Found an autoconfigured home address "
170 "immediately: %s\n", ip6_sprintf(&pr->ndpr_addr));
171 #endif
172 }
173 else {
174 #if MIP6_DEBUG
175 mip6_debug("Couldn't find an autoconfigured home address "
176 "immediately.\n");
177 #endif
178 }
179 return pr;
180 }
181
182
183 void
184 mip6_enable_hooks(int scope)
185 {
186 int s;
187
188 /*
189 * Activate the hook functions. After this some packets might come
190 * to the module...
191 * Note: mip6_minus_a_case_hook() is an exception and is not handled
192 * here.
193 */
194 s = splimp();
195 if (scope == MIP6_GENERIC_HOOKS) {
196 mip6_store_dstopt_pre_hook = mip6_store_dstopt_pre;
197 mip6_rec_ctrl_sig_hook = mip6_rec_ctrl_sig;
198 mip6_new_packet_hook = mip6_new_packet;
199 mip6_icmp6_input_hook = mip6_icmp6_input;
200 mip6_output_hook = mip6_output;
201 }
202
203 if (scope == MIP6_CONFIG_HOOKS) {
204 /* Activate Home Agent-specific hooks */
205 mip6_write_config_data_ha_hook = mip6_write_config_data_ha;
206 mip6_clear_config_data_ha_hook = mip6_clear_config_data_ha;
207 mip6_enable_func_ha_hook = mip6_enable_func_ha;
208
209 /* Activate Mobile Node-specific hooks */
210 mip6_write_config_data_mn_hook = mip6_write_config_data_mn;
211 mip6_clear_config_data_mn_hook = mip6_clear_config_data_mn;
212 mip6_enable_func_mn_hook = mip6_enable_func_mn;
213 }
214
215 if (scope == MIP6_SPECIFIC_HOOKS) {
216 /* Activate Home Agent-specific hooks */
217 if (MIP6_IS_HA_ACTIVE) {
218 mip6_rec_ra_hook = mip6_rec_raha;
219 mip6_global_addr_hook = mip6_global_addr;
220 mip6_hal_dynamic_hook = mip6_hal_dynamic;
221 mip6_icmp6_output_hook = mip6_icmp6_output;
222 }
223
224 /* Activate Mobile Node-specific hooks */
225 if (MIP6_IS_MN_ACTIVE) {
226 mip6_route_optimize_hook = mip6_route_optimize;
227 mip6_rec_ra_hook = mip6_rec_ramn;
228 mip6_select_defrtr_hook = mip6_select_defrtr;
229 mip6_get_home_prefix_hook = mip6_get_home_prefix;
230 mip6_prelist_update_hook = mip6_prelist_update;
231 mip6_expired_defrouter_hook = mip6_expired_defrouter;
232 mip6_probe_pfxrtrs_hook = mip6_probe_pfxrtrs;
233 mip6_store_advint_hook = mip6_store_advint;
234 mip6_get_md_state_hook = mip6_get_md_state;
235 mip6_rec_ba_hook = mip6_rec_ba;
236 mip6_rec_br_hook = mip6_rec_bu;
237 mip6_stop_bu_hook = mip6_stop_bu;
238 mip6_esm_find_hook = mip6_esm_find;
239 }
240 }
241 splx(s);
242 return;
243 }
244
245
246 void
247 mip6_disable_hooks(int scope)
248 {
249 int s;
250
251 /*
252 * Deactivate the hook functions. After this some packets might not
253 * come to the module...
254 */
255 s = splimp();
256
257 if (scope == MIP6_GENERIC_HOOKS) {
258 mip6_store_dstopt_pre_hook = 0;
259 mip6_rec_ctrl_sig_hook = 0;
260 mip6_new_packet_hook = 0;
261 mip6_icmp6_input_hook = 0;
262 mip6_output_hook = 0;
263 }
264
265 if (scope == MIP6_SPECIFIC_HOOKS) {
266
267 /* De-activate Home Agent-specific hooks */
268 if (MIP6_IS_HA_ACTIVE) {
269 mip6_rec_ra_hook = 0;
270 mip6_global_addr_hook = 0;
271 mip6_hal_dynamic_hook = 0;
272 mip6_write_config_data_ha_hook = 0;
273 mip6_clear_config_data_ha_hook = 0;
274 mip6_enable_func_ha_hook = 0;
275 }
276
277 /* De-activate Mobile Node-specific hooks */
278 if (MIP6_IS_MN_ACTIVE) {
279 mip6_route_optimize_hook = 0;
280 mip6_rec_ra_hook = 0;
281 mip6_select_defrtr_hook = 0;
282 mip6_get_home_prefix_hook = 0;
283 mip6_prelist_update_hook = 0;
284 mip6_expired_defrouter_hook = 0;
285 mip6_probe_pfxrtrs_hook = 0;
286 mip6_store_advint_hook = 0;
287 mip6_get_md_state_hook = 0;
288 mip6_rec_ba_hook = 0;
289 mip6_rec_br_hook = 0;
290 mip6_stop_bu_hook = 0;
291 mip6_write_config_data_mn_hook = 0;
292 mip6_clear_config_data_mn_hook = 0;
293 mip6_enable_func_mn_hook = 0;
294 mip6_esm_find_hook = 0;
295 mip6_minus_a_case_hook = 0;
296 }
297 }
298 splx(s);
299 return;
300 }
301
302
303 int
304 mip6_attach(int module)
305 {
306 /*
307 * Important that necessary settings have been done _before_ calling
308 * mip6_attach(), e.g. home address specified or autoconfig set.
309 * mip6config program sees to that.
310 */
311
312 /*
313 No support for modules here yet. XXXYYY
314
315 Old check (not valid any longer):
316 #if (defined(MIP6_MN) || defined (MIP6_HA) || defined(MIP6_MODULES))
317 */
318 if (mip6_module) {
319 #if MIP6_DEBUG
320 char *old = "?", *new = "?";
321 if (mip6_module == MIP6_HA_MODULE)
322 strcpy(old, "Home Agent");
323 if (mip6_module == MIP6_MN_MODULE)
324 strcpy(old, "Mobile Node");
325 if (module == MIP6_HA_MODULE)
326 strcpy(new, "Home Agent");
327 if (module == MIP6_MN_MODULE)
328 strcpy(new, "Mobile Node");
329
330 mip6_debug("Can't switch operation mode from %s to %s \n"
331 "- please deactivate first (\"mip6config -x\")\n",
332 old, new);
333 #endif
334 return EINVAL;
335 }
336
337 switch (module) {
338 case MIP6_HA_MODULE:
339 printf("%s: attach ha\n", __FUNCTION__); /* RM */
340 mip6_module = module;
341 mip6_ha_init();
342 break;
343
344 case MIP6_MN_MODULE:
345 printf("%s: attach mn\n", __FUNCTION__); /* RM */
346 mip6_module = module;
347 mip6_mn_init();
348 break;
349
350 default:
351 #if MIP6_DEBUG
352 mip6_debug("%s: illegal attach (module = %d)\n", __FUNCTION__,
353 module);
354 #endif
355 return EINVAL;
356 }
357
358 if (MIP6_IS_MN_ACTIVE) {
359 if(mip6_get_home_prefix_hook) /* Test arbitrary hook */
360 return 0;
361
362 /*
363 * If autoconfig state: find a global address to use as Home
364 * Address.
365 * - Take first available on any interface, else if no found:
366 * - Enable hook to wait for a Router Advertisement to give
367 * us one.
368 */
369 if (mip6_config.autoconfig) {
370 struct nd_prefix *pr;
371 struct in6_addr addr;
372
373 addr = in6addr_any;
374 if ((pr = mip6_find_auto_home_addr()) != NULL) {
375 mip6_esm_create(pr->ndpr_ifp, &addr, &addr,
376 &pr->ndpr_addr,pr->ndpr_plen,
377 MIP6_STATE_UNDEF, PERMANENT,
378 0xFFFF);
379 mip6_enable_hooks(MIP6_SPECIFIC_HOOKS);
380 mip6_md_init();
381 }
382 else {
383 #if MIP6_DEBUG
384 mip6_debug("Waiting for Router Advertisement "
385 "to give me an address.\n");
386 #endif
387 mip6_minus_a_case_hook = mip6_minus_a_case;
388 }
389 }
390 else {
391 /* Manual config */
392 mip6_enable_hooks(MIP6_SPECIFIC_HOOKS);
393 mip6_md_init();
394 }
395 }
396
397 if (MIP6_IS_HA_ACTIVE) {
398 /* XXXYYY Build anycast or is it done? */
399 mip6_enable_hooks(MIP6_SPECIFIC_HOOKS);
400 }
401 return 0;
402 }
403
404
405 int
406 mip6_release(void)
407 {
408 /* Disable the hooks */
409 mip6_disable_hooks(MIP6_SPECIFIC_HOOKS);
410
411 if (MIP6_IS_MN_ACTIVE) {
412 mip6_mn_exit();
413 mip6_md_exit();
414 }
415
416 if (MIP6_IS_HA_ACTIVE)
417 mip6_ha_exit();
418
419 /*
420 Correspondent Node functionality is never terminated.
421 mip6_disable_hooks(MIP6_GENERIC_HOOKS);
422 mip6_exit();
423 */
424
425 mip6_module = 0; /* Make HA or MN inactive */
426
427 return 0;
428 }