2 * Prefix solicitation and advertisement
5 * Jaakko Laine <medved@iki.fi>
7 * $Id: s.prefix.c 1.30 03/04/10 13:09:54+03:00 anttit@jon.mipl.mediapoli.com $
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
15 #include <linux/kernel.h>
16 #include <linux/types.h>
17 #include <linux/config.h>
18 #include <linux/icmpv6.h>
19 #include <linux/net.h>
20 #include <linux/spinlock.h>
21 #include <linux/timer.h>
22 #include <linux/netdevice.h>
24 #include <net/addrconf.h>
25 #include <net/ip6_route.h>
26 #include <net/mipv6.h>
28 #include "mipv6_icmp.h"
30 #include "sortedlist.h"
34 #define INFINITY 0xffffffff
36 struct timer_list pfx_timer;
38 struct list_head pfx_list;
39 rwlock_t pfx_list_lock = RW_LOCK_UNLOCKED;
41 int compare_pfx_list_entry(const void *data1, const void *data2,
44 struct pfx_list_entry *e1 = (struct pfx_list_entry *) data1;
45 struct pfx_list_entry *e2 = (struct pfx_list_entry *) data2;
47 return ((ipv6_addr_cmp(&e1->daddr, &e2->daddr) == 0)
48 && (e2->ifindex == -1 || e1->ifindex == e2->ifindex));
52 * mipv6_pfx_cancel_send - cancel pending items to daddr from saddr
53 * @daddr: Destination address
54 * @ifindex: pending items on this interface will be canceled
56 * if ifindex == -1, all items to daddr will be removed
58 void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex)
61 struct pfx_list_entry entry;
65 /* We'll just be comparing these parts... */
66 memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
67 entry.ifindex = ifindex;
69 write_lock_bh(&pfx_list_lock);
71 while (mipv6_slist_del_item(&pfx_list, &entry,
72 compare_pfx_list_entry) == 0)
75 if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
76 mod_timer(&pfx_timer, tmp);
78 write_unlock_bh(&pfx_list_lock);
82 * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
83 * @daddr: address of HA
84 * @saddr: our address to use as source address
85 * @ifindex: interface index
87 void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
91 struct pfx_list_entry entry;
95 memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
96 memcpy(&entry.saddr, saddr, sizeof(struct in6_addr));
98 entry.ifindex = ifindex;
100 write_lock_bh(&pfx_list_lock);
101 if (mipv6_slist_modify(&pfx_list, &entry, sizeof(struct pfx_list_entry),
102 jiffies + INITIAL_SOLICIT_TIMER * HZ,
103 compare_pfx_list_entry))
104 DEBUG(DBG_WARNING, "Cannot add new HA to pfx list");
106 if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
107 mod_timer(&pfx_timer, tmp);
108 write_unlock_bh(&pfx_list_lock);
111 int mipv6_pfx_add_home(int ifindex, struct in6_addr *saddr,
112 struct in6_addr *daddr, unsigned long min_expire)
116 write_lock(&pfx_list_lock);
118 if (min_expire != INFINITY) {
119 unsigned long expire;
120 struct pfx_list_entry entry;
122 memcpy(&entry.daddr, saddr, sizeof(struct in6_addr));
123 memcpy(&entry.saddr, daddr, sizeof(struct in6_addr));
125 entry.ifindex = ifindex;
127 /* This is against the draft, but we need to set
128 * a minimum interval for a prefix solicitation.
129 * Otherwise a prefix solicitation storm will
130 * result if valid lifetime of the prefix is
131 * smaller than MAX_PFX_ADV_DELAY
133 min_expire -= MAX_PFX_ADV_DELAY;
134 min_expire = min_expire < MIN_PFX_SOL_DELAY ? MIN_PFX_SOL_DELAY : min_expire;
136 expire = jiffies + min_expire * HZ;
138 if (mipv6_slist_modify(&pfx_list, &entry,
139 sizeof(struct pfx_list_entry),
141 compare_pfx_list_entry) != 0)
142 DEBUG(DBG_WARNING, "Cannot add new entry to pfx_list");
145 if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
146 mod_timer(&pfx_timer, tmp);
148 write_unlock(&pfx_list_lock);
154 * set_ha_pfx_list - manipulate pfx_list for HA when timer goes off
155 * @entry: pfx_list_entry that is due
157 static void set_ha_pfx_list(struct pfx_list_entry *entry)
162 * set_mn_pfx_list - manipulate pfx_list for MN when timer goes off
163 * @entry: pfx_list_entry that is due
165 static void set_mn_pfx_list(struct pfx_list_entry *entry)
170 * pfx_timer_handler - general timer handler
173 * calls set_ha_pfx_list and set_mn_pfx_list to do the thing when
176 static void pfx_timer_handler(unsigned long dummy)
179 struct pfx_list_entry *entry;
183 write_lock(&pfx_list_lock);
184 if (!(entry = mipv6_slist_get_first(&pfx_list)))
187 if (mip6node_cnf.capabilities & CAP_HA)
188 set_ha_pfx_list(entry);
189 if (mip6node_cnf.capabilities & CAP_MN)
190 set_mn_pfx_list(entry);
191 if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
192 mod_timer(&pfx_timer, tmp);
195 write_unlock(&pfx_list_lock);
198 int mipv6_initialize_pfx_icmpv6(void)
200 INIT_LIST_HEAD(&pfx_list);
202 init_timer(&pfx_timer);
203 pfx_timer.function = pfx_timer_handler;
208 void mipv6_shutdown_pfx_icmpv6(void)
210 struct prefix_info *tmp;
212 if (timer_pending(&pfx_timer))
213 del_timer(&pfx_timer);
215 write_lock_bh(&pfx_list_lock);
216 while ((tmp = mipv6_slist_del_first(&pfx_list)))
218 write_unlock_bh(&pfx_list_lock);
221 EXPORT_SYMBOL(mipv6_initialize_pfx_icmpv6);
222 EXPORT_SYMBOL(mipv6_pfx_add_home);
223 EXPORT_SYMBOL(mipv6_shutdown_pfx_icmpv6);
224 EXPORT_SYMBOL(compare_pfx_list_entry);
225 EXPORT_SYMBOL(pfx_list);
226 EXPORT_SYMBOL(pfx_timer);
227 EXPORT_SYMBOL(mipv6_pfx_cancel_send);
228 EXPORT_SYMBOL(pfx_list_lock);