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 | ||
8d06afab | 126 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); |
1da177e4 LT |
127 | static DEFINE_SPINLOCK(addrconf_verify_lock); |
128 | ||
129 | static void addrconf_join_anycast(struct inet6_ifaddr *ifp); | |
130 | static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); | |
131 | ||
132 | static int addrconf_ifdown(struct net_device *dev, int how); | |
133 | ||
e431b8c0 | 134 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); |
1da177e4 LT |
135 | static void addrconf_dad_timer(unsigned long data); |
136 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | |
137 | static void addrconf_rs_timer(unsigned long data); | |
138 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | |
139 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | |
140 | ||
141 | static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |
142 | struct prefix_info *pinfo); | |
143 | static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); | |
144 | ||
145 | static struct notifier_block *inet6addr_chain; | |
146 | ||
147 | struct ipv6_devconf ipv6_devconf = { | |
148 | .forwarding = 0, | |
149 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | |
150 | .mtu6 = IPV6_MIN_MTU, | |
151 | .accept_ra = 1, | |
152 | .accept_redirects = 1, | |
153 | .autoconf = 1, | |
154 | .force_mld_version = 0, | |
155 | .dad_transmits = 1, | |
156 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | |
157 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | |
158 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | |
159 | #ifdef CONFIG_IPV6_PRIVACY | |
160 | .use_tempaddr = 0, | |
161 | .temp_valid_lft = TEMP_VALID_LIFETIME, | |
162 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | |
163 | .regen_max_retry = REGEN_MAX_RETRY, | |
164 | .max_desync_factor = MAX_DESYNC_FACTOR, | |
165 | #endif | |
166 | .max_addresses = IPV6_MAX_ADDRESSES, | |
167 | }; | |
168 | ||
169 | static struct ipv6_devconf ipv6_devconf_dflt = { | |
170 | .forwarding = 0, | |
171 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | |
172 | .mtu6 = IPV6_MIN_MTU, | |
173 | .accept_ra = 1, | |
174 | .accept_redirects = 1, | |
175 | .autoconf = 1, | |
176 | .dad_transmits = 1, | |
177 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | |
178 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | |
179 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | |
180 | #ifdef CONFIG_IPV6_PRIVACY | |
181 | .use_tempaddr = 0, | |
182 | .temp_valid_lft = TEMP_VALID_LIFETIME, | |
183 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | |
184 | .regen_max_retry = REGEN_MAX_RETRY, | |
185 | .max_desync_factor = MAX_DESYNC_FACTOR, | |
186 | #endif | |
187 | .max_addresses = IPV6_MAX_ADDRESSES, | |
188 | }; | |
189 | ||
190 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | |
191 | #if 0 | |
192 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |
193 | #endif | |
194 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | |
195 | ||
196 | int ipv6_addr_type(const struct in6_addr *addr) | |
197 | { | |
198 | int type; | |
199 | u32 st; | |
200 | ||
201 | st = addr->s6_addr32[0]; | |
202 | ||
203 | if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { | |
204 | type = IPV6_ADDR_MULTICAST; | |
205 | ||
206 | switch((st & htonl(0x00FF0000))) { | |
207 | case __constant_htonl(0x00010000): | |
208 | type |= IPV6_ADDR_LOOPBACK; | |
209 | break; | |
210 | ||
211 | case __constant_htonl(0x00020000): | |
212 | type |= IPV6_ADDR_LINKLOCAL; | |
213 | break; | |
214 | ||
215 | case __constant_htonl(0x00050000): | |
216 | type |= IPV6_ADDR_SITELOCAL; | |
217 | break; | |
218 | }; | |
219 | return type; | |
220 | } | |
221 | ||
222 | type = IPV6_ADDR_UNICAST; | |
223 | ||
224 | /* Consider all addresses with the first three bits different of | |
225 | 000 and 111 as finished. | |
226 | */ | |
227 | if ((st & htonl(0xE0000000)) != htonl(0x00000000) && | |
228 | (st & htonl(0xE0000000)) != htonl(0xE0000000)) | |
229 | return type; | |
230 | ||
231 | if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) | |
232 | return (IPV6_ADDR_LINKLOCAL | type); | |
233 | ||
234 | if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) | |
235 | return (IPV6_ADDR_SITELOCAL | type); | |
236 | ||
237 | if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { | |
238 | if (addr->s6_addr32[2] == 0) { | |
239 | if (addr->s6_addr32[3] == 0) | |
240 | return IPV6_ADDR_ANY; | |
241 | ||
242 | if (addr->s6_addr32[3] == htonl(0x00000001)) | |
243 | return (IPV6_ADDR_LOOPBACK | type); | |
244 | ||
245 | return (IPV6_ADDR_COMPATv4 | type); | |
246 | } | |
247 | ||
248 | if (addr->s6_addr32[2] == htonl(0x0000ffff)) | |
249 | return IPV6_ADDR_MAPPED; | |
250 | } | |
251 | ||
252 | st &= htonl(0xFF000000); | |
253 | if (st == 0) | |
254 | return IPV6_ADDR_RESERVED; | |
255 | st &= htonl(0xFE000000); | |
256 | if (st == htonl(0x02000000)) | |
257 | return IPV6_ADDR_RESERVED; /* for NSAP */ | |
258 | if (st == htonl(0x04000000)) | |
259 | return IPV6_ADDR_RESERVED; /* for IPX */ | |
260 | return type; | |
261 | } | |
262 | ||
263 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | |
264 | { | |
265 | if (del_timer(&ifp->timer)) | |
266 | __in6_ifa_put(ifp); | |
267 | } | |
268 | ||
269 | enum addrconf_timer_t | |
270 | { | |
271 | AC_NONE, | |
272 | AC_DAD, | |
273 | AC_RS, | |
274 | }; | |
275 | ||
276 | static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |
277 | enum addrconf_timer_t what, | |
278 | unsigned long when) | |
279 | { | |
280 | if (!del_timer(&ifp->timer)) | |
281 | in6_ifa_hold(ifp); | |
282 | ||
283 | switch (what) { | |
284 | case AC_DAD: | |
285 | ifp->timer.function = addrconf_dad_timer; | |
286 | break; | |
287 | case AC_RS: | |
288 | ifp->timer.function = addrconf_rs_timer; | |
289 | break; | |
290 | default:; | |
291 | } | |
292 | ifp->timer.expires = jiffies + when; | |
293 | add_timer(&ifp->timer); | |
294 | } | |
295 | ||
296 | /* Nobody refers to this device, we may destroy it. */ | |
297 | ||
298 | void in6_dev_finish_destroy(struct inet6_dev *idev) | |
299 | { | |
300 | struct net_device *dev = idev->dev; | |
301 | BUG_TRAP(idev->addr_list==NULL); | |
302 | BUG_TRAP(idev->mc_list==NULL); | |
303 | #ifdef NET_REFCNT_DEBUG | |
304 | printk(KERN_DEBUG "in6_dev_finish_destroy: %s\n", dev ? dev->name : "NIL"); | |
305 | #endif | |
306 | dev_put(dev); | |
307 | if (!idev->dead) { | |
308 | printk("Freeing alive inet6 device %p\n", idev); | |
309 | return; | |
310 | } | |
311 | snmp6_free_dev(idev); | |
312 | kfree(idev); | |
313 | } | |
314 | ||
315 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |
316 | { | |
317 | struct inet6_dev *ndev; | |
318 | ||
319 | ASSERT_RTNL(); | |
320 | ||
321 | if (dev->mtu < IPV6_MIN_MTU) | |
322 | return NULL; | |
323 | ||
324 | ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL); | |
325 | ||
326 | if (ndev) { | |
327 | memset(ndev, 0, sizeof(struct inet6_dev)); | |
328 | ||
329 | rwlock_init(&ndev->lock); | |
330 | ndev->dev = dev; | |
331 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); | |
332 | ndev->cnf.mtu6 = dev->mtu; | |
333 | ndev->cnf.sysctl = NULL; | |
334 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); | |
335 | if (ndev->nd_parms == NULL) { | |
336 | kfree(ndev); | |
337 | return NULL; | |
338 | } | |
339 | /* We refer to the device */ | |
340 | dev_hold(dev); | |
341 | ||
342 | if (snmp6_alloc_dev(ndev) < 0) { | |
343 | ADBG((KERN_WARNING | |
344 | "%s(): cannot allocate memory for statistics; dev=%s.\n", | |
345 | __FUNCTION__, dev->name)); | |
346 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | |
347 | ndev->dead = 1; | |
348 | in6_dev_finish_destroy(ndev); | |
349 | return NULL; | |
350 | } | |
351 | ||
352 | if (snmp6_register_dev(ndev) < 0) { | |
353 | ADBG((KERN_WARNING | |
354 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", | |
355 | __FUNCTION__, dev->name)); | |
356 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | |
357 | ndev->dead = 1; | |
358 | in6_dev_finish_destroy(ndev); | |
359 | return NULL; | |
360 | } | |
361 | ||
362 | /* One reference from device. We must do this before | |
363 | * we invoke __ipv6_regen_rndid(). | |
364 | */ | |
365 | in6_dev_hold(ndev); | |
366 | ||
367 | #ifdef CONFIG_IPV6_PRIVACY | |
368 | get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); | |
369 | get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); | |
370 | init_timer(&ndev->regen_timer); | |
371 | ndev->regen_timer.function = ipv6_regen_rndid; | |
372 | ndev->regen_timer.data = (unsigned long) ndev; | |
373 | if ((dev->flags&IFF_LOOPBACK) || | |
374 | dev->type == ARPHRD_TUNNEL || | |