1 /* $KAME: mip6_mn.c,v 1.11 2000/03/18 03:05:42 itojun Exp $ */
4 * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
33 * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB
34 * All rights reserved.
36 * Author: Conny Larsson <conny.larsson@era.ericsson.se>
40 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
45 * Mobile IPv6 Mobile Nodes
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/malloc.h>
51 #include <sys/domain.h>
52 #include <sys/protosw.h>
53 #include <sys/socket.h>
54 #include <sys/errno.h>
56 #include <sys/kernel.h>
57 #include <sys/syslog.h>
58 #include <sys/ioccom.h>
60 #include <net/if_types.h>
61 #include <net/route.h>
62 #include <netinet/in.h>
63 #include <netinet/in_var.h>
64 #include <netinet6/in6_var.h>
65 #include <netinet/ip6.h>
66 #include <netinet6/ip6_var.h>
67 #include <netinet/icmp6.h>
68 #include <netinet6/nd6.h>
69 #include <netinet6/mip6.h>
70 #include <netinet6/mip6_common.h>
72 /* Declaration of Global variables. */
73 struct mip6_bul
*mip6_bulq
= NULL
; /* First entry in Binding Update list */
74 struct mip6_esm
*mip6_esmq
= NULL
; /* List of event-state machines */
76 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
77 struct callout_handle mip6_timer_outqueue_handle
;
78 struct callout_handle mip6_timer_bul_handle
;
79 struct callout_handle mip6_timer_esm_handle
;
84 ##############################################################################
86 # INITIALIZATION AND EXIT FUNCTIONS
87 # These functions are executed when the MIPv6 code is activated and de-
88 # activated respectively.
90 ##############################################################################
94 ******************************************************************************
95 * Function: mip6_mn_init
96 * Description: Initialization of MIPv6 variables that must be initialized
97 * before the MN code is executed.
98 ******************************************************************************
103 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
104 /* Initialize handle for timer functions. */
105 callout_handle_init(&mip6_timer_outqueue_handle
);
106 callout_handle_init(&mip6_timer_bul_handle
);
107 callout_handle_init(&mip6_timer_esm_handle
);
110 printf("%s: MIP6 Mobile Node initialized\n", __FUNCTION__
);
116 ******************************************************************************
117 * Function: mip6_mn_exit
118 * Description: This function is called when the MN module is unloaded
119 * (relesed) from the kernel.
120 ******************************************************************************
125 struct mip6_output
*outp
, *outp_tmp
;
126 struct mip6_bul
*bulp
;
127 struct mip6_esm
*esp
;
130 /* Cancel outstanding timeout function calls. */
131 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
132 untimeout(mip6_timer_outqueue
, (void *)NULL
,
133 mip6_timer_outqueue_handle
);
134 untimeout(mip6_timer_bul
, (void *)NULL
, mip6_timer_bul_handle
);
135 untimeout(mip6_timer_esm
, (void *)NULL
, mip6_timer_esm_handle
);
137 untimeout(mip6_timer_outqueue
, (void *)NULL
);
138 untimeout(mip6_timer_bul
, (void *)NULL
);
139 untimeout(mip6_timer_esm
, (void *)NULL
);
142 /* Remove each entry in every queue. */
144 for (outp
= mip6_outq
; outp
;) {
148 _FREE(outp_tmp
->opt
, M_TEMP
);
149 if (outp_tmp
->subopt
)
150 _FREE(outp_tmp
->subopt
, M_TEMP
);
151 _FREE(outp_tmp
, M_TEMP
);
155 for (bulp
= mip6_bulq
; bulp
;)
156 bulp
= mip6_bul_delete(bulp
);
159 for (esp
= mip6_esmq
; esp
;)
160 esp
= mip6_esm_delete(esp
);
168 ##############################################################################
170 # RECEIVING FUNCTIONS
171 # These functions receives the incoming IPv6 packet and further processing of
172 # the packet depends on the content in the packet.
174 ##############################################################################
178 ******************************************************************************
179 * Function: mip6_new_defrtr
180 * Description: Called from the move detection algorithm when it has decided
181 * to change default router, i.e the network that we were
182 * connected to has changed.
184 ******************************************************************************
187 mip6_new_defrtr(state
, home_prefix
, prim_prefix
, def_router
)
188 int state
; /* State from move detection algorithm */
189 struct nd_prefix
*home_prefix
; /* Prefix for Home Address */
190 struct nd_prefix
*prim_prefix
; /* Prefix for primary care-of address */
191 struct nd_defrouter
*def_router
; /* New default router being used */
193 struct in6_addr
*home_addr
; /* Home Address for Mobile Node */
194 struct in6_addr
*prim_addr
; /* Primary Care-of Adress for MN */
195 struct mip6_esm
*esp
; /* Home address entry */
196 struct mip6_bul
*bulp
; /* Entry in the BU list */
197 struct ifaddr
*if_addr
; /* Interface address */
198 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
199 struct in6_addr ll_all_addr
; /* Link local all nodes address */
200 struct in6_addr old_coa
;
201 struct sockaddr_in6 sin6
;
202 u_int32_t lifetime
; /* Lifetime used in BU */
203 u_long na_flags
; /* Flags for NA message */
205 /* Check incoming parameters */
206 if (home_prefix
!= NULL
)
207 home_addr
= &home_prefix
->ndpr_addr
;
209 log(LOG_ERR
, "%s: No home address configured\n", __FUNCTION__
);
213 esp
= mip6_esm_find(home_addr
);
216 "%s: No event-state machine found\n", __FUNCTION__
);
220 if (prim_prefix
!= NULL
)
221 prim_addr
= &prim_prefix
->ndpr_addr
;
225 /* Decide how the mobile node has moved. */
226 if ((prim_prefix
== NULL
) && (state
== MIP6_MD_UNDEFINED
)) {
227 /* The Mobile Node is not connected to a network */
228 esp
->state
= MIP6_STATE_UNDEF
;
229 esp
->coa
= in6addr_any
;
230 if (esp
->ha_fn
!= NULL
) {
231 _FREE(esp
->ha_fn
, M_TEMP
);
234 if (mip6_tunnel(NULL
, NULL
, MIP6_TUNNEL_DEL
, MIP6_NODE_MN
,
237 } else if ((prim_prefix
== NULL
) && (state
== MIP6_MD_HOME
)) {
238 /* The Mobile Node is returning to the home link. Change the
239 parameters for the event-state machine. */
240 esp
->state
= MIP6_STATE_DEREG
;
242 esp
->coa
= esp
->home_addr
;
244 /* Send a BU de-registration to the Home Agent. */
245 bulp
= mip6_bul_find(NULL
, home_addr
);
247 /* The event-state machine was in state undefined. */
248 esp
->state
= MIP6_STATE_HOME
;
250 /* When returning home and no home registration exist
251 we can not assume the home address to be unique.
252 Perform DAD, but find the i/f address first. */
253 bzero(&sin6
, sizeof(struct sockaddr_in6
));
254 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
255 sin6
.sin6_family
= AF_INET6
;
256 sin6
.sin6_addr
= esp
->home_addr
;
258 if_addr
= ifa_ifwithaddr((struct sockaddr
*)&sin6
);
262 ((struct in6_ifaddr
*)if_addr
)->ia6_flags
|=
264 nd6_dad_start(if_addr
, NULL
);
268 bulp
->lifetime
= mip6_config
.hr_lifetime
;
269 bulp
->refreshtime
= bulp
->lifetime
;
270 bulp
->coa
= bulp
->bind_addr
;
272 bu_data
.prefix_len
= esp
->prefix_len
;
275 if (mip6_send_bu(bulp
, &bu_data
, NULL
) != 0)
278 /* Send a BU to the previous foreign network. */
279 if ( !IN6_IS_ADDR_UNSPECIFIED(&old_coa
) &&
280 (esp
->ha_fn
!= NULL
)) {
281 /* Find lifetime used for the BU to the def router. */
282 lifetime
= mip6_prefix_lifetime(&old_coa
);
283 lifetime
= min(lifetime
, MIP6_BU_LIFETIME_DEFRTR
);
285 /* Create a tunnel used by the MN to receive
286 incoming tunneled packets. */
287 if (mip6_tunnel(home_addr
, &esp
->ha_fn
->addr
,
289 MIP6_NODE_MN
, (void *)esp
))
292 mip6_send_bu2fn(&old_coa
, esp
->ha_fn
, home_addr
,
294 _FREE(esp
->ha_fn
, M_TEMP
);
298 /* The Mobile Node must send a Neighbor Advertisement to inform
299 other nodes that it has arrived back to its home network.
300 The first NA will be sent in the create function, the
301 remaining NAs are sent by the timer function. */
302 ll_all_addr
= in6addr_linklocal_allnodes
;
303 na_flags
= ND_NA_FLAG_OVERRIDE
;
304 mip6_na_create(home_addr
, &ll_all_addr
, home_addr
,
305 esp
->prefix_len
, na_flags
, 1);
306 } else if ((prim_prefix
!= NULL
) && (state
== MIP6_MD_FOREIGN
)) {
307 /* If no Home Agent Address exist. Build an anycast address */
308 if (IN6_IS_ADDR_UNSPECIFIED(&esp
->ha_hn
)) {
309 mip6_build_ha_anycast(&esp
->ha_hn
, &esp
->home_addr
,
311 if (IN6_IS_ADDR_UNSPECIFIED(&esp
->ha_hn
)) {
313 "%s: Could not create anycast address "
314 "for Mobile Node, wrong prefix length\n",
320 if ((esp
->state
== MIP6_STATE_UNDEF
) ||
321 (esp
->state
== MIP6_STATE_HOME
) ||
322 (esp
->state
== MIP6_STATE_DEREG
)) {
323 /* Home Network --> Foreign Network */
324 /* Update state information for the home address. */
325 esp
->state
= MIP6_STATE_NOTREG
;
326 esp
->coa
= *prim_addr
;
327 if (esp
->ha_fn
!= NULL
) {
328 _FREE(esp
->ha_fn
, M_TEMP
);
332 /* Find an existing or create a new BUL entry. */
333 bulp
= mip6_bul_find(NULL
, &esp
->home_addr
);
335 bulp
= mip6_bul_create(&esp
->ha_hn
,
338 mip6_config
.hr_lifetime
,
343 bulp
->coa
= *prim_addr
;
344 bulp
->lifetime
= mip6_config
.hr_lifetime
;
345 bulp
->refreshtime
= bulp
->lifetime
;
348 /* Send a BU registration to the Home Agent. */
349 bulp
->coa
= *prim_addr
;
350 bulp
->lifetime
= mip6_config
.hr_lifetime
;
351 bulp
->refreshtime
= mip6_config
.hr_lifetime
;
353 bu_data
.prefix_len
= esp
->prefix_len
;
356 if (mip6_send_bu(bulp
, &bu_data
, NULL
) != 0)
358 } else if (esp
->state
== MIP6_STATE_REG
||
359 esp
->state
== MIP6_STATE_REREG
||
360 esp
->state
== MIP6_STATE_REGNEWCOA
||
361 esp
->state
== MIP6_STATE_NOTREG
) {
362 /* Foreign Network --> New Foreign Network */
363 /* Update state information for the home address. */
364 esp
->state
= MIP6_STATE_REGNEWCOA
;
366 esp
->coa
= *prim_addr
;
368 /* Find an existing or create a new BUL entry. */
369 bulp
= mip6_bul_find(NULL
, &esp
->home_addr
);
371 bulp
= mip6_bul_create(&esp
->ha_hn
,
374 mip6_config
.hr_lifetime
,
380 /* Send a BU registration to the Home Agent. */
381 bulp
->coa
= *prim_addr
;
382 bulp
->lifetime
= mip6_config
.hr_lifetime
;
383 bulp
->refreshtime
= mip6_config
.hr_lifetime
;
384 bulp
->no_of_sent_bu
= 0;
386 bu_data
.prefix_len
= esp
->prefix_len
;
389 if (mip6_send_bu(bulp
, &bu_data
, NULL
) != 0)
392 /* Send a BU registration to the previous default
394 if ( !IN6_IS_ADDR_UNSPECIFIED(&old_coa
) &&
396 /* Find lifetime to be used for the BU to
398 lifetime
= mip6_prefix_lifetime(&old_coa
);
399 lifetime
= min(lifetime
,
400 MIP6_BU_LIFETIME_DEFRTR
);
402 /* Create a tunnel used by the MN to receive
403 incoming tunneled packets. */
404 if (mip6_tunnel(prim_addr
, &esp
->ha_fn
->addr
,
406 MIP6_NODE_MN
, (void *)esp
))
409 mip6_send_bu2fn(&old_coa
, esp
->ha_fn
,
412 _FREE(esp
->ha_fn
, M_TEMP
);
417 esp
->state
= MIP6_STATE_UNDEF
;
423 ##############################################################################
425 # CONTROL SIGNAL FUNCTIONS
426 # Functions for processing of incoming control signals (Binding Acknowledge-
427 # ment and Binding Request option) and sub-options (Home Agents list).
429 ##############################################################################
433 ******************************************************************************
434 * Function: mip6_rec_ba
435 * Description: Receive a BA option and evaluate the contents.
436 * Ret value: 0 Everything is OK.
437 * IPPROTO_DONE Error code used when something went wrong.
438 ******************************************************************************
441 mip6_rec_ba(m_in
, off
)
442 struct mbuf
*m_in
; /* Mbuf containing the entire IPv6 packet */
443 int off
; /* Offset from start of mbuf to start of dest option */
445 struct mip6_esm
*esp
; /* Home address entry */
446 struct mip6_bul
*bulp
; /* Entry in the Binding Update list */
447 struct in6_addr
*from_src
; /* Source address in received packet */
448 struct in6_addr bind_addr
; /* Binding addr in BU causing this BA */
456 /* Make sure that the BA contains a valid AH or ESP header. */
459 if ( !((m_in
->m_flags
& M_AUTHIPHDR
&& m_in
->m_flags
& M_AUTHIPDGM
) ||
460 (m_in
->m_flags
& M_AUTHIPDGM
&& m_in
->m_flags
& M_DECRYPTED
))) {
461 ip6stat
.ip6s_badoptions
++;
462 log(LOG_ERR
, "%s: No AH or ESP included in BA\n",
469 /* Make sure that the length field in the BA is >= 11. */
470 if (mip6_inp
->ba_opt
->len
< IP6OPT_BALEN
) {
471 ip6stat
.ip6s_badoptions
++;
472 log(LOG_ERR
, "%s: Length field in BA < 11\n", __FUNCTION__
);
476 /* Make sure that the sent BU sequence number == received BA sequence
477 number. But first, find the source address for the incoming packet
478 (it may include a home address option). */
479 if (mip6_inp
->optflag
& MIP6_DSTOPT_HA
)
480 from_src
= &mip6_inp
->ha_opt
->home_addr
;
482 from_src
= &mip6_inp
->ip6_src
;
484 bulp
= mip6_bul_find(from_src
, &mip6_inp
->ip6_dst
);
486 log(LOG_ERR
, "%s: No Binding Update List entry found\n",
491 if (mip6_inp
->ba_opt
->seqno
!= bulp
->seqno
) {
492 ip6stat
.ip6s_badoptions
++;
494 "%s: Received sequence number not equal to sent\n",
500 mip6_debug("\nReceived Binding Acknowledgement\n");
501 mip6_debug("IP Header Src: %s\n", ip6_sprintf(from_src
));
502 mip6_debug("IP Header Dst: %s\n",
503 ip6_sprintf(&mip6_inp
->ip6_dst
));
504 mip6_debug("Type/Length/Status: %x / %u / %u\n",
505 mip6_inp
->ba_opt
->type
,
506 mip6_inp
->ba_opt
->len
, mip6_inp
->ba_opt
->status
);
507 mip6_debug("Seq no/Life time: %u / %u\n", mip6_inp
->ba_opt
->seqno
,
508 mip6_inp
->ba_opt
->lifetime
);
509 mip6_debug("Refresh time: %u\n", mip6_inp
->ba_opt
->refresh
);
511 if (mip6_inp
->ba_opt
->len
> IP6OPT_BALEN
) {
512 offset
= mip6_opt_offset(m_in
, off
, IP6OPT_BINDING_ACK
);
516 mip6_debug("Sub-options present (TLV coded)\n");
517 for (ii
= IP6OPT_BALEN
; ii
< mip6_inp
->ba_opt
->len
; ii
++) {
518 if ((ii
- IP6OPT_BALEN
) % 16 == 0)
520 if ((ii
- IP6OPT_BALEN
) % 4 == 0)
522 m_copydata(m_in
, offset
+ 2 + ii
, sizeof(var
),
524 mip6_debug("%02x", var
);
525 if ((ii
- IP6OPT_BALEN
+ 1) % 16 == 0)
528 if ((ii
- IP6OPT_BALEN
) % 16)
534 /* Check the status field in the BA. */
535 if (mip6_inp
->ba_opt
->status
>= 128) {
536 /* Remove the BUL entry and process the error
537 (order is important). */
538 bind_addr
= bulp
->bind_addr
;
539 hr_flag
= bulp
->hr_flag
;
540 mip6_bul_delete(bulp
);
542 error
= mip6_ba_error(from_src
, &mip6_inp
->ip6_dst
,
543 &bind_addr
, hr_flag
);
547 /* BA was accepted. Update corresponding entry in the BUL.
548 Stop retransmitting the BU. */
549 bulp
->no_of_sent_bu
= 0;
550 bulp
->update_rate
= MIP6_MAX_UPDATE_RATE
;
551 mip6_clear_retrans(bulp
);
553 /* If the BA was received from the Home Agent the state
554 of the event state machine shall be updated. */
556 esp
= mip6_esm_find(&bulp
->bind_addr
);
558 log(LOG_ERR
, "%s: No event-state machine found\n",
563 /* If Dynamic Home Agent Address Discovery, change
564 HA address and remove esp->dad entry. */
566 esp
->ha_hn
= *from_src
;
567 bulp
->dst_addr
= *from_src
;
569 _FREE(esp
->dad
->hal
, M_TEMP
);
570 _FREE(esp
->dad
, M_TEMP
);
574 /* Update the state for the home address. */
575 if (esp
->state
== MIP6_STATE_DEREG
) {
576 mip6_bul_delete(bulp
);
578 /* Remove the tunnel for the MN */
579 mip6_tunnel(NULL
, NULL
, MIP6_TUNNEL_DEL
,
580 MIP6_NODE_MN
, (void *)esp
);
582 /* Send BU to each CN in the BUL to remove its
584 mip6_update_cns(&esp
->home_addr
,
585 &esp
->home_addr
, 0, 0);
588 /* Don't set the state until BUs have been sent to
589 all CNs, otherwise the Home Address option will
590 not be added for the outgoing packet. */
591 esp
->state
= MIP6_STATE_HOME
;
592 esp
->coa
= in6addr_any
;
594 esp
->state
= MIP6_STATE_REG
;
596 /* Create or modify a tunnel used by the MN to
597 receive incoming tunneled packets. */
598 if (mip6_tunnel(&esp
->coa
, &esp
->ha_hn
,
599 MIP6_TUNNEL_MOVE
, MIP6_NODE_MN
,
603 /* Send BU to each CN in the BUL to update BC entry. */
604 bulp
->lifetime
= mip6_inp
->ba_opt
->lifetime
;
605 bulp
->refreshtime
= mip6_inp
->ba_opt
->refresh
;
606 mip6_update_cns(&esp
->home_addr
, &esp
->coa
, 0,
616 ******************************************************************************
617 * Function: mip6_rec_br
618 * Description: Receive a Binding Request option and evaluate the contents.
619 * Ret value: 0 Everything is OK.
620 * IPPROTO_DONE Error code used when something went wrong.
621 ******************************************************************************
624 mip6_rec_br(m_in
, off
)
625 struct mbuf
*m_in
; /* Mbuf containing the entire IPv6 packet */
626 int off
; /* Offset from start of mbuf to start of dest option */
628 struct mip6_opt_bu
*bu_opt
; /* BU allocated in function */
629 struct in6_addr
*from_src
; /* Src address in rec packet */
630 struct mip6_esm
*esp
; /* Home address entry */
631 struct mip6_bul
*bulp_cn
; /* CN entry in the BU list */
632 struct mip6_bul
*bulp_ha
; /* HA entry in the BU list */
633 struct mip6_subbuf
*subbuf
= NULL
; /* Sub-options for an option */
634 struct mip6_subopt_coa altcoa
; /* Alternate care-of address */
635 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
636 long time_second
= time
.tv_sec
;
639 const struct mbuf
*m
= (const struct mbuf
*)m_in
;
644 /* Make sure that the BA contains a valid AH or ESP header. */
645 if (mip6_inp
->br_opt
->type
!= IP6OPT_BINDING_REQ
) {
646 ip6stat
.ip6s_badoptions
++;
651 mip6_debug("\nReceived Binding Request\n");
652 mip6_debug("Type/Length: %x / %u\n", mip6_inp
->br_opt
->type
,
653 mip6_inp
->br_opt
->len
);
655 if (mip6_inp
->br_opt
->len
> IP6OPT_BRLEN
) {
656 offset
= mip6_opt_offset(m_in
, off
, IP6OPT_BINDING_REQ
);
660 mip6_debug("Sub-options present (TLV coded)\n");
661 for (ii
= IP6OPT_BRLEN
; ii
< mip6_inp
->br_opt
->len
; ii
++) {
662 if (m
->m_len
< offset
+ 2 + ii
+ 1)
664 if ((ii
- IP6OPT_BRLEN
) % 16 == 0)
666 if ((ii
- IP6OPT_BRLEN
) % 4 == 0)
668 m_copydata(m_in
, offset
+ 2 + ii
, sizeof(var
),
670 mip6_debug("%02x", var
);
671 if ((ii
- IP6OPT_BRLEN
+ 1) % 16 == 0)
674 if ((ii
- IP6OPT_BRLEN
) % 16)
680 /* Check if the BR includes a Unique Identifier sub-option. */
681 if (mip6_inp
->br_opt
->len
> IP6OPT_BRLEN
) {
682 /* Received tunneled Router Advertisement when the MN's home
683 subnet is renumbered while the MN is away from home. */
684 /* XXX Code have to be added. */
686 /* A CN is requesting the MN to send a BU to update its BC. */
687 /* Find the source address for the incoming packet (it may
688 include a home address option). */
689 if (mip6_inp
->optflag
& MIP6_DSTOPT_HA
)
690 from_src
= &mip6_inp
->ha_opt
->home_addr
;
692 from_src
= &mip6_inp
->ip6_src
;
694 /* Find out which lifetime to use in the BU */
695 bulp_cn
= mip6_bul_find(from_src
, &mip6_inp
->ip6_dst
);
699 esp
= mip6_esm_find(&mip6_inp
->ip6_dst
);
701 log(LOG_ERR
, "%s: no event-state machine found\n",
706 bulp_ha
= mip6_bul_find(&esp
->ha_hn
, &mip6_inp
->ip6_dst
);
710 if (bulp_ha
->lifetime
> bulp_cn
->lifetime
) {
711 /* Send a BU to the previous default router. */
713 bu_opt
= mip6_create_bu(0, 0, 0, bulp_cn
->seqno
,
718 altcoa
.type
= IP6SUBOPT_ALTCOA
;
719 altcoa
.len
= IP6OPT_COALEN
;
720 altcoa
.coa
= bulp_cn
->coa
;
721 if (mip6_store_subopt(&subbuf
, (caddr_t
)&altcoa
)
724 _FREE(subbuf
, M_TEMP
);
728 mip6_outq_create(bu_opt
, subbuf
, &esp
->home_addr
,
731 bulp_cn
->lifetime
= bulp_ha
->lifetime
;
732 bulp_cn
->refreshtime
= bulp_ha
->lifetime
;
733 bulp_cn
->lasttime
= time_second
;
734 bulp_cn
->no_of_sent_bu
= 0;
735 bulp_cn
->update_rate
= MIP6_MAX_UPDATE_RATE
;
736 mip6_clear_retrans(bulp_cn
);
745 ******************************************************************************
746 * Function: mip6_rec_hal
747 * Description: Performs Dynamic Home Agent Address Discovery. Called when a
748 * list of global home agent addresses is received. Checks if the
749 * received packets source address is in the list. If not it shall
750 * be added as the first entry in the list.
751 * Save the home agent address list in the event-state machine
752 * and send a BU to the first address in the list.
753 * Note: The timeout used in the BU is a trade off between how long
754 * time it shall wait before the next entry in the list is picked
755 * and, if successful first registration, the time to perform
756 * next registration. I believe 16 - 32 seconds will be fine.
757 * Ret value: 0 Everything is OK.
758 * IPPROTO_DONE Error code used when something went wrong.
759 ******************************************************************************
762 mip6_rec_hal(src
, dst
, hal
)
763 struct in6_addr
*src
; /* Incoming packet source address */
764 struct in6_addr
*dst
; /* Incoming packet destination address */
765 struct mip6_subopt_hal
*hal
; /* List of HA's on the home link */
767 struct mip6_esm
*esp
; /* Event-state machine */
768 struct mip6_bul
*bulp
; /* Entry in the Binding Update list */
769 struct mip6_subbuf
*subbuf
; /* Buffer containing sub-options */
770 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
771 int found
, ii
, new_len
, index
;
775 /* Find the event-state machine */
776 esp
= mip6_esm_find(dst
);
779 "%s: Couldn't find an event-state machine for "
781 __FUNCTION__
, ip6_sprintf(dst
));
785 /* If the incoming source address is not in the list of home
786 agents it is treated as the HA with highest preference.
787 Otherwise, the HA's are tried in the listed order. */
790 new_len
= IP6OPT_HALEN
;
792 index
= hal
->len
/ IP6OPT_HALEN
;
793 for (ii
= 0; ii
< index
; ii
++) {
794 if (IN6_ARE_ADDR_EQUAL(&hal
->halist
[ii
], src
)) {
802 new_len
= hal
->len
+ IP6OPT_HALEN
;
805 /* Store the home agents list in the event-state machine. Add the
806 incoming packets source address if necessary. */
807 esp
->dad
= (struct mip6_dad
*)MALLOC(sizeof(struct mip6_dad
),
809 if (esp
->dad
== NULL
)
811 bzero(esp
->dad
, sizeof(struct mip6_dad
));
813 index
= new_len
/ IP6OPT_HALEN
;
814 esp
->dad
->hal
= (struct mip6_subopt_hal
*)
815 MALLOC(sizeof(struct mip6_subopt_hal
) +
816 ((index
- 1) * sizeof(struct in6_addr
)),
818 if (esp
->dad
->hal
== NULL
)
821 esp
->dad
->hal
->type
= IP6SUBOPT_HALIST
;
822 esp
->dad
->hal
->len
= new_len
;
824 for (ii
= 0; ii
< index
; ii
++) {
825 bcopy(&hal
->halist
[ii
], &esp
->dad
->hal
->halist
[ii
],
826 sizeof(struct in6_addr
));
829 bcopy(src
, &esp
->dad
->hal
->halist
[0], sizeof(struct in6_addr
));
830 for (ii
= 0; ii
< index
- 1; ii
++) {
831 bcopy(&hal
->halist
[ii
], &esp
->dad
->hal
->halist
[ii
+1],
832 sizeof(struct in6_addr
));
836 /* Create a BUL entry. If there exist one already something is
837 wrong and an error message is sent to the console. */
838 bulp
= mip6_bul_find(src
, dst
);
841 "%s: A BUL entry found but it shouldn't have been. "
842 "Internal error that must be looked into\n", __FUNCTION__
);
846 bulp
= mip6_bul_create(&esp
->dad
->hal
->halist
[0], &esp
->home_addr
,
847 &esp
->coa
, MIP6_BU_LIFETIME_DHAAD
, 1);
851 /* Send a BU registration to the Home Agent with highest preference. */
852 bu_data
.prefix_len
= esp
->prefix_len
;
855 if (mip6_send_bu(bulp
, &bu_data
, subbuf
) != 0)
858 /* Set index to next entry to be used in the list.
859 Starts at 0 (which has been sent in this function) */
860 if ((esp
->dad
->hal
->len
/ IP6OPT_HALEN
) == 1)
871 ******************************************************************************
872 * Function: mip6_rec_ramn
873 * Description: Processed by a Mobile Node. Includes a Router Advertisement
874 * with a H-bit set in the flags variable (checked by the calling
876 * The global unicast address for the home agent with the highest
877 * preference and the time when it expires are stored.
878 * Ret value: 0 Everything is OK. Otherwise appropriate error code.
879 ******************************************************************************
882 mip6_rec_ramn(m
, off
)
883 struct mbuf
*m
; /* Mbuf containing the entire IPv6 packet */
884 int off
; /* Offset from start of mbuf to start of RA */
886 struct ip6_hdr
*ip6
; /* IPv6 header */
887 struct nd_router_advert
*ra
; /* Router Advertisement */
888 struct mip6_esm
*esp
; /* Event-state machine */
889 struct nd_opt_hai
*hai
; /* Home Agent information option */
890 struct nd_opt_prefix_info
*pi
; /* Ptr to prefix information */
891 u_int8_t
*opt_ptr
; /* Ptr to current option in RA */
892 int cur_off
; /* Cur offset from start of RA */
893 caddr_t icmp6msg
; /* Copy of mbuf (consequtively) */
897 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
898 long time_second
= time
.tv_sec
;
901 /* Find out if the RA can be processed */
902 ip6
= mtod(m
, struct ip6_hdr
*);
903 if (ip6
->ip6_hlim
!= 255) {
905 "%s: Invalid hlim %d in Router Advertisement\n",
911 if (!IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_src
)) {
913 "%s: Source address %s is not link-local\n", __FUNCTION__
,
914 ip6_sprintf(&ip6
->ip6_src
));
918 /* The mbuf data must be stored consequtively to be able to
919 cast data from it. */
920 icmp6len
= m
->m_pkthdr
.len
- off
;
921 icmp6msg
= (caddr_t
)MALLOC(icmp6len
, M_TEMP
, M_WAITOK
);
922 if (icmp6msg
== NULL
)
925 m_copydata(m
, off
, icmp6len
, icmp6msg
);
926 ra
= (struct nd_router_advert
*)icmp6msg
;
928 /* First, if a Home Agent Information option is present then the Home
929 Agent preference and lifetime is taken from the option. */
930 cur_off
= sizeof(struct nd_router_advert
);
931 tmp_lifetime
= ntohl(ra
->nd_ra_router_lifetime
);
934 while (cur_off
< icmp6len
) {
935 opt_ptr
= ((caddr_t
)icmp6msg
+ cur_off
);
936 if (*opt_ptr
== ND_OPT_HA_INFORMATION
) {
937 /* Check the home agent information option */
938 hai
= (struct nd_opt_hai
*)opt_ptr
;
939 if (hai
->nd_opt_hai_len
!= 1) {
940 ip6stat
.ip6s_badoptions
++;
944 tmp_pref
= ntohs(hai
->nd_opt_hai_pref
);
945 tmp_lifetime
= ntohs(hai
->nd_opt_hai_lifetime
);
949 if (*(opt_ptr
+ 1) == 0) {
950 ip6stat
.ip6s_badoptions
++;
953 cur_off
+= *(opt_ptr
+ 1) * 8;
957 /* Go through all prefixes and store global address for the Home
958 Agent with the highest preference. */
959 cur_off
= sizeof(struct nd_router_advert
);
960 while (cur_off
< icmp6len
) {
961 opt_ptr
= ((caddr_t
)icmp6msg
+ cur_off
);
962 if (*opt_ptr
== ND_OPT_PREFIX_INFORMATION
) {
963 /* Check the prefix information option */
964 pi
= (struct nd_opt_prefix_info
*)opt_ptr
;
965 if (pi
->nd_opt_pi_len
!= 4) {
966 ip6stat
.ip6s_badoptions
++;
970 if (!(pi
->nd_opt_pi_flags_reserved
&
971 ND_OPT_PI_FLAG_RTADDR
)) {
976 if (IN6_IS_ADDR_MULTICAST(&pi
->nd_opt_pi_prefix
) ||
977 IN6_IS_ADDR_LINKLOCAL(&pi
->nd_opt_pi_prefix
)) {
982 /* Aggregatable unicast address, rfc2374 */
983 if (((pi
->nd_opt_pi_prefix
.s6_addr8
[0] & 0xe0) >
984 0x10) && (pi
->nd_opt_pi_prefix_len
!= 64)) {
989 /* Only save the address if it's equal to the coa. */
990 for (esp
= mip6_esmq
; esp
; esp
= esp
->next
) {
991 if (in6_are_prefix_equal(
992 &pi
->nd_opt_pi_prefix
,
994 pi
->nd_opt_pi_prefix_len
)) {
995 if (esp
->ha_fn
== NULL
) {
996 esp
->ha_fn
= (struct mip6_hafn
*)
997 MALLOC(sizeof(struct mip6_hafn
), M_TEMP
, M_WAITOK
);
998 if (esp
->ha_fn
== NULL
)
1000 bzero(esp
->ha_fn
, sizeof(struct mip6_hafn
));
1002 esp
->ha_fn
->addr
= pi
->nd_opt_pi_prefix
;
1003 esp
->ha_fn
->prefix_len
= pi
->nd_opt_pi_prefix_len
;
1004 esp
->ha_fn
->pref
= tmp_pref
;
1005 esp
->ha_fn
->time
= time_second
+ tmp_lifetime
;
1007 if (tmp_pref
> esp
->ha_fn
->pref
) {
1008 esp
->ha_fn
->addr
= pi
->nd_opt_pi_prefix
;
1009 esp
->ha_fn
->prefix_len
= pi
->nd_opt_pi_prefix_len
;
1010 esp
->ha_fn
->pref
= tmp_pref
;
1011 esp
->ha_fn
->time
= time_second
+ tmp_lifetime
;
1013 esp
->ha_fn
->time
= time_second
+ tmp_lifetime
;
1021 if (*(opt_ptr
+ 1) == 0) {
1022 ip6stat
.ip6s_badoptions
++;
1023 return IPPROTO_DONE
;
1025 cur_off
+= *(opt_ptr
+ 1) * 8;
1033 ******************************************************************************
1034 * Function: mip6_route_optimize
1035 * Description: When a tunneled packet is received a BU shall be sent to the
1036 * CN if no Binding Update List entry exist or if the rate limit
1037 * for sending BUs for an existing BUL entry is not exceded.
1038 * Ret value: 0 Everything is OK.
1039 * IPPROTO_DONE Error code used when something went wrong.
1040 ******************************************************************************
1043 mip6_route_optimize(m
)
1044 struct mbuf
*m
; /* Mbuf containing the entire IPv6 packet */
1046 struct ip6_hdr
*ip6
;
1047 struct mip6_esm
*esp
;
1048 struct mip6_bul
*bulp
, *bulp_hr
;
1049 struct mip6_subbuf
*subbuf
; /* Buffer containing sub-options */
1050 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
1051 struct mip6_subopt_coa altcoa
; /* Alternate care-of address */
1053 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1054 long time_second
= time
.tv_sec
;
1057 /* Make sure that all requirements are meet for sending a BU to
1058 the original sender of the packet. */
1059 if (!(m
->m_flags
& M_MIP6TUNNEL
))
1062 ip6
= mtod(m
, struct ip6_hdr
*);
1063 esp
= mip6_esm_find(&ip6
->ip6_dst
);
1067 /* Try to find an existing BUL entry. */
1068 bulp
= mip6_bul_find(&ip6
->ip6_src
, &esp
->home_addr
);
1070 /* Some information needed from the BU home registration */
1071 bulp_hr
= mip6_bul_find(NULL
, &esp
->home_addr
);
1072 if (bulp_hr
== NULL
)
1074 bulp
= mip6_bul_create(&ip6
->ip6_src
, &esp
->home_addr
,
1075 &esp
->coa
, bulp_hr
->lifetime
, 0);
1077 return IPPROTO_DONE
;
1079 /* If the existing BUL entry is waiting for an ack or
1080 has disabled sending BU, no BU shall be sent. */
1081 if ((bulp
->state
) || (bulp
->bu_flag
== 0))
1084 /* Check the rate limiting for sending Binding Updates */
1085 t
= (time_t)time_second
;
1087 mip6_debug("%s: Rate limiting for sending BU\n", __FUNCTION__
);
1088 mip6_debug("(time - bulp->lasttime) < bulp->update_rate\n");
1089 mip6_debug("time = %lu\n", (u_long
)t
);
1090 mip6_debug("bulp->lasttimetime = %lu\n", bulp
->lasttime
);
1091 mip6_debug("bulp->update_rate = %d\n", bulp
->update_rate
);
1093 if ((t
- bulp
->lasttime
) < bulp
->update_rate
)
1097 /* OK we have to send a BU. */
1099 bu_data
.prefix_len
= esp
->prefix_len
;
1102 altcoa
.type
= IP6SUBOPT_ALTCOA
;
1103 altcoa
.len
= IP6OPT_COALEN
;
1104 altcoa
.coa
= bulp
->coa
;
1105 if (mip6_store_subopt(&subbuf
, (caddr_t
)&altcoa
)) {
1106 if (subbuf
) _FREE(subbuf
, M_TEMP
);
1107 return IPPROTO_DONE
;
1110 if (mip6_send_bu(bulp
, &bu_data
, subbuf
) != 0)
1111 return IPPROTO_DONE
;
1118 ##############################################################################
1121 # These functions are called when an IPv6 packet has been created internally
1122 # by MIPv6 and shall be sent directly to its destination or when an option
1123 # (BU, BA, BR) has been created and shall be stored in the mipv6 output queue
1124 # for piggybacking on the first outgoing packet sent to the node.
1126 ##############################################################################
1130 ******************************************************************************
1131 * Function: mip6_send_bu
1132 * Description: Send a Binding Update option to a node (CN, HA or MN). A new
1133 * IPv6 packet is built including an IPv6 header and a Destination
1134 * header (where the BU is stored).
1135 * Arguments: bulp - BUL entry for which the BU is sent.
1136 * data - BU data needed when the BU option is created. NULL
1137 * if the BU option stored in the BUL entry is used.
1138 * subopt - Sub-options for the BU. NULL if the BU sub-options
1139 * stored in the BUL entry is used.
1140 * Note: The following combinations of indata are possible:
1141 * data == NULL && subbuf == NULL Use existing data, i.e used for
1143 * data != NULL && subbuf == NULL Clear existing data and send a
1144 * new BU without sub-options
1145 * data != NULL && subbuf != NULL Clear existing data and send a
1146 * new BU with new sub-options
1147 * Ret value: 0 if everything OK. Otherwise appropriate error code.
1148 ******************************************************************************
1151 mip6_send_bu(bulp
, data
, subbuf
)
1152 struct mip6_bul
*bulp
;
1153 struct mip6_bu_data
*data
;
1154 struct mip6_subbuf
*subbuf
;
1156 struct mbuf
*m_ip6
; /* IPv6 header stored in a mbuf */
1157 struct ip6_pktopts
*pktopt
; /* Options for IPv6 packet */
1158 struct mip6_opt_bu
*bu_opt
; /* Binding Update option */
1159 struct mip6_subbuf
*bu_subopt
; /* Binding Update sub-options */
1160 struct mip6_esm
*esp
; /* Home address entry */
1162 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1163 long time_second
= time
.tv_sec
;
1170 /* Make sure that it's allowed to send a BU */
1174 if (!bulp
->bu_flag
) {
1176 "%s: BU not sent to host %s due to an ICMP Parameter "
1177 "Problem, Code 2, when a BU was sent previously\n",
1178 __FUNCTION__
, ip6_sprintf(&bulp
->dst_addr
));
1182 /* Only send BU if we are not in state UNDEFINED */
1183 esp
= mip6_esm_find(&bulp
->bind_addr
);
1185 log(LOG_ERR
, "%s: We should never come here\n", __FUNCTION__
);
1187 } else if (esp
->state
== MIP6_STATE_UNDEF
) {
1189 "%s: Mobile Node with home address %s not connected to "
1190 "any network. Binding Update could not be sent.\n",
1191 __FUNCTION__
, ip6_sprintf(&bulp
->bind_addr
));
1195 /* Evaluate parameters according to the note in the function header */
1196 if ((data
== NULL
) && (subbuf
== NULL
)) {
1197 if ((bulp
->state
== NULL
) || (bulp
->state
->bu_opt
== NULL
)) {
1199 "%s: No existing BU option to send\n",
1204 bu_opt
= bulp
->state
->bu_opt
;
1205 bu_opt
->seqno
= bulp
->seqno
;
1206 bu_subopt
= bulp
->state
->bu_subopt
;
1207 } else if (data
!= NULL
) {
1208 mip6_clear_retrans(bulp
);
1210 bulp
->state
= mip6_create_retrans(bulp
);
1211 if (bulp
->state
== NULL
)
1216 bu_opt
= mip6_create_bu(data
->prefix_len
, data
->ack
,
1218 bulp
->seqno
, bulp
->lifetime
);
1219 if (bu_opt
== NULL
) {
1220 mip6_clear_retrans(bulp
);
1226 bulp
->state
->bu_opt
= bu_opt
;
1227 bulp
->state
->bu_subopt
= subbuf
;
1228 bu_subopt
= bulp
->state
->bu_subopt
;
1233 "%s: Function parameter error. We should not come here\n",
1238 /* Allocate necessary memory and send the BU */
1239 pktopt
= (struct ip6_pktopts
*)MALLOC(sizeof(struct ip6_pktopts
),
1243 bzero(pktopt
, sizeof(struct ip6_pktopts
));
1245 pktopt
->ip6po_hlim
= -1; /* -1 means to use default hop limit */
1246 m_ip6
= mip6_create_ip6hdr(&bulp
->bind_addr
, &bulp
->dst_addr
,
1249 _FREE(pktopt
, M_TEMP
);
1253 pktopt
->ip6po_dest2
= mip6_create_dh((void *)bu_opt
, bu_subopt
,
1255 if(pktopt
->ip6po_dest2
== NULL
) {
1256 _FREE(pktopt
, M_TEMP
);
1257 _FREE(m_ip6
, M_TEMP
);
1261 mip6_config
.enable_outq
= 0;
1262 error
= ip6_output(m_ip6
, pktopt
, NULL
, 0, NULL
, NULL
);
1264 _FREE(pktopt
->ip6po_dest2
, M_TEMP
);
1265 _FREE(pktopt
, M_TEMP
);
1266 mip6_config
.enable_outq
= 1;
1268 "%s: ip6_output function failed to send BU, error = %d\n",
1269 __FUNCTION__
, error
);
1272 mip6_config
.enable_outq
= 1;
1274 /* Update Binding Update List variables. */
1275 bulp
->lasttime
= time_second
;
1276 bulp
->no_of_sent_bu
+= 1;
1278 if ( !(bu_opt
->flags
& MIP6_BU_AFLAG
)) {
1279 if (bulp
->no_of_sent_bu
>= MIP6_MAX_FAST_UPDATES
)
1280 bulp
->update_rate
= MIP6_SLOW_UPDATE_RATE
;
1284 mip6_debug("\nSent Binding Update option (0x%x)\n", bu_opt
);
1285 mip6_debug("IP Header Src: %s\n", ip6_sprintf(&bulp
->bind_addr
));
1286 mip6_debug("IP Header Dst: %s\n", ip6_sprintf(&bulp
->dst_addr
));
1287 mip6_debug("Type/Length/Flags: %x / %u / ", bu_opt
->type
, bu_opt
->len
);
1288 if (bu_opt
->flags
& MIP6_BU_AFLAG
)
1290 if (bu_opt
->flags
& MIP6_BU_HFLAG
)
1292 if (bu_opt
->flags
& MIP6_BU_RFLAG
)
1295 mip6_debug("Seq no/Life time: %u / %u\n", bu_opt
->seqno
,
1297 mip6_debug("Prefix length: %u\n", bu_opt
->prefix_len
);
1300 mip6_debug("Sub-options present (TLV coded)\n");
1301 for (ii
= 0; ii
< bu_subopt
->len
; ii
++) {
1303 mip6_debug("\t0x:");
1306 bcopy((caddr_t
)&bu_subopt
->buffer
[ii
],
1308 mip6_debug("%02x", var
);
1309 if ((ii
+ 1) % 16 == 0)
1317 _FREE(pktopt
->ip6po_dest2
, M_TEMP
);
1318 _FREE(pktopt
, M_TEMP
);
1325 ******************************************************************************
1326 * Function: mip6_send_bu2fn
1327 * Description: Create a new or modify an existing Binding Update List entry,
1328 * create a Bindig Update option and a new temporary event-state
1329 * machine and send the Binding Update option to a Home Agent at
1330 * the previous foreign network.
1332 ******************************************************************************
1335 mip6_send_bu2fn(old_coa
, old_ha
, coa
, esm_ifp
, lifetime
)
1336 struct in6_addr
*old_coa
; /* Previous care-of address */
1337 struct mip6_hafn
*old_ha
; /* Previous Home Agent address */
1338 struct in6_addr
*coa
; /* Current coa or home address */
1339 struct ifnet
*esm_ifp
; /* Physical i/f used by event-state machine */
1340 u_int32_t lifetime
; /* Lifetime for BU */
1342 struct mip6_esm
*esp
; /* ESM for prev COA */
1343 struct mip6_bul
*bulp
; /* BU list entry*/
1344 struct mip6_subbuf
*subbuf
; /* Buffer containing sub-options */
1345 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
1346 struct mip6_subopt_coa altcoa
; /* Alternate care-of address */
1347 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1348 long time_second
= time
.tv_sec
;
1351 /* Make sure that the Home Agent at the previous network exist and
1352 that it's still valid. */
1356 if (time_second
> old_ha
->time
) {
1358 "%s: Timer had expired for Home Agent on "
1359 "previous network. No BU sent\n",
1365 /* Find an existing or create a new BUL entry. */
1366 bulp
= mip6_bul_find(NULL
, old_coa
);
1368 bulp
= mip6_bul_create(&old_ha
->addr
, old_coa
, coa
,
1373 bulp
->dst_addr
= old_ha
->addr
;
1375 bulp
->lifetime
= lifetime
;
1376 bulp
->refreshtime
= lifetime
;
1377 mip6_clear_retrans(bulp
);
1380 /* Create an event-state machine to be used when the home address
1381 option is created for outgoing packets. The event-state machine
1382 must be removed when the BUL entry is removed. */
1383 esp
= mip6_esm_create(esm_ifp
, &old_ha
->addr
, coa
, old_coa
, 0,
1384 MIP6_STATE_NOTREG
, TEMPORARY
,
1385 MIP6_BU_LIFETIME_DEFRTR
);
1389 /* Send the Binding Update option */
1392 bu_data
.prefix_len
= 0;
1395 altcoa
.type
= IP6SUBOPT_ALTCOA
;
1396 altcoa
.len
= IP6OPT_COALEN
;
1398 if (mip6_store_subopt(&subbuf
, (caddr_t
)&altcoa
)) {
1400 _FREE(subbuf
, M_TEMP
);
1404 if (mip6_send_bu(bulp
, &bu_data
, subbuf
) != 0)
1411 ******************************************************************************
1412 * Function: mip6_update_cns
1413 * Description: Search the BUL for each entry with a matching home address for
1414 * which no Binding Update has been sent for the new COA.
1415 * Call a function for queueing the BU.
1416 * Note: Since this BU is stored in the MN for a couple of seconds
1417 * before it is piggybacked or flashed from the queue it may
1418 * not have the ack-bit set.
1420 ******************************************************************************
1423 mip6_update_cns(home_addr
, coa
, prefix_len
, lifetime
)
1424 struct in6_addr
*home_addr
; /* Home Address for MN */
1425 struct in6_addr
*coa
; /* New Primary COA for MN */
1426 u_int8_t prefix_len
; /* Prefix length for Home Address */
1427 u_int32_t lifetime
; /* Lifetime for BU registration */
1429 struct mip6_bul
*bulp
; /* Entry in the Binding Update List */
1431 /* Try to find existing entry in the BUL. Home address must match. */
1432 for (bulp
= mip6_bulq
; bulp
;) {
1433 if (IN6_ARE_ADDR_EQUAL(home_addr
, &bulp
->bind_addr
) &&
1434 !IN6_ARE_ADDR_EQUAL(coa
, &bulp
->coa
)) {
1435 /* Queue a BU for transmission to the node. */
1436 mip6_queue_bu(bulp
, home_addr
, coa
,
1437 prefix_len
, lifetime
);
1439 /* Remove BUL entry if it's a de-registration. */
1440 if (IN6_ARE_ADDR_EQUAL(home_addr
, coa
) ||
1442 bulp
= mip6_bul_delete(bulp
);
1453 ******************************************************************************
1454 * Function: mip6_queue_bu
1455 * Description: Create a BU and a sub-option (alternate care-of address).
1456 * Update the BUL entry and store it in the output queue for
1458 * Note: Since this BU is stored in the MN for a couple of seconds
1459 * before it is piggybacked or flashed from the queue it may
1460 * not have the ack-bit set.
1462 ******************************************************************************
1465 mip6_queue_bu(bulp
, home_addr
, coa
, prefix_len
, lifetime
)
1466 struct mip6_bul
*bulp
; /* Entry in the Binding Update List */
1467 struct in6_addr
*home_addr
; /* Home Address for MN */
1468 struct in6_addr
*coa
; /* New Primary COA for MN */
1469 u_int8_t prefix_len
; /* Prefix length for Home Address */
1470 u_int32_t lifetime
; /* Lifetime for BU registration */
1472 struct mip6_opt_bu
*bu_opt
; /* BU allocated in this function */
1473 struct mip6_subbuf
*subbuf
; /* Buffer containing sub-options */
1474 struct mip6_subopt_coa altcoa
; /* Alternate care-of address */
1475 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
1476 long time_second
= time
.tv_sec
;
1479 /* Check if it's allowed to send a BU to this node. */
1480 if ((coa
== NULL
) || (bulp
== NULL
))
1483 if (bulp
->bu_flag
== 0) {
1485 "%s: BU not sent to host %s due to an ICMP Parameter "
1486 "Problem, Code 2, when a BU was sent previously\n",
1487 __FUNCTION__
, ip6_sprintf(&bulp
->dst_addr
));
1491 /* Create the sub-option */
1493 altcoa
.type
= IP6SUBOPT_ALTCOA
;
1494 altcoa
.len
= IP6OPT_COALEN
;
1496 if (mip6_store_subopt(&subbuf
, (caddr_t
)&altcoa
)) {
1498 _FREE(subbuf
, M_TEMP
);
1504 bu_opt
= mip6_create_bu(prefix_len
, 0, 0, bulp
->seqno
, lifetime
);
1505 if (bu_opt
== NULL
) {
1506 log(LOG_ERR
, "%s: Could not create a BU\n", __FUNCTION__
);
1510 /* Update BUL entry */
1512 bulp
->lifetime
= lifetime
;
1513 bulp
->refreshtime
= lifetime
;
1514 bulp
->lasttime
= time_second
;
1515 bulp
->no_of_sent_bu
+= 1;
1516 mip6_clear_retrans(bulp
);
1518 /* Add entry to the output queue for transmission to the CN. */
1519 mip6_outq_create(bu_opt
, subbuf
, home_addr
, &bulp
->dst_addr
, NOT_SENT
);
1525 ##############################################################################
1528 # Miscellaneous functions needed for processing of incoming control signals
1529 # or events originated from the move detection algorithm.
1531 ##############################################################################
1535 ******************************************************************************
1536 * Function: mip6_create_bu
1537 * Description: Create a Binding Update option for transmission.
1538 * Ret value: Pointer to the BU option or NULL.
1539 * Note: Variable seqno and lifetime set in function
1540 * mip6_update_bul_entry.
1541 ******************************************************************************
1543 struct mip6_opt_bu
*
1544 mip6_create_bu(prefix_len
, ack
, hr
, seqno
, lifetime
)
1545 u_int8_t prefix_len
; /* Prefix length for Home Address */
1546 int ack
; /* Ack required (0 = FALSE otherwise TRUE) */
1547 int hr
; /* Home Registration (0 = FALSE otherwise TRUE) */
1548 u_int16_t seqno
; /* Sequence number */
1549 u_int32_t lifetime
; /* Suggested lifetime for the BU registration */
1551 struct mip6_opt_bu
*bu_opt
; /* BU allocated in this function */
1553 /* Allocate and store Binding Update option data */
1554 bu_opt
= (struct mip6_opt_bu
*)MALLOC(sizeof(struct mip6_opt_bu
),
1558 bzero(bu_opt
, sizeof(struct mip6_opt_bu
));
1560 bu_opt
->type
= IP6OPT_BINDING_UPDATE
;
1561 bu_opt
->len
= IP6OPT_BULEN
;
1562 bu_opt
->seqno
= seqno
;
1563 bu_opt
->lifetime
= lifetime
;
1565 /* The prefix length field is valid only for "home registration" BU. */
1567 bu_opt
->flags
|= MIP6_BU_HFLAG
;
1568 bu_opt
->prefix_len
= prefix_len
;
1570 bu_opt
->flags
|= MIP6_BU_RFLAG
;
1572 bu_opt
->prefix_len
= 0;
1575 bu_opt
->flags
|= MIP6_BU_AFLAG
;
1578 mip6_debug("\nBinding Update option created (0x%x)\n", bu_opt
);
1586 ******************************************************************************
1587 * Function: mip6_stop_bu
1588 * Description: Stop sending a Binding Update to the host that has generated
1589 * the icmp error message.
1591 ******************************************************************************
1594 mip6_stop_bu(ip6_dst
)
1595 struct in6_addr
*ip6_dst
; /* Host that generated ICMP error message */
1597 struct mip6_bul
*bulp
; /* Entry in the BU list */
1599 /* No future BU shall be sent to this destination. */
1600 for (bulp
= mip6_bulq
; bulp
; bulp
= bulp
->next
) {
1601 if (IN6_ARE_ADDR_EQUAL(ip6_dst
, &bulp
->dst_addr
))
1609 ******************************************************************************
1610 * Function: mip6_ba_error
1611 * Description: Each incoming BA error is taken care of by this function.
1612 * If a registration to the Home Agent failed then dynamic home
1613 * agent address discovery shall be performed. If a de-regi-
1614 * stration failed then perform the same actions as when a
1615 * BA with status equals to 0 is received.
1616 * If a registration or de-registration to the CN failed then
1617 * the error is logged, no further action is taken.
1618 * If dynamic home agent address discovery already has been
1619 * done then take the next entry in the list. If its just one
1620 * entry in the list discard it and send a BU with destination
1621 * address equals to Home Agents anycast address.
1622 * Ret value: 0 Everything is OK.
1623 * IPPROTO_DONE Error code used when something went wrong.
1624 ******************************************************************************
1627 mip6_ba_error(src
, dst
, bind_addr
, hr_flag
)
1628 struct in6_addr
*src
; /* Src address for received BA option */
1629 struct in6_addr
*dst
; /* Dst address for received BA option */
1630 struct in6_addr
*bind_addr
; /* Binding addr in BU causing this error */
1631 u_int8_t hr_flag
; /* Home reg flag in BU causing this error */
1633 struct mip6_bul
*bulp
; /* New BUL entry*/
1634 struct mip6_esm
*esp
; /* Home address entry */
1635 struct in6_addr
*dst_addr
;
1636 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
1638 int error
, max_index
;
1640 if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_UNSPEC
) {
1641 /* Reason unspecified
1642 Received when either a Home Agent or Correspondent Node
1643 was not able to process the BU. */
1645 "\nBinding Acknowledgement error = %d "
1646 "(Reason unspecified) from host %s\n",
1647 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1648 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_PROHIBIT
) {
1649 /* Administratively prohibited */
1651 "\nBinding Acknowledgement error = %d "
1652 "(Administratively prohibited) from host %s\n",
1653 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1654 log(LOG_INFO
, "Contact your system administrator\n");
1655 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_RESOURCE
) {
1656 /* Insufficient resources
1657 Received when a Home Agent receives a BU with the H-bit
1658 set and insufficient space exist or can be reclaimed
1661 "\nBinding Acknowledgement error = %d "
1662 "(Insufficient resources) from host %s\n",
1663 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1664 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_HOMEREGNOSUP
) {
1665 /* Home registration not supported
1666 Received when a primary care-of address registration
1667 (sec. 9.3) is done and the node is not a router
1668 implementing Home Agent functionality. */
1670 "\nBinding Acknowledgement error = %d "
1671 "(Home registration not supported) from host %s\n",
1672 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1673 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_SUBNET
) {
1675 Received when a primary care-of address registration
1676 (sec. 9.3) is done and the home address for the binding
1677 is not an on-link IPv6 address with respect to the Home
1678 Agent's current prefix list. */
1680 "\nBinding Acknowledgement error = %d "
1681 "(Not home subnet) from host %s\n",
1682 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1683 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_DHAAD
) {
1684 /* Dynamic Home Agent Address Discovery
1685 Received when a Mobile Node is trying to find out the
1686 global address of the home agents on its home subnetwork
1688 error
= mip6_rec_hal(src
, dst
, mip6_inp
->hal
);
1690 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_IFLEN
) {
1691 /* Incorrect subnet prefix length
1692 Received when a primary care-of address registration
1693 (sec. 9.3) is done and the prefix length in the BU
1694 differs from the length of the home agent's own knowledge
1695 of the subnet prefix length on the home link. */
1697 "\nBinding Acknowledgement error = %d "
1698 "(Incorrect subnet prefix length) from host %s\n",
1699 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1700 } else if (mip6_inp
->ba_opt
->status
== MIP6_BA_STATUS_NOTHA
) {
1701 /* Not Home Agent for this Mobile Node
1702 Received when a primary care-of address de-registration
1703 (sec. 9.4) is done and the Home Agent has no entry for
1704 this mobil node marked as "home registration" in its
1707 "\nBinding Acknowledgement error = %d "
1708 "(Not Home Agent for this Mobile Node) from host %s\n",
1709 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1712 "\nBinding Acknowledgement error = %d (Unknown) "
1714 mip6_inp
->ba_opt
->status
, ip6_sprintf(src
));
1717 /* Furthr processing according to the desription in the header. */
1719 esp
= mip6_esm_find(bind_addr
);
1722 "%s: No event-state machine found\n",
1724 return IPPROTO_DONE
;
1727 /* If it's a de-registration, clear up the ESM. */
1728 if (esp
->state
== MIP6_STATE_DEREG
) {
1729 /* Remove the tunnel for the MN */
1730 mip6_tunnel(NULL
, NULL
, MIP6_TUNNEL_DEL
,
1731 MIP6_NODE_MN
, (void *)esp
);
1733 /* Send BU to each entry (CN) in the BUL to remove
1735 mip6_update_cns(&esp
->home_addr
, &esp
->home_addr
,
1739 /* Don't set the state until BUs have been sent
1740 to all CNs, otherwise the Home Address option
1741 will not be added for the outgoing packet. */
1742 esp
->state
= MIP6_STATE_HOME
;
1743 esp
->coa
= in6addr_any
;
1747 /* If it's a registration, perform dynamic home agent address
1748 discovery or use the existing. */
1750 if (esp
->dad
->hal
->len
== IP6OPT_HALEN
) {
1752 _FREE(esp
->dad
->hal
, M_TEMP
);
1753 _FREE(esp
->dad
, M_TEMP
);
1755 /* Build an anycast address */
1756 mip6_build_ha_anycast(&esp
->ha_hn
,
1759 if (IN6_IS_ADDR_UNSPECIFIED(&esp
->ha_hn
)) {
1761 "%s: Could not create anycast "
1762 "address for Mobile Node, "
1763 "wrong prefix length\n",
1765 return IPPROTO_DONE
;
1767 dst_addr
= &esp
->ha_hn
;
1768 lifetime
= mip6_config
.hr_lifetime
;
1770 dst_addr
= &esp
->dad
->hal
->halist
[esp
->dad
->index
];
1771 max_index
= (esp
->dad
->hal
->len
/ IP6OPT_HALEN
) - 1;
1772 if (esp
->dad
->index
== max_index
)
1773 esp
->dad
->index
= 0;
1775 esp
->dad
->index
+= 1;
1776 lifetime
= MIP6_BU_LIFETIME_DHAAD
;
1779 /* Build an anycast address */
1780 mip6_build_ha_anycast(&esp
->ha_hn
, &esp
->home_addr
,
1782 if (IN6_IS_ADDR_UNSPECIFIED(&esp
->ha_hn
)) {
1784 "%s: Could not create anycast address for Mobile "
1785 "Node, wrong prefix length\n", __FUNCTION__
);
1786 return IPPROTO_DONE
;
1788 dst_addr
= &esp
->ha_hn
;
1789 lifetime
= mip6_config
.hr_lifetime
;
1792 /* Create a new BUL entry and send a BU to the Home Agent */
1793 bulp
= mip6_bul_create(dst_addr
, &esp
->home_addr
, &esp
->coa
,
1796 return IPPROTO_DONE
;
1798 bu_data
.prefix_len
= esp
->prefix_len
;
1801 if (mip6_send_bu(bulp
, &bu_data
, NULL
) != 0)
1802 return IPPROTO_DONE
;
1810 ******************************************************************************
1811 * Function: mip6_prefix_lifetime
1812 * Description: Decide the remaining valid lifetime for a home address. Search
1813 * the prefix list for a match and use this lifetime value.
1814 * Note: This function is used by the MN since no test of the on-link
1816 * Ret value: Lifetime
1817 ******************************************************************************
1820 mip6_prefix_lifetime(addr
)
1821 struct in6_addr
*addr
; /* IPv6 address to check */
1823 struct nd_prefix
*pr
; /* Entries in the prexix list */
1824 u_int32_t min_time
; /* Minimum life time */
1826 min_time
= 0xffffffff;
1827 for (pr
= nd_prefix
.lh_first
; pr
; pr
= pr
->ndpr_next
) {
1828 if (in6_are_prefix_equal(addr
, &pr
->ndpr_prefix
.sin6_addr
,
1830 return pr
->ndpr_vltime
;
1839 ******************************************************************************
1840 * Function: mip6_create_retrans
1841 * Description: Removes the current content of the bulp->state variable and
1842 * allocates new memory.
1843 * Ret value: Pointer to the allocated memory or NULL.
1844 ******************************************************************************
1846 struct mip6_retrans
*
1847 mip6_create_retrans(bulp
)
1848 struct mip6_bul
*bulp
;
1853 mip6_clear_retrans(bulp
);
1854 bulp
->state
= (struct mip6_retrans
*)MALLOC(
1855 sizeof(struct mip6_retrans
),
1857 if (bulp
->state
== NULL
)
1859 bzero(bulp
->state
, sizeof(struct mip6_retrans
));
1861 bulp
->state
->bu_opt
= NULL
;
1862 bulp
->state
->bu_subopt
= NULL
;
1863 bulp
->state
->ba_timeout
= 2;
1864 bulp
->state
->time_left
= 2;
1871 ******************************************************************************
1872 * Function: mip6_clear_retrans
1873 * Description: Removes the current content of the bulp->state variable and
1876 ******************************************************************************
1879 mip6_clear_retrans(bulp
)
1880 struct mip6_bul
*bulp
;
1886 if (bulp
->state
->bu_opt
)
1887 _FREE(bulp
->state
->bu_opt
, M_TEMP
);
1888 if (bulp
->state
->bu_subopt
)
1889 _FREE(bulp
->state
->bu_subopt
, M_TEMP
);
1890 _FREE(bulp
->state
, M_TEMP
);
1899 ##############################################################################
1902 # The Mobile Node maintains a Bindig Update List (BUL) for each node to which
1903 # a BU has been sent.
1904 # Besides from this a list of event-state machines, one for each home address
1905 # is handled by the Mobile Node and the Correspondent Node since it may
1906 # become mobile at any time.
1907 # An output queue for piggybacking of options (BU, BA, BR) on the first
1908 # outgoing packet sent to the node is also maintained. If the option has not
1909 # been sent with a packet within MIP6_OUTQ_LIFETIME it will be sent in a
1912 ##############################################################################
1916 ******************************************************************************
1917 * Function: mip6_bul_find
1918 * Description: Find a Binding Update List entry for which a matching can be
1919 * found for both the destination and binding address.
1920 * If variable dst_addr is NULL an entry for home registration
1921 * will be searched for.
1922 * Ret value: Pointer to Binding Update List entry or NULL
1923 ******************************************************************************
1926 mip6_bul_find(dst_addr
, bind_addr
)
1927 struct in6_addr
*dst_addr
; /* Destination Address for Binding Update */
1928 struct in6_addr
*bind_addr
; /* Home Address for MN or previous COA */
1930 struct mip6_bul
*bulp
; /* Entry in the Binding Update list */
1932 if (dst_addr
== NULL
) {
1933 for (bulp
= mip6_bulq
; bulp
; bulp
= bulp
->next
) {
1934 if (IN6_ARE_ADDR_EQUAL(bind_addr
, &bulp
->bind_addr
) &&
1939 for (bulp
= mip6_bulq
; bulp
; bulp
= bulp
->next
) {
1940 if (IN6_ARE_ADDR_EQUAL(dst_addr
, &bulp
->dst_addr
) &&
1941 IN6_ARE_ADDR_EQUAL(bind_addr
, &bulp
->bind_addr
))
1947 /* It might be that the dest address for the BU was the Home
1948 Agent anycast address and in that case we try to find it. */
1949 for (bulp
= mip6_bulq
; bulp
; bulp
= bulp
->next
) {
1950 if ((bulp
->dst_addr
.s6_addr8
[15] & 0x7f) ==
1951 MIP6_ADDR_ANYCAST_HA
&&
1952 IN6_ARE_ADDR_EQUAL(bind_addr
, &bulp
->bind_addr
)) {
1964 ******************************************************************************
1965 * Function: mip6_bul_create
1966 * Description: Create a new Binding Update List entry and insert it as the
1967 * first entry in the list.
1968 * Ret value: Pointer to Binding Update List entry or NULL.
1969 * Note: If the BUL timeout function has not been started it is started.
1970 * The BUL timeout function will be called once every second until
1971 * there are no more entries in the BUL.
1972 ******************************************************************************
1975 mip6_bul_create(dst_addr
, bind_addr
, coa
, lifetime
, hr
)
1976 struct in6_addr
*dst_addr
; /* Dst address for Binding Update */
1977 struct in6_addr
*bind_addr
; /* Home Address for MN or previous COA */
1978 struct in6_addr
*coa
; /* Primary COA for MN */
1979 u_int32_t lifetime
; /* Lifetime for BU */
1980 u_int8_t hr
; /* Home registration flag */
1982 struct mip6_bul
*bulp
; /* New Binding Update list entry */
1985 bulp
= (struct mip6_bul
*)MALLOC(sizeof(struct mip6_bul
),
1989 bzero(bulp
, sizeof(struct mip6_bul
));
1992 bulp
->dst_addr
= *dst_addr
;
1993 bulp
->bind_addr
= *bind_addr
;
1995 bulp
->lifetime
= lifetime
;
1996 bulp
->refreshtime
= lifetime
;
1999 bulp
->no_of_sent_bu
= 0;
2003 bulp
->update_rate
= MIP6_MAX_UPDATE_RATE
;
2005 /* Insert the entry as the first entry in the BUL. */
2007 if (mip6_bulq
== NULL
) {
2009 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2010 mip6_timer_bul_handle
=
2012 timeout(mip6_timer_bul
, (void *)0, hz
);
2014 bulp
->next
= mip6_bulq
;
2020 mip6_debug("\nBinding Update List Entry created (0x%x)\n", bulp
);
2021 mip6_debug("Destination Address: %s\n", ip6_sprintf(&bulp
->dst_addr
));
2022 mip6_debug("Binding Address: %s\n", ip6_sprintf(&bulp
->bind_addr
));
2023 mip6_debug("Care-of Address: %s\n", ip6_sprintf(&bulp
->coa
));
2024 mip6_debug("Life/Refresh time: %u / %u\n", bulp
->lifetime
,
2026 mip6_debug("Seq no/Home reg: %u / ", bulp
->seqno
);
2028 mip6_debug("TRUE\n");
2030 mip6_debug("FALSE\n");
2038 ******************************************************************************
2039 * Function: mip6_bul_delete
2040 * Description: Delete the requested Binding Update list entry.
2041 * Ret value: Ptr to next entry in list or NULL if last entry removed.
2042 ******************************************************************************
2045 mip6_bul_delete(bul_remove
)
2046 struct mip6_bul
*bul_remove
; /* BUL entry to be deleted */
2048 struct mip6_bul
*bulp
; /* Current entry in the BU list */
2049 struct mip6_bul
*bulp_prev
; /* Previous entry in the BU list */
2050 struct mip6_bul
*bulp_next
; /* Next entry in the BU list */
2053 /* Find the requested entry in the BUL. */
2057 for (bulp
= mip6_bulq
; bulp
; bulp
= bulp
->next
) {
2058 bulp_next
= bulp
->next
;
2059 if (bulp
== bul_remove
) {
2060 if (bulp_prev
== NULL
)
2061 mip6_bulq
= bulp
->next
;
2063 bulp_prev
->next
= bulp
->next
;
2065 mip6_debug("\nBU List Entry deleted (0x%x)\n", bulp
);
2067 mip6_clear_retrans(bulp
);
2068 _FREE(bulp
, M_TEMP
);
2070 /* Remove the timer if the BUL queue is empty */
2071 if (mip6_bulq
== NULL
) {
2072 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2073 untimeout(mip6_timer_bul
, (void *)NULL
,
2074 mip6_timer_bul_handle
);
2075 callout_handle_init(&mip6_timer_bul_handle
);
2077 untimeout(mip6_timer_bul
, (void *)NULL
);
2091 ******************************************************************************
2092 * Function: mip6_esm_find
2093 * Description: Find an event-state machine for which the Mobile Nodes home
2094 * address matches and the type is correct.
2095 * Ret value: Pointer to event-state machine entry or NULL
2096 ******************************************************************************
2099 mip6_esm_find(home_addr
)
2100 struct in6_addr
*home_addr
; /* MNs home address */
2102 struct mip6_esm
*esp
;
2104 for (esp
= mip6_esmq
; esp
; esp
= esp
->next
) {
2105 if (IN6_ARE_ADDR_EQUAL(home_addr
, &esp
->home_addr
))
2114 ******************************************************************************
2115 * Function: mip6_esm_create
2116 * Description: Create an event-state machine entry and add it first to the
2117 * list. If type is PERMANENT the lifetime will be set to 0xFFFF,
2118 * otherwise it will be set to the specified lifetime. If type is
2119 * TEMPORARY the timer will be started if not already started.
2120 * Ret value: Pointer to an event-state machine or NULL.
2121 ******************************************************************************
2124 mip6_esm_create(ifp
, ha_hn
, coa
, home_addr
, prefix_len
, state
,
2126 struct ifnet
*ifp
; /* Physical i/f used by this home address */
2127 struct in6_addr
*ha_hn
; /* Home agent address (home network) */
2128 struct in6_addr
*coa
; /* Current care-of address */
2129 struct in6_addr
*home_addr
; /* Home address */
2130 u_int8_t prefix_len
; /* Prefix length for the home address */
2131 int state
; /* State of the home address */
2132 enum esm_type type
; /* Permanent or Temporary esm */
2133 u_int16_t lifetime
; /* Lifetime for event-state machine */
2135 struct mip6_esm
*esp
, *esp_tmp
;
2138 esp
= (struct mip6_esm
*)MALLOC(sizeof(struct mip6_esm
),
2142 "%s: Could not create an event-state machine\n",
2146 bzero(esp
, sizeof(struct mip6_esm
));
2153 esp
->home_addr
= *home_addr
;
2154 esp
->prefix_len
= prefix_len
;
2155 esp
->ha_hn
= *ha_hn
;
2160 if (type
== PERMANENT
) {
2161 esp
->lifetime
= 0xFFFF;
2164 esp
->lifetime
= lifetime
;
2168 /* If no TEMPORARY already exist and the new is TEMPORARY, start
2170 for (esp_tmp
= mip6_esmq
; esp_tmp
; esp_tmp
= esp_tmp
->next
) {
2171 if (esp_tmp
->type
== TEMPORARY
)
2175 /* Insert entry as the first entry in the event-state machine list */
2177 if (mip6_esmq
== NULL
)
2180 esp
->next
= mip6_esmq
;
2186 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2187 mip6_timer_esm_handle
=
2189 timeout(mip6_timer_esm
, (void *)0, hz
);
2197 ******************************************************************************
2198 * Function: mip6_esm_delete
2199 * Description: Delete the requested event-state machine.
2200 * Ret value: Ptr to next entry in list or NULL if last entry removed.
2201 ******************************************************************************
2204 mip6_esm_delete(esm_remove
)
2205 struct mip6_esm
*esm_remove
; /* Event-state machine to be deleted */
2207 struct mip6_esm
*esp
; /* Current entry in event-state list */
2208 struct mip6_esm
*esp_prev
; /* Previous entry in event-state list */
2209 struct mip6_esm
*esp_next
; /* Next entry in the event-state list */
2212 /* Find the requested entry in the event-state list. */
2216 for (esp
= mip6_esmq
; esp
; esp
= esp
->next
) {
2217 esp_next
= esp
->next
;
2218 if (esp
== esm_remove
) {
2219 if (esp_prev
== NULL
)
2220 mip6_esmq
= esp
->next
;
2222 esp_prev
->next
= esp
->next
;
2224 mip6_tunnel(NULL
, NULL
, MIP6_TUNNEL_DEL
, MIP6_NODE_MN
,
2229 _FREE(esp
->dad
->hal
, M_TEMP
);
2230 _FREE(esp
->dad
, M_TEMP
);
2234 _FREE(esp
->ha_fn
, M_TEMP
);
2239 mip6_debug("\nEvent-state machine deleted (0x%x)\n",
2244 /* Remove the timer if the ESM queue is empty */
2245 if (mip6_esmq
== NULL
) {
2246 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2247 untimeout(mip6_timer_esm
, (void *)NULL
,
2248 mip6_timer_esm_handle
);
2249 callout_handle_init(&mip6_timer_esm_handle
);
2251 untimeout(mip6_timer_esm
, (void *)NULL
);
2265 ******************************************************************************
2266 * Function: mip6_outq_create
2267 * Description: Add an entry to the output queue and store the destination
2268 * option and the sub-option (if present) to this entry.
2269 * Ret value: 0 Everything is OK
2270 * Otherwise appropriate error code
2271 * Note: If the outqueue timeout function has not been started it is
2272 * started. The outqueue timeout function will be called once
2273 * every MIP6_OUTQ_INTERVAL second until there are no more entries
2275 ******************************************************************************
2278 mip6_outq_create(opt
, subbuf
, src_addr
, dst_addr
, flag
)
2279 void *opt
; /* Destination option (BU, BR or BA) */
2280 struct mip6_subbuf
*subbuf
; /* Buffer containing destination sub-options */
2281 struct in6_addr
*src_addr
; /* Source address for the option */
2282 struct in6_addr
*dst_addr
; /* Destination address for the option */
2283 enum send_state flag
; /* Flag indicating the state of the entry */
2285 struct mip6_output
*outp
; /* Pointer to output list entry */
2288 outp
= (struct mip6_output
*)MALLOC(sizeof(struct mip6_output
),
2292 bzero(outp
, sizeof(struct mip6_output
));
2296 outp
->subopt
= subbuf
;
2297 outp
->ip6_dst
= *dst_addr
;
2298 outp
->ip6_src
= *src_addr
;
2300 outp
->lifetime
= MIP6_OUTQ_LIFETIME
;
2303 if (mip6_outq
== NULL
) {
2305 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2306 mip6_timer_outqueue_handle
=
2308 timeout(mip6_timer_outqueue
, (void *)0,
2309 hz
* (MIP6_OUTQ_INTERVAL
/10));
2311 /* Add this entry as the first entry in the queue. */
2312 outp
->next
= mip6_outq
;
2322 ******************************************************************************
2323 * Function: mip6_outq_delete
2324 * Description: Delete the requested output queue entry.
2325 * Ret value: Ptr to next entry in list or NULL if last entry removed.
2326 ******************************************************************************
2328 struct mip6_output
*
2329 mip6_outq_delete(oqp_remove
)
2330 struct mip6_output
*oqp_remove
; /* Output queue entry to be deleted */
2332 struct mip6_output
*oqp
; /* Current entry in output queue */
2333 struct mip6_output
*oqp_prev
; /* Previous entry in output queue */
2334 struct mip6_output
*oqp_next
; /* Next entry in the output queue */
2337 /* Find the requested entry in the output queue. */
2341 for (oqp
= mip6_outq
; oqp
; oqp
= oqp
->next
) {
2342 oqp_next
= oqp
->next
;
2343 if (oqp
== oqp_remove
) {
2344 if (oqp_prev
== NULL
)
2345 mip6_outq
= oqp
->next
;
2347 oqp_prev
->next
= oqp
->next
;
2350 _FREE(oqp
->opt
, M_TEMP
);
2353 _FREE(oqp
->subopt
, M_TEMP
);
2356 mip6_debug("\nOutput Queue entry deleted (0x%x)\n",
2361 /* Remove the timer if the output queue is empty */
2362 if (mip6_outq
== NULL
) {
2363 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2364 untimeout(mip6_timer_outqueue
, (void *)NULL
,
2365 mip6_timer_outqueue_handle
);
2366 callout_handle_init(
2367 &mip6_timer_outqueue_handle
);
2369 untimeout(mip6_timer_outqueue
, (void *)NULL
);
2383 ******************************************************************************
2384 * Function: mip6_outq_flush
2385 * Description: All entries in the output queue that have not been sent are
2386 * sent and then removed. No consideration of the time left for
2387 * the entry is taken.
2389 * XXX The code is almost the same as in mip6_timer_outqueue
2390 ******************************************************************************
2395 struct mip6_output
*outp
; /* Ptr to current mip6 output element */
2396 struct ip6_pktopts
*pktopt
; /* Packet Ext headers, options and data */
2397 struct mip6_opt
*opt
; /* Destination option */
2398 struct mbuf
*m_ip6
; /* IPv6 header stored in a mbuf */
2399 int error
; /* Error code from function call */
2400 int off
; /* Offset from start of DH (byte) */
2403 /* Go through the entire output queue and send all packets that
2404 have not been sent. */
2406 for (outp
= mip6_outq
; outp
;) {
2407 if (outp
->flag
== NOT_SENT
) {
2408 m_ip6
= mip6_create_ip6hdr(&outp
->ip6_src
,
2411 if (m_ip6
== NULL
) {
2416 /* Allocate packet extension header. */
2417 pktopt
= (struct ip6_pktopts
*)
2418 MALLOC(sizeof(struct ip6_pktopts
),
2420 if (pktopt
== NULL
) {
2421 _FREE(m_ip6
, M_TEMP
);
2425 bzero(pktopt
, sizeof(struct ip6_pktopts
));
2426 pktopt
->ip6po_hlim
= -1; /* -1 use def hop limit */
2428 opt
= (struct mip6_opt
*)outp
->opt
;
2430 if (opt
->type
== IP6OPT_BINDING_UPDATE
) {
2431 /* Add my BU option to the Dest Header */
2432 error
= mip6_add_bu(&pktopt
->ip6po_dest2
,
2434 (struct mip6_opt_bu
*)
2438 _FREE(m_ip6
, M_TEMP
);
2439 _FREE(pktopt
, M_TEMP
);
2443 } else if (opt
->type
== IP6OPT_BINDING_ACK
) {
2444 /* Add my BA option to the Dest Header */
2445 error
= mip6_add_ba(&pktopt
->ip6po_dest2
,
2447 (struct mip6_opt_ba
*)
2451 _FREE(m_ip6
, M_TEMP
);
2452 _FREE(pktopt
, M_TEMP
);
2456 } else if (opt
->type
== IP6OPT_BINDING_REQ
) {
2457 /* Add my BR option to the Dest Header */
2458 error
= mip6_add_br(&pktopt
->ip6po_dest2
,
2460 (struct mip6_opt_br
*)
2464 _FREE(m_ip6
, M_TEMP
);
2465 _FREE(pktopt
, M_TEMP
);
2471 /* Disable the search of the output queue to make
2472 sure that we not end up in an infinite loop. */
2473 mip6_config
.enable_outq
= 0;
2474 error
= ip6_output(m_ip6
, pktopt
, NULL
, 0, NULL
, NULL
);
2476 _FREE(m_ip6
, M_TEMP
);
2477 _FREE(pktopt
, M_TEMP
);
2478 mip6_config
.enable_outq
= 1;
2481 "%s: ip6_output function failed, "
2482 "error = %d\n", __FUNCTION__
, error
);
2485 mip6_config
.enable_outq
= 1;
2488 mip6_debug("\nEntry from Output Queue sent\n");
2492 /* Remove entry from the queue that has been sent. */
2493 if (outp
->flag
== SENT
)
2494 outp
= mip6_outq_delete(outp
);
2498 /* Remove the timer if the output queue is empty */
2499 if (mip6_outq
== NULL
) {
2500 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2501 untimeout(mip6_timer_outqueue
, (void *)NULL
,
2502 mip6_timer_outqueue_handle
);
2503 callout_handle_init(&mip6_timer_outqueue_handle
);
2505 untimeout(mip6_timer_outqueue
, (void *)NULL
);
2515 ##############################################################################
2518 # These functions are called at regular basis. They operate on the lists, e.g.
2519 # reducing timer counters and removing entries from the list if needed.
2521 ##############################################################################
2525 ******************************************************************************
2526 * Function: mip6_timer_outqueue
2527 * Description: Search the outqueue for entries that have not been sent yet and
2528 * for which the lifetime has expired.
2529 * If there are more entries left in the output queue, call this
2530 * fuction again every MIP6_OUTQ_INTERVAL until the queue is
2533 ******************************************************************************
2536 mip6_timer_outqueue(arg
)
2537 void *arg
; /* Not used */
2539 struct mip6_output
*outp
; /* Ptr to current mip6 output element */
2540 struct ip6_pktopts
*pktopt
; /* Packet Ext headers, options and data */
2541 struct mip6_opt
*opt
; /* Destination option */
2542 struct mbuf
*m_ip6
; /* IPv6 header stored in a mbuf */
2543 int error
; /* Error code from function call */
2544 int off
; /* Offset from start of DH (byte) */
2547 boolean_t funnel_state
;
2548 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
2550 /* Go through the entire output queue and send all packets that
2551 have not been sent. */
2552 for (outp
= mip6_outq
; outp
;) {
2553 if (outp
->flag
== NOT_SENT
)
2554 outp
->lifetime
-= MIP6_OUTQ_INTERVAL
;
2556 if ((outp
->flag
== NOT_SENT
) && (outp
->lifetime
<= 0)) {
2557 m_ip6
= mip6_create_ip6hdr(&outp
->ip6_src
,
2560 if (m_ip6
== NULL
) {
2565 /* Allocate packet extension header. */
2566 pktopt
= (struct ip6_pktopts
*)
2567 MALLOC(sizeof(struct ip6_pktopts
),
2569 if (pktopt
== NULL
) {
2570 _FREE(m_ip6
, M_TEMP
);
2574 bzero(pktopt
, sizeof(struct ip6_pktopts
));
2575 pktopt
->ip6po_hlim
= -1; /* -1 default hop limit */
2577 opt
= (struct mip6_opt
*)outp
->opt
;
2579 if (opt
->type
== IP6OPT_BINDING_UPDATE
) {
2580 /* Add my BU option to the Dest Header */
2581 error
= mip6_add_bu(&pktopt
->ip6po_dest2
,
2583 (struct mip6_opt_bu
*)
2587 _FREE(m_ip6
, M_TEMP
);
2588 _FREE(pktopt
, M_TEMP
);
2592 } else if (opt
->type
== IP6OPT_BINDING_ACK
) {
2593 /* Add my BA option to the Dest Header */
2594 error
= mip6_add_ba(&pktopt
->ip6po_dest2
,
2596 (struct mip6_opt_ba
*)
2600 _FREE(m_ip6
, M_TEMP
);
2601 _FREE(pktopt
, M_TEMP
);
2605 } else if (opt
->type
== IP6OPT_BINDING_REQ
) {
2606 /* Add my BR option to the Dest Header */
2607 error
= mip6_add_br(&pktopt
->ip6po_dest2
,
2609 (struct mip6_opt_br
*)
2613 _FREE(m_ip6
, M_TEMP
);
2614 _FREE(pktopt
, M_TEMP
);
2620 /* Disable the search of the output queue to make
2621 sure that we not end up in an infinite loop. */
2622 mip6_config
.enable_outq
= 0;
2623 error
= ip6_output(m_ip6
, pktopt
, NULL
, 0, NULL
, NULL
);
2625 _FREE(m_ip6
, M_TEMP
);
2626 _FREE(pktopt
, M_TEMP
);
2627 mip6_config
.enable_outq
= 1;
2630 "%s: ip6_output function failed, "
2631 "error = %d\n", __FUNCTION__
, error
);
2634 mip6_config
.enable_outq
= 1;
2637 mip6_debug("\nEntry from Output Queue sent\n");
2641 /* Remove entry from the queue that has been sent. */
2642 if (outp
->flag
== SENT
)
2643 outp
= mip6_outq_delete(outp
);
2648 if (mip6_outq
!= NULL
) {
2649 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2650 mip6_timer_outqueue_handle
=
2652 timeout(mip6_timer_outqueue
, (void *)0,
2653 hz
* (MIP6_OUTQ_INTERVAL
/10));
2656 (void) thread_funnel_set(network_flock
, FALSE
);
2663 ******************************************************************************
2664 * Function: mip6_timer_bul
2665 * Description: Search the Binding Update list for entries for which the life-
2666 * time or refresh time has expired.
2667 * If there are more entries left in the output queue, call this
2668 * fuction again once every second until the queue is empty.
2670 ******************************************************************************
2674 void *arg
; /* Not used */
2676 struct mip6_bul
*bulp
; /* Ptr to current BUL element */
2677 struct mip6_bul
*new_bulp
; /* Pointer to new BUL entry */
2678 struct mip6_esm
*esp
; /* Home address entry */
2679 struct mip6_opt_bu
*bu_opt
; /* BU option to be sent */
2680 struct in6_addr
*dst_addr
; /* Destination address for BU */
2681 struct mip6_subbuf
*subbuf
; /* Buffer containing sub-options */
2682 struct mip6_bu_data bu_data
; /* Data used when a BU is created */
2683 struct mip6_subopt_coa altcoa
; /* Alternate care-of address */
2686 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
2687 long time_second
= time
.tv_sec
;
2690 boolean_t funnel_state
;
2691 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
2694 /* Go through the entire BUL and check if any BU have to be sent. */
2697 for (bulp
= mip6_bulq
; bulp
;) {
2698 /* Find the correct event-state machine */
2699 esp
= mip6_esm_find(&bulp
->bind_addr
);
2705 /* If infinity lifetime, don't decrement it. */
2706 if (bulp
->lifetime
== 0xffffffff) {
2711 bulp
->lifetime
-= 1;
2712 if (bulp
->lifetime
== 0) {
2713 if ((bulp
->hr_flag
) && (esp
->type
== PERMANENT
)) {
2714 /* If this BUL entry is for the Home Agent
2715 a new one must be created before the old
2716 is deleted. The new entry shall try to
2717 register the MN again.
2718 This is not done for the previous default
2720 if ((esp
->state
== MIP6_STATE_REG
) ||
2721 (esp
->state
== MIP6_STATE_REREG
) ||
2722 (esp
->state
== MIP6_STATE_REGNEWCOA
) ||
2723 (esp
->state
== MIP6_STATE_NOTREG
))
2724 esp
->state
= MIP6_STATE_NOTREG
;
2725 else if ((esp
->state
== MIP6_STATE_HOME
) ||
2726 (esp
->state
== MIP6_STATE_DEREG
))
2727 esp
->state
= MIP6_STATE_DEREG
;
2729 esp
->state
= MIP6_STATE_UNDEF
;
2731 /* If Dynamic Home Agent Address Discovery,
2732 pick the dst address from the esp->dad list
2735 dst_addr
= &esp
->dad
->hal
->
2736 halist
[esp
->dad
->index
];
2737 max_index
= (esp
->dad
->hal
->len
/
2739 if (esp
->dad
->index
== max_index
)
2740 esp
->dad
->index
= 0;
2742 esp
->dad
->index
+= 1;
2743 lifetime
= MIP6_BU_LIFETIME_DHAAD
;
2745 dst_addr
= &esp
->ha_hn
;
2746 lifetime
= mip6_config
.hr_lifetime
;
2749 /* Send BU to the decided destination */
2750 new_bulp
= mip6_bul_create(dst_addr
,
2754 if (new_bulp
== NULL
)
2757 bu_data
.prefix_len
= esp
->prefix_len
;
2760 if (mip6_send_bu(new_bulp
, &bu_data
, NULL
)
2765 /* The BUL entry must be deleted. */
2766 bulp
= mip6_bul_delete(bulp
);
2770 if (bulp
->refreshtime
> 0)
2771 bulp
->refreshtime
-= 1;
2773 /* Skip the bul entry if its not allowed to send any further
2775 if (bulp
->bu_flag
== 0) {
2780 /* Check if a BU has already been sent to the destination. */
2781 if (bulp
->state
!= NULL
) {
2782 bulp
->state
->time_left
-= 1;
2783 if (bulp
->state
->time_left
== 0) {
2784 if (bulp
->hr_flag
) {
2785 /* This is a BUL entry for the HA */
2786 bulp
->state
->bu_opt
->lifetime
=
2788 bulp
->state
->bu_opt
->seqno
++;
2789 if (mip6_send_bu(bulp
, NULL
, NULL
)
2793 if (bulp
->state
->ba_timeout
<
2794 MIP6_MAX_BINDACK_TIMEOUT
)
2795 bulp
->state
->ba_timeout
=
2799 bulp
->state
->ba_timeout
=
2800 (u_int8_t
)MIP6_MAX_BINDACK_TIMEOUT
;
2802 bulp
->state
->time_left
= bulp
->state
->ba_timeout
;
2804 /* This is a BUL entry for a Correspondent Node */
2805 if (bulp
->state
->ba_timeout
>= MIP6_MAX_BINDACK_TIMEOUT
) {
2806 /* Do NOT continue to retransmit the BU */
2807 bulp
->no_of_sent_bu
= 0;
2808 mip6_clear_retrans(bulp
);
2810 bulp
->state
->bu_opt
->lifetime
= bulp
->lifetime
;
2811 bulp
->state
->bu_opt
->seqno
++;
2812 if (mip6_send_bu(bulp
, NULL
, NULL
) != 0)
2815 bulp
->state
->ba_timeout
= 2 * bulp
->state
->ba_timeout
;
2816 bulp
->state
->time_left
= bulp
->state
->ba_timeout
;
2824 /* Refreshtime has expired and no BU has been sent to the HA
2825 so far. Then we do it. */
2826 if (bulp
->refreshtime
== 0) {
2827 /* Store sub-option for BU option. */
2828 altcoa
.type
= IP6SUBOPT_ALTCOA
;
2829 altcoa
.len
= IP6OPT_COALEN
;
2830 altcoa
.coa
= bulp
->coa
;
2831 if (mip6_store_subopt(&subbuf
, (caddr_t
)&altcoa
)) {
2833 _FREE(subbuf
, M_TEMP
);
2837 if (bulp
->hr_flag
) {
2838 /* Since this is an entry for the Home Agent a new BU
2839 is being sent for which we require the receiver to
2840 respond with a BA. */
2841 bu_data
.prefix_len
= esp
->prefix_len
;
2844 bulp
->lifetime
= mip6_config
.hr_lifetime
;
2845 if (mip6_send_bu(bulp
, &bu_data
, subbuf
) != 0)
2848 /* This is an entry for a CN that has requested a BU to be
2849 sent when the refreshtime expires. We will NOT require
2850 this BU to be acknowledged. */
2852 bu_opt
= mip6_create_bu(0, 0, 0, bulp
->seqno
,
2853 mip6_config
.hr_lifetime
);
2857 bulp
->lasttime
= time_second
;
2858 mip6_outq_create(bu_opt
, subbuf
, &bulp
->bind_addr
,
2859 &bulp
->dst_addr
, NOT_SENT
);
2867 if (mip6_bulq
!= NULL
) {
2868 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2869 mip6_timer_bul_handle
=
2871 timeout(mip6_timer_bul
, (void *)0, hz
);
2875 (void) thread_funnel_set(network_flock
, FALSE
);
2882 ******************************************************************************
2883 * Function: mip6_timer_esm
2884 * Description: This function is called when an event-state machine has been
2885 * created for sending a BU to the previous default router. The
2886 * event-state machine entry is needed for the correct addition
2887 * of the home address option for outgoing packets.
2888 * When the life time for the BU expires the event-state machine
2889 * is removed as well.
2891 ******************************************************************************
2895 void *arg
; /* Not used */
2897 struct mip6_esm
*esp
; /* Current event-state machine entry */
2900 boolean_t funnel_state
;
2901 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
2904 /* Go through the entire list of event-state machines. */
2906 for (esp
= mip6_esmq
; esp
;) {
2907 if (esp
->type
== TEMPORARY
) {
2910 if (esp
->lifetime
== 0)
2911 esp
= mip6_esm_delete(esp
);
2919 /* Only start the timer if there is a TEMPORARY machine in the list. */
2921 for (esp
= mip6_esmq
; esp
; esp
= esp
->next
) {
2922 if (esp
->type
== TEMPORARY
) {
2929 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
2930 mip6_timer_esm_handle
=
2932 timeout(mip6_timer_esm
, (void *)0, hz
);
2936 (void) thread_funnel_set(network_flock
, FALSE
);
2943 ##############################################################################
2946 # These functions are called from mip6_ioctl.
2948 ##############################################################################
2952 ******************************************************************************
2953 * Function: mip6_write_config_data_mn
2954 * Description: This function is called to write certain config values for
2955 * MIPv6. The data is written into the global config structure.
2957 ******************************************************************************
2959 int mip6_write_config_data_mn(u_long cmd
, void *arg
)
2963 struct mip6_input_data
*input
;
2964 struct mip6_static_addr
*np
;
2967 struct in6_addr any
= in6addr_any
;
2970 case SIOCACOADDR_MIP6
:
2971 input
= (struct mip6_input_data
*) arg
;
2972 np
= (struct mip6_static_addr
*)
2973 MALLOC(sizeof(struct mip6_static_addr
),
2978 np
->ip6_addr
= input
->ip6_addr
;
2979 np
->prefix_len
= input
->prefix_len
;
2980 np
->ifp
= ifunit(input
->if_name
);
2981 if (np
->ifp
== NULL
) {
2982 strncpy(ifn
, input
->if_name
, sizeof(ifn
));
2985 LIST_INSERT_HEAD(&mip6_config
.fna_list
, np
, addr_entry
);
2988 case SIOCAHOMEADDR_MIP6
:
2989 input
= (struct mip6_input_data
*) arg
;
2990 ifp
= ifunit(input
->if_name
);
2994 p
= mip6_esm_create(ifp
, &input
->ha_addr
, &any
,
2995 &input
->ip6_addr
, input
->prefix_len
,
2996 MIP6_STATE_UNDEF
, PERMANENT
, 0xFFFF);
2998 return EINVAL
; /*XXX*/
3002 case SIOCSBULIFETIME_MIP6
:
3003 mip6_config
.bu_lifetime
= ((struct mip6_input_data
*)arg
)->value
;
3006 case SIOCSHRLIFETIME_MIP6
:
3007 mip6_config
.hr_lifetime
= ((struct mip6_input_data
*)arg
)->value
;
3010 case SIOCDCOADDR_MIP6
:
3011 input
= (struct mip6_input_data
*) arg
;
3012 for (np
= mip6_config
.fna_list
.lh_first
; np
!= NULL
;
3013 np
= np
->addr_entry
.le_next
){
3014 if (IN6_ARE_ADDR_EQUAL(&input
->ip6_addr
, &np
->ip6_addr
))
3018 retval
= EADDRNOTAVAIL
;
3021 LIST_REMOVE(np
, addr_entry
);
3030 ******************************************************************************
3031 * Function: mip6_clear_config_data_mn
3032 * Description: This function is called to clear internal lists handled by
3035 ******************************************************************************
3037 int mip6_clear_config_data_mn(u_long cmd
, caddr_t data
)
3042 struct mip6_static_addr
*np
;
3043 struct mip6_bul
*bulp
;
3047 case SIOCSFORADDRFLUSH_MIP6
:
3048 for (np
= LIST_FIRST(&mip6_config
.fna_list
); np
;
3049 np
= LIST_NEXT(np
, addr_entry
)) {
3050 LIST_REMOVE(np
, addr_entry
);
3054 case SIOCSHADDRFLUSH_MIP6
:
3058 case SIOCSBULISTFLUSH_MIP6
:
3059 for (bulp
= mip6_bulq
; bulp
;)
3060 bulp
= mip6_bul_delete(bulp
);
3070 ******************************************************************************
3071 * Function: mip6_enable_func_mn
3072 * Description: This function is called to enable or disable certain functions
3073 * in mip6. The data is written into the global config struct.
3075 ******************************************************************************
3077 int mip6_enable_func_mn(u_long cmd
, caddr_t data
)
3082 enable
= ((struct mip6_input_data
*)data
)->value
;
3085 case SIOCSPROMMODE_MIP6
:
3086 mip6_config
.enable_prom_mode
= enable
;
3089 case SIOCSBU2CN_MIP6
:
3090 mip6_config
.enable_bu_to_cn
= enable
;
3093 case SIOCSREVTUNNEL_MIP6
:
3094 mip6_config
.enable_rev_tunnel
= enable
;
3097 case SIOCSAUTOCONFIG_MIP6
:
3098 mip6_config
.autoconfig
= enable
;
3101 case SIOCSEAGERMD_MIP6
:
3102 mip6_eager_md(enable
);