1 /* $KAME: mip6_ha.c,v 1.8 2000/03/18 03:05:40 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 Home Agent
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/route.h>
61 #include <netinet/in.h>
62 #include <netinet/in_var.h>
63 #include <netinet/ip6.h>
64 #include <netinet6/nd6.h>
65 #include <netinet6/ip6_var.h>
66 #include <netinet/icmp6.h>
67 #include <netinet6/mip6.h>
68 #include <netinet6/mip6_common.h>
69 #include <machine/limits.h>
71 #include <net/net_osdep.h>
73 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
74 /* Declaration of Global variables. */
75 struct callout_handle mip6_timer_ll_handle
;
80 ##############################################################################
82 # INITIALIZATION AND EXIT FUNCTIONS
83 # These functions are executed when the MIPv6 code is activated and de-
84 # activated respectively.
86 ##############################################################################
90 ******************************************************************************
91 * Function: mip6_ha_init
92 * Description: Initialization of MIPv6 variables that must be initialized
93 * before the HA code is executed.
94 ******************************************************************************
99 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
100 /* Initialize handle for timer functions. */
101 callout_handle_init(&mip6_timer_ll_handle
);
108 ******************************************************************************
109 * Function: mip6_ha_exit
110 * Description: This function is called when the HA module is unloaded
111 * (relesed) from the kernel.
112 ******************************************************************************
117 struct mip6_link_list
*llp
;
120 /* Cancel outstanding timeout function calls. */
121 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
122 untimeout(mip6_timer_ll
, (void *)NULL
, mip6_timer_ll_handle
);
124 untimeout(mip6_timer_ll
, (void *)NULL
);
127 /* Remove each entry in every queue. */
129 for (llp
= mip6_llq
; llp
;)
130 llp
= mip6_ll_delete(llp
);
138 ##############################################################################
140 # RECEIVING FUNCTIONS
141 # These functions receives the incoming IPv6 packet and further processing of
142 # the packet depends on the content in the packet.
144 ##############################################################################
148 ******************************************************************************
149 * Function: mip6_rec_raha
150 * Description: Processed by a Home Agent. Includes a Router Advertisement
151 * with a H-bit set in the flags variable (checked by the calling
153 * A link list entry and a Home Agent List entry are created or
154 * modified if needed.
155 * Ret value: 0 Everything is OK. Otherwise appropriate error code.
156 ******************************************************************************
159 mip6_rec_raha(m
, off
)
160 struct mbuf
*m
; /* Mbuf containing the entire IPv6 packet */
161 int off
; /* Offset from start of mbuf to start of RA */
163 struct ifnet
*ifp
; /* Receiving interface */
164 struct ip6_hdr
*ip6
; /* IPv6 header */
165 struct nd_router_advert
*ra
; /* Router Advertisement */
166 struct mip6_link_list
*llp
; /* Link list entry */
167 struct mip6_ha_list
*halp
; /* Home Agent list entry */
168 caddr_t icmp6msg
; /* Copy of mbuf (consequtively) */
169 char ifname
[IFNAMSIZ
+1]; /* Interface name */
170 int res
, s
, icmp6len
;
172 /* Find out if the RA can be processed */
173 ip6
= mtod(m
, struct ip6_hdr
*);
174 if (ip6
->ip6_hlim
!= 255) {
176 "%s: Invalid hlim %d in Router Advertisement\n",
177 __FUNCTION__
, ip6
->ip6_hlim
);
181 if (!IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_src
)) {
183 "%s: Source Address %s is not link-local\n",
184 __FUNCTION__
, ip6_sprintf(&ip6
->ip6_src
));
188 /* Find out which interface the RA arrived at */
189 ifp
= m
->m_pkthdr
.rcvif
;
190 sprintf(ifname
, "%s", if_name(ifp
));
192 llp
= mip6_ll_find(ifname
);
194 llp
= mip6_ll_create(ifname
, ifp
);
199 /* The mbuf data must be stored consequtively to be able to
200 cast data from it. */
201 icmp6len
= m
->m_pkthdr
.len
- off
;
202 icmp6msg
= (caddr_t
)MALLOC(icmp6len
, M_TEMP
, M_NOWAIT
);
203 if (icmp6msg
== NULL
)
206 m_copydata(m
, off
, icmp6len
, icmp6msg
);
207 ra
= (struct nd_router_advert
*)icmp6msg
;
209 /* Find the Home Agent sending the RA and read its options.
210 This section must have high priority since the Home Agent
211 list entry lifetime is initialized to 0 and could be
212 removed by the timer function before the RA options have
215 halp
= mip6_hal_find(llp
->ha_list
, &ip6
->ip6_src
);
217 halp
= mip6_hal_create(&llp
->ha_list
, &ip6
->ip6_src
,
218 ntohl(ra
->nd_ra_router_lifetime
), 0);
224 halp
->lifetime
= ntohl(ra
->nd_ra_router_lifetime
);
228 res
= mip6_ra_options(halp
, icmp6msg
, icmp6len
);
240 ##############################################################################
243 # Miscellaneous functions needed for the internal processing of incoming and
244 # outgoing control signals.
246 ##############################################################################
250 ******************************************************************************
251 * Function: mip6_ra_options
252 * Description: Search through all the options in the Router Advertisement
253 * and store them in the Home Agent List.
254 * Ret value: 0 Everything is OK. Otherwise appropriate error code.
255 ******************************************************************************
258 mip6_ra_options(halp
, icmp6msg
, icmp6len
)
259 struct mip6_ha_list
*halp
; /* Home Agent list entry */
260 caddr_t icmp6msg
; /* icmp6 message */
261 int icmp6len
; /* Length of icmp6 message */
263 struct mip6_addr_list
*ap
; /* Address list entry */
264 struct nd_opt_hai
*hai
; /* Home Agent information option */
265 struct nd_opt_advint
*ai
; /* Advertisement Interval option */
266 struct nd_opt_prefix_info
*pi
; /* Ptr to prefix information */
267 u_int8_t
*optp
; /* Ptr to current option in RA */
268 int cur_off
; /* Cur offset from start of RA */
270 /* Process each option in the RA */
271 cur_off
= sizeof(struct nd_router_advert
);
272 while (cur_off
< icmp6len
) {
273 optp
= ((caddr_t
)icmp6msg
+ cur_off
);
274 if (*optp
== ND_OPT_PREFIX_INFORMATION
) {
275 /* Check the prefix information option */
276 pi
= (struct nd_opt_prefix_info
*)optp
;
277 if (pi
->nd_opt_pi_len
!= 4) {
278 ip6stat
.ip6s_badoptions
++;
282 if (!(pi
->nd_opt_pi_flags_reserved
&
283 ND_OPT_PI_FLAG_RTADDR
)) {
288 if (IN6_IS_ADDR_MULTICAST(&pi
->nd_opt_pi_prefix
) ||
289 IN6_IS_ADDR_LINKLOCAL(&pi
->nd_opt_pi_prefix
)) {
294 /* Aggregatable unicast address, rfc2374 */
295 if (((pi
->nd_opt_pi_prefix
.s6_addr8
[0] & 0xe0) > 0x10)
296 && (pi
->nd_opt_pi_prefix_len
!= 64)) {
301 /* Store the address if not already present */
302 for (ap
= halp
->addr_list
; ap
; ap
= ap
->next
) {
303 if (IN6_ARE_ADDR_EQUAL(&ap
->ip6_addr
,
304 &pi
->nd_opt_pi_prefix
))
309 /* Create a new address list entry. */
310 ap
= (struct mip6_addr_list
*)
311 MALLOC(sizeof(struct mip6_addr_list
),
315 bzero(ap
, sizeof(struct mip6_addr_list
));
317 ap
->next
= halp
->addr_list
;
318 ap
->ip6_addr
= pi
->nd_opt_pi_prefix
;
319 ap
->prefix_len
= pi
->nd_opt_pi_prefix_len
;
320 halp
->addr_list
= ap
;
324 } else if (*optp
== ND_OPT_ADV_INTERVAL
) {
325 /* Check the advertisement interval option */
326 ai
= (struct nd_opt_advint
*)optp
;
327 if (ai
->nd_opt_int_len
!= 1) {
328 ip6stat
.ip6s_badoptions
++;
332 /* XXX. Function call to move detection */
335 } else if (*optp
== ND_OPT_HA_INFORMATION
) {
336 /* Check the home agent information option */
337 hai
= (struct nd_opt_hai
*)optp
;
338 if (hai
->nd_opt_hai_len
!= 1) {
339 ip6stat
.ip6s_badoptions
++;
343 halp
->pref
= ntohs(hai
->nd_opt_hai_pref
);
344 halp
->lifetime
= ntohs(hai
->nd_opt_hai_lifetime
);
348 if (*(optp
+ 1) == 0) {
349 ip6stat
.ip6s_badoptions
++;
352 cur_off
+= *(optp
+ 1) * 8;
361 ******************************************************************************
362 * Function: mip6_hal_dynamic
363 * Description: Search through all the link lists and home agents list and
364 * create a Home Agents List sub-option to be used in dynamic
365 * home agent address discovery.
366 * If my own global source address is included in the first
367 * home agents list entry, leave it. It will be in the source
368 * address of the outgoing packet anyway.
369 * Ret value: Ptr to the sub-option or NULL.
370 ******************************************************************************
372 struct mip6_subopt_hal
*
373 mip6_hal_dynamic(own_addr
)
374 struct in6_addr
*own_addr
; /* Own global unicast source address used */
376 struct mip6_link_list
*llp
; /* Link list entry */
377 struct mip6_ha_list
*halp
; /* Home Agent list entry */
378 struct mip6_subopt_hal
*opt
; /* Home Agents list sub-option */
379 struct mip6_addr_list
*addrp
; /* Address list entry */
380 struct mip6_addr_list
*tmp_addrp
; /* Temporary address list entry */
381 struct ifaddr
*if_addr
; /* Interface data */
382 struct sockaddr_in6 sin6
;
383 char ifname
[IFNAMSIZ
+1]; /* Interface name */
386 /* Find the interface */
387 bzero(&sin6
, sizeof(struct sockaddr_in6
));
388 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
389 sin6
.sin6_family
= AF_INET6
;
390 sin6
.sin6_addr
= *own_addr
;
392 if_addr
= ifa_ifwithaddr((struct sockaddr
*)&sin6
);
396 sprintf(ifname
, "%s", if_name(if_addr
->ifa_ifp
));
398 llp
= mip6_ll_find(ifname
);
402 /* Allocate memory for home agent list sub option */
403 opt
= (struct mip6_subopt_hal
*)MALLOC(sizeof(struct mip6_subopt_hal
) +
404 31 * sizeof(struct in6_addr
),
409 opt
->type
= IP6SUBOPT_HALIST
;
412 /* Search the home agents list for the specific link. */
413 /* First, sort the Home Agent list in decending order */
414 mip6_hal_sort(&llp
->ha_list
);
416 for (halp
= llp
->ha_list
; halp
; halp
= halp
->next
) {
419 for (addrp
= halp
->addr_list
; addrp
; addrp
= addrp
->next
) {
420 len
= addrp
->prefix_len
;
421 if (in6_are_prefix_equal(own_addr
, &addrp
->ip6_addr
, len
)) {
422 if (IN6_ARE_ADDR_EQUAL(own_addr
, &addrp
->ip6_addr
)) {
425 } else if (tmp_addrp
== NULL
)
430 if (found
&& (ii
!= 0)) {
431 opt
->halist
[ii
] = addrp
->ip6_addr
;
432 opt
->len
+= IP6OPT_HALISTLEN
;
434 } else if (tmp_addrp
!= NULL
) {
435 opt
->halist
[ii
] = tmp_addrp
->ip6_addr
;
436 opt
->len
+= IP6OPT_HALISTLEN
;
452 ******************************************************************************
453 * Function: mip6_global_addr
454 * Description: Search the list of IP addresses and find the interface for
455 * the anycast address. Find a link local address and use this
456 * address while searching through the list of home agents.
457 * When my own home agent is found, pick the first global address
458 * which matches the aycast prefix.
459 * Ret value: Ptr to the global unicast address or NULL.
460 ******************************************************************************
463 mip6_global_addr(anycast_addr
)
464 struct in6_addr
*anycast_addr
; /* Home Agents anycast address */
466 struct in6_ifaddr
*ia
; /* I/f address for anycast address */
467 struct in6_ifaddr
*ia_ll
; /* I/f address for link local address */
468 struct ifnet
*ifp
; /* Interface */
469 struct mip6_ha_list
*halp
; /* Home Agent list entry */
470 struct mip6_addr_list
*addrp
; /* Address list entry */
471 struct mip6_link_list
*llp
; /* Link list entry for anycast address */
472 char ifname
[IFNAMSIZ
+1]; /* Interface name */
474 /* Find out the interface for the anycast address */
475 for (ia
= in6_ifaddr
; ia
; ia
= ia
->ia_next
)
477 if (ia
->ia_addr
.sin6_family
!= AF_INET6
)
479 if ((ia
->ia6_flags
& IN6_IFF_ANYCAST
) &&
480 IN6_ARE_ADDR_EQUAL(anycast_addr
, &ia
->ia_addr
.sin6_addr
))
487 ifp
= ia
->ia_ifa
.ifa_ifp
;
488 sprintf(ifname
, "%s", if_name(ifp
));
489 llp
= mip6_ll_find(ifname
);
493 /* Use link local address to identify my own home agent list entry */
494 /* XXX: I'm not sure if the 2nd arg is OK(jinmei@kame) */
495 ia_ll
= in6ifa_ifpforlinklocal(ifp
, 0);
498 halp
= mip6_hal_find(llp
->ha_list
, &ia_ll
->ia_addr
.sin6_addr
);
502 /* Find my global address */
503 for (addrp
= halp
->addr_list
; addrp
; addrp
= addrp
->next
) {
504 if (in6_are_prefix_equal(anycast_addr
, &addrp
->ip6_addr
,
506 return &addrp
->ip6_addr
;
514 ******************************************************************************
515 * Function: mip6_icmp6_output
516 * Description: Takes care of an outgoing Router Advertisement. It finds the
517 * outgoing interface and add each prefix to the home agents list.
518 * Each prefix is also added to the internal prefix list used
519 * when a BU is received to decide whether the MN is on-link or
522 ******************************************************************************
526 struct mbuf
*m
; /* Mbuf chain with IPv6 packet */
528 struct ip6_hdr
*ip6
; /* IPv6 header */
529 struct icmp6_hdr
*icmp6
; /* ICMP6 header */
530 struct nd_router_advert
*ra
; /* Router Advertisement */
531 struct ifaddr
*if_addr
; /* Interface address */
532 struct mip6_link_list
*llp
; /* Link list entry */
533 struct mip6_ha_list
*halp
; /* Home Agent list entry */
534 struct sockaddr_in6 sin6
;
535 caddr_t icmp6msg
; /* Copy of mbuf (consequtively) */
536 char ifname
[IFNAMSIZ
+1]; /* Interface name */
537 int icmp6len
, s
, res
;
539 /* Check if the packet shall be processed */
540 if (!MIP6_IS_HA_ACTIVE
)
543 ip6
= mtod(m
, struct ip6_hdr
*);
544 if (ip6
->ip6_nxt
!= IPPROTO_ICMPV6
)
547 /* The mbuf data must be stored consequtively to be able to cast data
549 icmp6len
= m
->m_pkthdr
.len
- sizeof(struct ip6_hdr
);
550 icmp6msg
= (caddr_t
)MALLOC(icmp6len
, M_TEMP
, M_WAITOK
);
551 if (icmp6msg
== NULL
)
554 m_copydata(m
, sizeof(struct ip6_hdr
), icmp6len
, icmp6msg
);
555 icmp6
= (struct icmp6_hdr
*)icmp6msg
;
557 /* Check if the packet shall be processed */
558 if (icmp6
->icmp6_type
!= ND_ROUTER_ADVERT
) {
559 _FREE(icmp6msg
, M_TEMP
);
563 if (icmp6
->icmp6_code
!= 0) {
564 _FREE(icmp6msg
, M_TEMP
);
568 if (icmp6len
< sizeof(struct nd_router_advert
)) {
569 _FREE(icmp6msg
, M_TEMP
);
573 /* Find the outgoing interface */
574 bzero(&sin6
, sizeof(struct sockaddr_in6
));
575 sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
576 sin6
.sin6_family
= AF_INET6
;
577 sin6
.sin6_addr
= ip6
->ip6_src
;
579 if_addr
= ifa_ifwithaddr((struct sockaddr
*)&sin6
);
580 if (if_addr
== NULL
) {
581 _FREE(icmp6msg
, M_TEMP
);
585 sprintf(ifname
, "%s", if_name(if_addr
->ifa_ifp
));
587 llp
= mip6_ll_find(ifname
);
589 llp
= mip6_ll_create(ifname
, if_addr
->ifa_ifp
);
591 _FREE(icmp6msg
, M_TEMP
);
596 /* Find the Home Agent sending the RA and read its options.
597 This section must have high priority since the Home Agent list
598 entry lifetime is initialized to 0 and could be removed by the
599 timer function before the RA options have been evaluated. */
601 ra
= (struct nd_router_advert
*)icmp6
;
602 halp
= mip6_hal_find(llp
->ha_list
, &ip6
->ip6_src
);
604 halp
= mip6_hal_create(&llp
->ha_list
, &ip6
->ip6_src
,
605 ntohl(ra
->nd_ra_router_lifetime
), 0);
607 _FREE(icmp6msg
, M_TEMP
);
612 halp
->lifetime
= ntohl(ra
->nd_ra_router_lifetime
);
616 res
= mip6_ra_options(halp
, icmp6msg
, icmp6len
);
618 _FREE(icmp6msg
, M_TEMP
);
624 /* Add the prefix to prefix list and the anycast address to the
626 mip6_prefix_examine(halp
, if_addr
->ifa_ifp
, icmp6msg
, icmp6len
);
627 _FREE(icmp6msg
, M_TEMP
);
634 ******************************************************************************
635 * Function: mip6_prefix_examine
636 * Description: Add each prefix in a RA to the internal prefix list. Make
637 * sure that the Home-Agents anycast address for the prefix
638 * has been assigned to the interface.
640 ******************************************************************************
643 mip6_prefix_examine(halp
, ifp
, icmp6msg
, icmp6len
)
644 struct mip6_ha_list
*halp
; /* Home Agent list entry */
645 struct ifnet
*ifp
; /* Outgoing i/f for prefixes */
646 caddr_t icmp6msg
; /* icmp6 message */
647 int icmp6len
; /* Length of icmp6 message */
649 struct nd_opt_prefix_info
*pi
; /* Ptr to prefix information */
650 struct mip6_prefix
*pq
; /* Prefix queue entry */
651 struct in6_addr anycast_addr
;
652 int cur_off
; /* Cur offset from start of mbuf */
653 u_int8_t
*opt_ptr
; /* Ptr to current option in RA */
655 /* Process each option in the RA */
656 cur_off
= sizeof(struct nd_router_advert
);
657 while (cur_off
< icmp6len
) {
658 opt_ptr
= ((caddr_t
)icmp6msg
+ cur_off
);
659 if (*opt_ptr
== ND_OPT_PREFIX_INFORMATION
) {
660 /* Check the prefix information option */
661 pi
= (struct nd_opt_prefix_info
*)opt_ptr
;
662 if (pi
->nd_opt_pi_len
!= 4)
665 if (!(pi
->nd_opt_pi_flags_reserved
& ND_OPT_PI_FLAG_ONLINK
)) {
670 if (IN6_IS_ADDR_MULTICAST(&pi
->nd_opt_pi_prefix
) ||
671 IN6_IS_ADDR_LINKLOCAL(&pi
->nd_opt_pi_prefix
)) {
676 /* Aggregatable unicast address, rfc2374 */
677 if (((pi
->nd_opt_pi_prefix
.s6_addr8
[0] & 0xe0) > 0x10) &&
678 (pi
->nd_opt_pi_prefix_len
!= 64)) {
683 /* Store the prefix if not already present */
684 pq
= mip6_prefix_find(&pi
->nd_opt_pi_prefix
,
685 pi
->nd_opt_pi_prefix_len
);
688 pq
= mip6_prefix_create(ifp
, &pi
->nd_opt_pi_prefix
,
689 pi
->nd_opt_pi_prefix_len
,
690 pi
->nd_opt_pi_valid_time
);
694 /* Create an Home Agent anycast address, add it to the
696 mip6_build_ha_anycast(&anycast_addr
,
697 &pi
->nd_opt_pi_prefix
,
698 pi
->nd_opt_pi_prefix_len
);
699 error
= mip6_add_ifaddr(&anycast_addr
, ifp
,
700 pi
->nd_opt_pi_prefix_len
,
703 printf("%s: address assignment error (errno = %d).\n",
704 __FUNCTION__
, error
);
707 pq
->valid_time
= ntohl(pi
->nd_opt_pi_valid_time
);
712 if (*(opt_ptr
+ 1) == 0) {
715 cur_off
+= *(opt_ptr
+ 1) * 8;
723 ##############################################################################
726 # The Home Agent maintains three lists (link list, home agent list and global
727 # address list) which are integrated into each other. Besides from this an
728 # internal prefix list is maintained in order to know which prefixes it is
729 # supposed to be home network for. The functions in this section are used for
730 # maintenance (create, find, delete and update entries) of these lists.
732 ##############################################################################
736 ******************************************************************************
737 * Function: mip6_ll_find
738 * Description: For each physical interface, i.e. link, that a Home Agent
739 * send and receive Router Advertisements at, a link list entry
741 * Ret value: Pointer to found link list entry or NULL.
742 ******************************************************************************
744 struct mip6_link_list
*
748 struct mip6_link_list
*llp
;
750 for (llp
= mip6_llq
; llp
; llp
= llp
->next
) {
751 if (strcmp(ifname
, llp
->ifname
) == 0)
760 ******************************************************************************
761 * Function: mip6_ll_create
762 * Description: Create a new link list entry and add it first to the link
763 * list. Start the timer if not already started.
764 * Ret value: Pointer to created link list entry or NULL.
765 ******************************************************************************
767 struct mip6_link_list
*
768 mip6_ll_create(ifname
, ifp
)
772 struct mip6_link_list
*llp
;
773 int s
, start_timer
= 0;
775 if (mip6_llq
== NULL
)
778 llp
= (struct mip6_link_list
*)MALLOC(sizeof(struct mip6_link_list
),
782 bzero(llp
, sizeof(struct mip6_link_list
));
784 /* Add the new link list entry first to the list. */
786 llp
->next
= mip6_llq
;
787 strcpy(llp
->ifname
, ifname
);
794 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
795 mip6_timer_ll_handle
=
797 timeout(mip6_timer_ll_funneled
, (void *)0, hz
);
805 ******************************************************************************
806 * Function: mip6_ll_delete
807 * Description: Delete the requested link list entry.
808 * Ret value: Ptr to next entry in list or NULL if last entry removed.
809 ******************************************************************************
811 struct mip6_link_list
*
812 mip6_ll_delete(llp_del
)
813 struct mip6_link_list
*llp_del
; /* Link list entry to be deleted */
815 struct mip6_link_list
*llp
; /* Current entry in the list */
816 struct mip6_link_list
*llp_prev
; /* Previous entry in the list */
817 struct mip6_link_list
*llp_next
; /* Next entry in the list */
818 struct mip6_ha_list
*halp
; /* Home Agents list */
821 /* Find the requested entry in the link list. */
825 for (llp
= mip6_llq
; llp
; llp
= llp
->next
) {
826 llp_next
= llp
->next
;
827 if (llp
== llp_del
) {
828 if (llp_prev
== NULL
)
829 mip6_llq
= llp
->next
;
831 llp_prev
->next
= llp
->next
;
834 for (halp
= llp
->ha_list
; halp
;)
835 halp
= mip6_hal_delete(&llp
->ha_list
, halp
);
839 mip6_debug("\nLink List entry deleted (0x%x)\n", llp
);
843 /* Remove the timer if the BC queue is empty */
844 if (mip6_llq
== NULL
) {
845 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
846 untimeout(mip6_timer_ll
, (void *)NULL
, mip6_timer_ll_handle
);
847 callout_handle_init(&mip6_timer_ll_handle
);
849 untimeout(mip6_timer_ll
, (void *)NULL
);
863 ******************************************************************************
864 * Function: mip6_hal_find
865 * Description: Find a Home Agent list entry at a specific link. There will
866 * be one entry for each node sending a Router Advertisement
867 * with the H-bit set including a Prefix Information option
868 * with the R-bit set, for which the Router lifetime or the
869 * Home Agent lifetime (included in a separate option) is not 0.
870 * Ret value: Pointer to found Home Agent list entry or NULL.
871 ******************************************************************************
873 struct mip6_ha_list
*
874 mip6_hal_find(hal_start
, ll_addr
)
875 struct mip6_ha_list
*hal_start
; /* First entry in the Home Agents list */
876 struct in6_addr
*ll_addr
; /* Link local address to search for */
878 struct mip6_ha_list
*halp
;
880 for (halp
= hal_start
; halp
; halp
= halp
->next
) {
881 if (IN6_ARE_ADDR_EQUAL(&halp
->ll_addr
, ll_addr
))
890 ******************************************************************************
891 * Function: mip6_hal_create
892 * Description: Create a Home Agent list entry for a specific link.
893 * Ret value: Pointer to created Home Agent list entry or NULL.
894 ******************************************************************************
896 struct mip6_ha_list
*
897 mip6_hal_create(hal_start
, ll_addr
, lifetime
, pref
)
898 struct mip6_ha_list
**hal_start
; /* First entry in the Home Agents list */
899 struct in6_addr
*ll_addr
; /* Link local address to search for */
900 u_int32_t lifetime
; /* Node lifetime */
901 int16_t pref
; /* Node preference */
903 struct mip6_ha_list
*halp
;
906 halp
= (struct mip6_ha_list
*)MALLOC(sizeof(struct mip6_ha_list
),
910 bzero(halp
, sizeof(struct mip6_ha_list
));
912 /* Add the new home agent list entry first to the list. */
914 halp
->next
= *hal_start
;
915 halp
->ll_addr
= *ll_addr
;
916 halp
->lifetime
= lifetime
;
918 halp
->addr_list
= NULL
;
927 ******************************************************************************
928 * Function: mip6_hal_sort
929 * Description: Sort the Home Agent list in decending order. Uses a temporary
930 * list where all the existing elements are moved.
932 ******************************************************************************
935 mip6_hal_sort(ha_head
)
936 struct mip6_ha_list
**ha_head
; /* Start of Home Agent list */
938 struct mip6_ha_list
*start
, *halp
;
939 struct mip6_ha_list
*halp_prev
, *halp_before
, *halp_move
;
940 struct mip6_ha_list
*local_start
, *local_last
;
944 if (*ha_head
== NULL
)
953 /* Find entry with highest preference */
954 last_pref
= SHRT_MIN
;
956 for (halp
= start
; halp
; halp
= halp
->next
) {
957 if (halp
->pref
> last_pref
) {
958 last_pref
= halp
->pref
;
960 halp_before
= halp_prev
;
965 /* Move it to the new list */
966 if (local_start
== NULL
)
967 local_start
= halp_move
;
969 local_last
->next
= halp_move
;
970 local_last
= halp_move
;
972 /* Update the existing list */
973 if (halp_before
== NULL
)
974 start
= halp_move
->next
;
976 halp_before
->next
= halp_move
->next
;
981 *ha_head
= local_start
;
989 ******************************************************************************
990 * Function: mip6_hal_delete
991 * Description: Delete a Home Agent list entry. If there are any address list
992 * entries associated with the Home Agent entry they are deleted
994 * Ret value: Pointer to the next Home Agent list entry.
995 * NULL if the remaining list is empty or end of list reached.
996 ******************************************************************************
998 struct mip6_ha_list
*
999 mip6_hal_delete(ha_start
, ha_delete
)
1000 struct mip6_ha_list
**ha_start
; /* First list entry of HAs for a link */
1001 struct mip6_ha_list
*ha_delete
; /* Home Agent entry to delete */
1003 struct mip6_ha_list
*halp
; /* Current HA list entry */
1004 struct mip6_ha_list
*halp_prev
; /* Previous HA list entry */
1005 struct mip6_addr_list
*addrp
; /* Address list entry */
1006 struct mip6_addr_list
*addr_delete
; /* Address list entry to delete */
1011 for (halp
= *ha_start
; halp
; halp
= halp
->next
) {
1012 if (halp
!= ha_delete
) {
1017 /* Search the address list and remove each entry */
1018 for (addrp
= halp
->addr_list
; addrp
;) {
1019 addr_delete
= addrp
;
1020 addrp
= addrp
->next
;
1021 _FREE(addr_delete
, M_TEMP
);
1024 /* Make sure that the pointer to the first entry is correct */
1025 if (halp
== *ha_start
) {
1026 *ha_start
= halp
->next
;
1027 _FREE(halp
, M_TEMP
);
1031 halp_prev
->next
= halp
->next
;
1032 _FREE(halp
, M_TEMP
);
1034 return halp_prev
->next
;
1044 ##############################################################################
1047 # These functions are called at regular basis. They operate on the lists,
1048 # e.g. reducing timer counters and removing entries from the list if needed.
1050 ##############################################################################
1054 ******************************************************************************
1055 * Function: mip6_timer_ll
1056 * Description: Search the Home Agent list for each link and delete entries for
1057 * which the timer has expired.
1058 * If there are more entries left in the Home Agent list, call
1059 * this fuction again once every second until the list is empty.
1061 ******************************************************************************
1064 mip6_timer_ll_funneled(arg
)
1065 void *arg
; /* Not used */
1068 boolean_t funnel_state
;
1069 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
1073 (void) thread_funnel_set(network_flock
, FALSE
);
1078 void *arg
; /* Not used */
1080 struct mip6_link_list
*llp
; /* Current Link list entry */
1081 struct mip6_ha_list
*halp
; /* Current Home Agent list entry */
1084 /* Go through the entire Home Agent List and delete all entries
1085 for which the time has expired. */
1087 for (llp
= mip6_llq
; llp
;) {
1088 for (halp
= llp
->ha_list
; halp
;) {
1089 halp
->lifetime
-= 1;
1090 if (halp
->lifetime
== 0)
1091 halp
= mip6_hal_delete(&llp
->ha_list
, halp
);
1096 if (llp
->ha_list
== NULL
)
1097 llp
= mip6_ll_delete(llp
);
1103 if (mip6_llq
!= NULL
) {
1104 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
1105 mip6_timer_ll_handle
=
1107 timeout(mip6_timer_ll_funneled
, (void *)0, hz
);
1114 ##############################################################################
1117 # These functions are called from mip6_ioctl.
1119 ##############################################################################
1123 ******************************************************************************
1124 * Function: mip6_write_config_data_ha
1125 * Description: This function is called to write certain config values for
1126 * MIPv6. The data is written into the global config structure.
1128 ******************************************************************************
1130 int mip6_write_config_data_ha(u_long cmd
, void *arg
)
1135 case SIOCSHAPREF_MIP6
:
1136 mip6_config
.ha_pref
= ((struct mip6_input_data
*)arg
)->value
;
1145 ******************************************************************************
1146 * Function: mip6_clear_config_data_ha
1147 * Description: This function is called to clear internal lists handled by
1150 ******************************************************************************
1152 int mip6_clear_config_data_ha(u_long cmd
, void *data
)
1156 struct mip6_link_list
*llp
;
1160 case SIOCSHALISTFLUSH_MIP6
:
1161 for (llp
= mip6_llq
; llp
;)
1162 llp
= mip6_ll_delete(llp
);
1172 ******************************************************************************
1173 * Function: mip6_enable_func_ha
1174 * Description: This function is called to enable or disable certain functions
1175 * in mip6. The data is written into the global config struct.
1177 ******************************************************************************
1179 int mip6_enable_func_ha(u_long cmd
, caddr_t data
)
1184 enable
= ((struct mip6_input_data
*)data
)->value
;
1187 case SIOCSFWDSLUNICAST_MIP6
:
1188 mip6_config
.fwd_sl_unicast
= enable
;
1191 case SIOCSFWDSLMULTICAST_MIP6
:
1192 mip6_config
.fwd_sl_multicast
= enable
;