Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * IPv6 Address [auto]configuration | |
3 | * Linux INET6 implementation | |
4 | * | |
5 | * Authors: | |
6 | * Pedro Roque <roque@di.fc.ul.pt> | |
7 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | |
8 | * | |
9 | * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $ | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License | |
13 | * as published by the Free Software Foundation; either version | |
14 | * 2 of the License, or (at your option) any later version. | |
15 | */ | |
16 | ||
17 | /* | |
18 | * Changes: | |
19 | * | |
20 | * Janos Farkas : delete timer on ifdown | |
21 | * <chexum@bankinf.banki.hu> | |
22 | * Andi Kleen : kill double kfree on module | |
23 | * unload. | |
24 | * Maciej W. Rozycki : FDDI support | |
25 | * sekiya@USAGI : Don't send too many RS | |
26 | * packets. | |
27 | * yoshfuji@USAGI : Fixed interval between DAD | |
28 | * packets. | |
29 | * YOSHIFUJI Hideaki @USAGI : improved accuracy of | |
30 | * address validation timer. | |
31 | * YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041) | |
32 | * support. | |
33 | * Yuji SEKIYA @USAGI : Don't assign a same IPv6 | |
34 | * address on a same interface. | |
35 | * YOSHIFUJI Hideaki @USAGI : ARCnet support | |
36 | * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to | |
37 | * seq_file. | |
38 | */ | |
39 | ||
40 | #include <linux/config.h> | |
41 | #include <linux/errno.h> | |
42 | #include <linux/types.h> | |
43 | #include <linux/socket.h> | |
44 | #include <linux/sockios.h> | |
45 | #include <linux/sched.h> | |
46 | #include <linux/net.h> | |
47 | #include <linux/in6.h> | |
48 | #include <linux/netdevice.h> | |
49 | #include <linux/if_arp.h> | |
50 | #include <linux/if_arcnet.h> | |
51 | #include <linux/if_infiniband.h> | |
52 | #include <linux/route.h> | |
53 | #include <linux/inetdevice.h> | |
54 | #include <linux/init.h> | |
55 | #ifdef CONFIG_SYSCTL | |
56 | #include <linux/sysctl.h> | |
57 | #endif | |
58 | #include <linux/delay.h> | |
59 | #include <linux/notifier.h> | |
543537bd | 60 | #include <linux/string.h> |
1da177e4 LT |
61 | |
62 | #include <net/sock.h> | |
63 | #include <net/snmp.h> | |
64 | ||
65 | #include <net/ipv6.h> | |
66 | #include <net/protocol.h> | |
67 | #include <net/ndisc.h> | |
68 | #include <net/ip6_route.h> | |
69 | #include <net/addrconf.h> | |
70 | #include <net/tcp.h> | |
71 | #include <net/ip.h> | |
72 | #include <linux/if_tunnel.h> | |
73 | #include <linux/rtnetlink.h> | |
74 | ||
75 | #ifdef CONFIG_IPV6_PRIVACY | |
76 | #include <linux/random.h> | |
77 | #include <linux/crypto.h> | |
78 | #include <asm/scatterlist.h> | |
79 | #endif | |
80 | ||
81 | #include <asm/uaccess.h> | |
82 | ||
83 | #include <linux/proc_fs.h> | |
84 | #include <linux/seq_file.h> | |
85 | ||
86 | /* Set to 3 to get tracing... */ | |
87 | #define ACONF_DEBUG 2 | |
88 | ||
89 | #if ACONF_DEBUG >= 3 | |
90 | #define ADBG(x) printk x | |
91 | #else | |
92 | #define ADBG(x) | |
93 | #endif | |
94 | ||
95 | #define INFINITY_LIFE_TIME 0xFFFFFFFF | |
96 | #define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b))) | |
97 | ||
98 | #ifdef CONFIG_SYSCTL | |
99 | static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p); | |
100 | static void addrconf_sysctl_unregister(struct ipv6_devconf *p); | |
101 | #endif | |
102 | ||
103 | #ifdef CONFIG_IPV6_PRIVACY | |
104 | static int __ipv6_regen_rndid(struct inet6_dev *idev); | |
105 | static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); | |
106 | static void ipv6_regen_rndid(unsigned long data); | |
107 | ||
108 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | |
109 | static struct crypto_tfm *md5_tfm; | |
110 | static DEFINE_SPINLOCK(md5_tfm_lock); | |
111 | #endif | |
112 | ||
113 | static int ipv6_count_addresses(struct inet6_dev *idev); | |
114 | ||
115 | /* | |
116 | * Configured unicast address hash table | |
117 | */ | |
118 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | |
119 | static DEFINE_RWLOCK(addrconf_hash_lock); | |
120 | ||
121 | /* Protects inet6 devices */ | |
122 | DEFINE_RWLOCK(addrconf_lock); | |
123 | ||
124 | static void addrconf_verify(unsigned long); | |
125 | ||
126 | static struct timer_list addr_chk_timer = | |
127 | TIMER_INITIALIZER(addrconf_verify, 0, 0); | |
128 | static DEFINE_SPINLOCK(addrconf_verify_lock); | |
129 | ||
130 | static void addrconf_join_anycast(struct inet6_ifaddr *ifp); | |
131 | static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); | |
132 | ||
133 | static int addrconf_ifdown(struct net_device *dev, int how); | |
134 | ||
e431b8c0 | 135 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); |
1da177e4 LT |
136 | static void addrconf_dad_timer(unsigned long data); |
137 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | |
138 | static void addrconf_rs_timer(unsigned long data); | |
139 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | |
140 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | |
141 | ||
142 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |
143 | struct prefix_info *pinfo); | |
144 | static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); | |
145 | ||
146 | static struct notifier_block *inet6addr_chain; | |
147 | ||
148 | struct ipv6_devconf ipv6_devconf = { | |
149 | .forwarding = 0, | |
150 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | |
151 | .mtu6 = IPV6_MIN_MTU, | |
152 | .accept_ra = 1, | |
153 | .accept_redirects = 1, | |
154 | .autoconf = 1, | |
155 | .force_mld_version = 0, | |
156 | .dad_transmits = 1, | |
157 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | |
158 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | |
159 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | |
160 | #ifdef CONFIG_IPV6_PRIVACY | |
161 | .use_tempaddr = 0, | |
162 | .temp_valid_lft = TEMP_VALID_LIFETIME, | |
163 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | |
164 | .regen_max_retry = REGEN_MAX_RETRY, | |
165 | .max_desync_factor = MAX_DESYNC_FACTOR, | |
166 | #endif | |
167 | .max_addresses = IPV6_MAX_ADDRESSES, | |
168 | }; | |
169 | ||
170 | static struct ipv6_devconf ipv6_devconf_dflt = { | |
171 | .forwarding = 0, | |
172 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | |
173 | .mtu6 = IPV6_MIN_MTU, | |
174 | .accept_ra = 1, | |
175 | .accept_redirects = 1, | |
176 | .autoconf = 1, | |
177 | .dad_transmits = 1, | |
178 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | |
179 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | |
180 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | |
181 | #ifdef CONFIG_IPV6_PRIVACY | |
182 | .use_tempaddr = 0, | |
183 | .temp_valid_lft = TEMP_VALID_LIFETIME, | |
184 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | |
185 | .regen_max_retry = REGEN_MAX_RETRY, | |
186 | .max_desync_factor = MAX_DESYNC_FACTOR, | |
187 | #endif | |
188 | .max_addresses = IPV6_MAX_ADDRESSES, | |
189 | }; | |
190 | ||
191 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | |
192 | #if 0 | |
193 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |
194 | #endif | |
195 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | |
196 | ||
197 | int ipv6_addr_type(const struct in6_addr *addr) | |
198 | { | |
199 | int type; | |
200 | u32 st; | |
201 | ||
202 | st = addr->s6_addr32[0]; | |
203 | ||
204 | if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { | |
205 | type = IPV6_ADDR_MULTICAST; | |
206 | ||
207 | switch((st & htonl(0x00FF0000))) { | |
208 | case __constant_htonl(0x00010000): | |
209 | type |= IPV6_ADDR_LOOPBACK; | |
210 | break; | |
211 | ||
212 | case __constant_htonl(0x00020000): | |
213 | type |= IPV6_ADDR_LINKLOCAL; | |
214 | break; | |
215 | ||
216 | case __constant_htonl(0x00050000): | |
217 | type |= IPV6_ADDR_SITELOCAL; | |
218 | break; | |
219 | }; | |
220 | return type; | |
221 | } | |
222 | ||
223 | type = IPV6_ADDR_UNICAST; | |
224 | ||
225 | /* Consider all addresses with the first three bits different of | |
226 | 000 and 111 as finished. | |
227 | */ | |
228 | if ((st & htonl(0xE0000000)) != htonl(0x00000000) && | |
229 | (st & htonl(0xE0000000)) != htonl(0xE0000000)) | |
230 | return type; | |
231 | ||
232 | if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) | |
233 | return (IPV6_ADDR_LINKLOCAL | type); | |
234 | ||
235 | if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) | |
236 | return (IPV6_ADDR_SITELOCAL | type); | |
237 | ||
238 | if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { | |
239 | if (addr->s6_addr32[2] == 0) { | |
240 | if (addr->s6_addr32[3] == 0) | |
241 | return IPV6_ADDR_ANY; | |
242 | ||
243 | if (addr->s6_addr32[3] == htonl(0x00000001)) | |
244 | return (IPV6_ADDR_LOOPBACK | type); | |
245 | ||
246 | return (IPV6_ADDR_COMPATv4 | type); | |
247 | } | |
248 | ||
249 | if (addr->s6_addr32[2] == htonl(0x0000ffff)) | |
250 | return IPV6_ADDR_MAPPED; | |
251 | } | |
252 | ||
253 | st &= htonl(0xFF000000); | |
254 | if (st == 0) | |
255 | return IPV6_ADDR_RESERVED; | |
256 | st &= htonl(0xFE000000); | |
257 | if (st == htonl(0x02000000)) | |
258 | return IPV6_ADDR_RESERVED; /* for NSAP */ | |
259 | if (st == htonl(0x04000000)) | |
260 | return IPV6_ADDR_RESERVED; /* for IPX */ | |
261 | return type; | |
262 | } | |
263 | ||
264 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | |
265 | { | |
266 | if (del_timer(&ifp->timer)) | |
267 | __in6_ifa_put(ifp); | |
268 | } | |
269 | ||
270 | enum addrconf_timer_t | |
271 | { | |
272 | AC_NONE, | |
273 | AC_DAD, | |
274 | AC_RS, | |
275 | }; | |
276 | ||
277 | static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |
278 | enum addrconf_timer_t what, | |
279 | unsigned long when) | |
280 | { | |
281 | if (!del_timer(&ifp->timer)) | |
282 | in6_ifa_hold(ifp); | |
283 | ||
284 | switch (what) { | |
285 | case AC_DAD: | |
286 | ifp->timer.function = addrconf_dad_timer; | |
287 | break; | |
288 | case AC_RS: | |
289 | ifp->timer.function = addrconf_rs_timer; | |
290 | break; | |
291 | default:; | |
292 | } | |
293 | ifp->timer.expires = jiffies + when; | |
294 | add_timer(&ifp->timer); | |
295 | } | |
296 | ||
297 | /* Nobody refers to this device, we may destroy it. */ | |
298 | ||
299 | void in6_dev_finish_destroy(struct inet6_dev *idev) | |
300 | { | |
301 | struct net_device *dev = idev->dev; | |
302 | BUG_TRAP(idev->addr_list==NULL); | |
303 | BUG_TRAP(idev->mc_list==NULL); | |
304 | #ifdef NET_REFCNT_DEBUG | |
305 | printk(KERN_DEBUG "in6_dev_finish_destroy: %s\n", dev ? dev->name : "NIL"); | |
306 | #endif | |
307 | dev_put(dev); | |
308 | if (!idev->dead) { | |
309 | printk("Freeing alive inet6 device %p\n", idev); | |
310 | return; | |
311 | } | |
312 | snmp6_free_dev(idev); | |
313 | kfree(idev); | |
314 | } | |
315 | ||
316 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |
317 | { | |
318 | struct inet6_dev *ndev; | |
319 | ||
320 | ASSERT_RTNL(); | |
321 | ||
322 | if (dev->mtu < IPV6_MIN_MTU) | |
323 | return NULL; | |
324 | ||
325 | ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL); | |
326 | ||
327 | if (ndev) { | |
328 | memset(ndev, 0, sizeof(struct inet6_dev)); | |
329 | ||
330 | rwlock_init(&ndev->lock); | |
331 | ndev->dev = dev; | |
332 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); | |
333 | ndev->cnf.mtu6 = dev->mtu; | |
334 | ndev->cnf.sysctl = NULL; | |
335 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); | |
336 | if (ndev->nd_parms == NULL) { | |
337 | kfree(ndev); | |
338 | return NULL; | |
339 | } | |
340 | /* We refer to the device */ | |
341 | dev_hold(dev); | |
342 | ||
343 | if (snmp6_alloc_dev(ndev) < 0) { | |
344 | ADBG((KERN_WARNING | |
345 | "%s(): cannot allocate memory for statistics; dev=%s.\n", | |
346 | __FUNCTION__, dev->name)); | |
347 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | |
348 | ndev->dead = 1; | |
349 | in6_dev_finish_destroy(ndev); | |
350 | return NULL; | |
351 | } | |
352 | ||
353 | if (snmp6_register_dev(ndev) < 0) { | |
354 | ADBG((KERN_WARNING | |
355 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", | |
356 | __FUNCTION__, dev->name)); | |
357 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | |
358 | ndev->dead = 1; | |
359 | in6_dev_finish_destroy(ndev); | |
360 | return NULL; | |
361 | } | |
362 | ||
363 | /* One reference from device. We must do this before | |
364 | * we invoke __ipv6_regen_rndid(). | |
365 | */ | |
366 | in6_dev_hold(ndev); | |
367 | ||
368 | #ifdef CONFIG_IPV6_PRIVACY | |
369 | get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); | |
370 | get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); | |
371 | init_timer(&ndev->regen_timer); | |
372 | ndev->regen_timer.function = ipv6_regen_rndid; | |
373 | ndev->regen_timer.data = (unsigned long) ndev; | |
374 | if ((dev->flags&IFF_LOOPBACK) || | |
375 | dev->type == ARPHRD_TUNNEL || | |