Blame view
net/ipv6/ndisc.c
45.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
/* * Neighbour Discovery for IPv6 |
1ab1457c4 [NET] IPV6: Fix w... |
3 |
* Linux INET6 implementation |
1da177e4c Linux-2.6.12-rc2 |
4 5 |
* * Authors: |
1ab1457c4 [NET] IPV6: Fix w... |
6 |
* Pedro Roque <roque@di.fc.ul.pt> |
1da177e4c Linux-2.6.12-rc2 |
7 8 9 10 11 12 13 14 15 16 17 |
* Mike Shaver <shaver@ingenia.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* * Changes: * |
31910575a [IPv6]: Export us... |
18 19 |
* Pierre Ynard : export userland ND options * through netlink (RDNSS support) |
1da177e4c Linux-2.6.12-rc2 |
20 21 |
* Lars Fenneberg : fixed MTU setting on receipt * of an RA. |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
* Janos Farkas : kmalloc failure checks * Alexey Kuznetsov : state machine reworked * and moved to net/core. * Pekka Savola : RFC2461 validation * YOSHIFUJI Hideaki @USAGI : Verify ND options properly */ /* Set to 3 to get tracing... */ #define ND_DEBUG 1 #define ND_PRINTK(fmt, args...) do { if (net_ratelimit()) { printk(fmt, ## args); } } while(0) #define ND_NOPRINTK(x...) do { ; } while(0) #define ND_PRINTK0 ND_PRINTK #define ND_PRINTK1 ND_NOPRINTK #define ND_PRINTK2 ND_NOPRINTK #define ND_PRINTK3 ND_NOPRINTK #if ND_DEBUG >= 1 #undef ND_PRINTK1 #define ND_PRINTK1 ND_PRINTK #endif #if ND_DEBUG >= 2 #undef ND_PRINTK2 #define ND_PRINTK2 ND_PRINTK #endif #if ND_DEBUG >= 3 #undef ND_PRINTK3 #define ND_PRINTK3 ND_PRINTK #endif #include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
52 53 54 55 56 57 58 59 60 61 |
#include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> #include <linux/sched.h> #include <linux/net.h> #include <linux/in6.h> #include <linux/route.h> #include <linux/init.h> #include <linux/rcupdate.h> |
5a0e3ad6a include cleanup: ... |
62 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 |
#ifdef CONFIG_SYSCTL #include <linux/sysctl.h> #endif |
1823730fb [IPv4]: Move inte... |
66 |
#include <linux/if_addr.h> |
1da177e4c Linux-2.6.12-rc2 |
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <linux/if_arp.h> #include <linux/ipv6.h> #include <linux/icmpv6.h> #include <linux/jhash.h> #include <net/sock.h> #include <net/snmp.h> #include <net/ipv6.h> #include <net/protocol.h> #include <net/ndisc.h> #include <net/ip6_route.h> #include <net/addrconf.h> #include <net/icmp.h> |
31910575a [IPv6]: Export us... |
81 82 |
#include <net/netlink.h> #include <linux/rtnetlink.h> |
1da177e4c Linux-2.6.12-rc2 |
83 84 |
#include <net/flow.h> #include <net/ip6_checksum.h> |
1ed8516f0 [IPV6]: Simplify ... |
85 |
#include <net/inet_common.h> |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 89 |
#include <linux/proc_fs.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv6.h> |
d6bf78171 net neigh: RCU co... |
90 91 |
static u32 ndisc_hash(const void *pkey, const struct net_device *dev, |
2c2aba6c5 ipv6: Use univers... |
92 |
__u32 *hash_rnd); |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 96 97 98 |
static int ndisc_constructor(struct neighbour *neigh); static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); static int pndisc_constructor(struct pneigh_entry *n); static void pndisc_destructor(struct pneigh_entry *n); static void pndisc_redo(struct sk_buff *skb); |
89d69d2b7 net: make neigh_o... |
99 |
static const struct neigh_ops ndisc_generic_ops = { |
1da177e4c Linux-2.6.12-rc2 |
100 101 102 103 104 |
.family = AF_INET6, .solicit = ndisc_solicit, .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_connected_output, |
1da177e4c Linux-2.6.12-rc2 |
105 |
}; |
89d69d2b7 net: make neigh_o... |
106 |
static const struct neigh_ops ndisc_hh_ops = { |
1da177e4c Linux-2.6.12-rc2 |
107 108 109 110 111 |
.family = AF_INET6, .solicit = ndisc_solicit, .error_report = ndisc_error_report, .output = neigh_resolve_output, .connected_output = neigh_resolve_output, |
1da177e4c Linux-2.6.12-rc2 |
112 |
}; |
89d69d2b7 net: make neigh_o... |
113 |
static const struct neigh_ops ndisc_direct_ops = { |
1da177e4c Linux-2.6.12-rc2 |
114 |
.family = AF_INET6, |
8f40b161d neigh: Pass neigh... |
115 116 |
.output = neigh_direct_output, .connected_output = neigh_direct_output, |
1da177e4c Linux-2.6.12-rc2 |
117 118 119 120 |
}; struct neigh_table nd_tbl = { .family = AF_INET6, |
1da177e4c Linux-2.6.12-rc2 |
121 122 123 124 125 126 127 128 |
.key_len = sizeof(struct in6_addr), .hash = ndisc_hash, .constructor = ndisc_constructor, .pconstructor = pndisc_constructor, .pdestructor = pndisc_destructor, .proxy_redo = pndisc_redo, .id = "ndisc_cache", .parms = { |
b672083ed ipv6: use ND_REAC... |
129 130 131 132 133 134 |
.tbl = &nd_tbl, .base_reachable_time = ND_REACHABLE_TIME, .retrans_time = ND_RETRANS_TIMER, .gc_staletime = 60 * HZ, .reachable_time = ND_REACHABLE_TIME, .delay_probe_time = 5 * HZ, |
8b5c171bb neigh: new unreso... |
135 |
.queue_len_bytes = 64*1024, |
b672083ed ipv6: use ND_REAC... |
136 137 138 139 140 |
.ucast_probes = 3, .mcast_probes = 3, .anycast_delay = 1 * HZ, .proxy_delay = (8 * HZ) / 10, .proxy_qlen = 64, |
1da177e4c Linux-2.6.12-rc2 |
141 142 143 144 145 146 147 148 149 |
}, .gc_interval = 30 * HZ, .gc_thresh1 = 128, .gc_thresh2 = 512, .gc_thresh3 = 1024, }; /* ND options */ struct ndisc_options { |
70ceb4f53 [IPV6]: ROUTE: Ad... |
150 151 152 153 154 |
struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX]; #ifdef CONFIG_IPV6_ROUTE_INFO struct nd_opt_hdr *nd_opts_ri; struct nd_opt_hdr *nd_opts_ri_end; #endif |
31910575a [IPv6]: Export us... |
155 156 |
struct nd_opt_hdr *nd_useropts; struct nd_opt_hdr *nd_useropts_end; |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
}; #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] #define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR] #define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO] #define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END] #define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR] #define nd_opts_mtu nd_opt_array[ND_OPT_MTU] #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7) /* * Return the padding between the option length and the start of the * link addr. Currently only IP-over-InfiniBand needs this, although * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may * also need a pad of 2. */ static int ndisc_addr_option_pad(unsigned short type) { switch (type) { case ARPHRD_INFINIBAND: return 2; default: return 0; } } static inline int ndisc_opt_addr_space(struct net_device *dev) { return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); } static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, unsigned short addr_type) { int space = NDISC_OPT_SPACE(data_len); int pad = ndisc_addr_option_pad(addr_type); opt[0] = type; opt[1] = space>>3; memset(opt + 2, 0, pad); opt += pad; space -= pad; memcpy(opt+2, data, data_len); data_len += 2; opt += data_len; if ((space -= data_len) > 0) memset(opt, 0, space); return opt + space; } static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end) { int type; if (!cur || !end || cur >= end) return NULL; type = cur->nd_opt_type; do { cur = ((void *)cur) + (cur->nd_opt_len << 3); } while(cur < end && cur->nd_opt_type != type); |
a02cec215 net: return opera... |
218 |
return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
1da177e4c Linux-2.6.12-rc2 |
219 |
} |
31910575a [IPv6]: Export us... |
220 221 |
static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) { |
a02cec215 net: return opera... |
222 |
return opt->nd_opt_type == ND_OPT_RDNSS; |
31910575a [IPv6]: Export us... |
223 224 225 226 227 228 229 230 231 232 |
} static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, struct nd_opt_hdr *end) { if (!cur || !end || cur >= end) return NULL; do { cur = ((void *)cur) + (cur->nd_opt_len << 3); } while(cur < end && !ndisc_is_useropt(cur)); |
a02cec215 net: return opera... |
233 |
return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; |
31910575a [IPv6]: Export us... |
234 |
} |
1da177e4c Linux-2.6.12-rc2 |
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts) { struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt; if (!nd_opt || opt_len < 0 || !ndopts) return NULL; memset(ndopts, 0, sizeof(*ndopts)); while (opt_len) { int l; if (opt_len < sizeof(struct nd_opt_hdr)) return NULL; l = nd_opt->nd_opt_len << 3; if (opt_len < l || l == 0) return NULL; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LL_ADDR: case ND_OPT_TARGET_LL_ADDR: case ND_OPT_MTU: case ND_OPT_REDIRECT_HDR: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { ND_PRINTK2(KERN_WARNING "%s(): duplicated ND6 option found: type=%d ", |
0dc47877a net: replace rema... |
259 |
__func__, |
1da177e4c Linux-2.6.12-rc2 |
260 261 262 263 264 265 266 |
nd_opt->nd_opt_type); } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFO: ndopts->nd_opts_pi_end = nd_opt; |
cfcabdcc2 [NET]: sparse war... |
267 |
if (!ndopts->nd_opt_array[nd_opt->nd_opt_type]) |
1da177e4c Linux-2.6.12-rc2 |
268 269 |
ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; break; |
70ceb4f53 [IPV6]: ROUTE: Ad... |
270 271 272 273 274 275 276 |
#ifdef CONFIG_IPV6_ROUTE_INFO case ND_OPT_ROUTE_INFO: ndopts->nd_opts_ri_end = nd_opt; if (!ndopts->nd_opts_ri) ndopts->nd_opts_ri = nd_opt; break; #endif |
1da177e4c Linux-2.6.12-rc2 |
277 |
default: |
31910575a [IPv6]: Export us... |
278 279 280 281 282 283 284 285 286 287 288 289 290 |
if (ndisc_is_useropt(nd_opt)) { ndopts->nd_useropts_end = nd_opt; if (!ndopts->nd_useropts) ndopts->nd_useropts = nd_opt; } else { /* * Unknown options must be silently ignored, * to accommodate future extension to the * protocol. */ ND_PRINTK2(KERN_NOTICE "%s(): ignored unsupported option; type=%d, len=%d ", |
0dc47877a net: replace rema... |
291 |
__func__, |
31910575a [IPv6]: Export us... |
292 293 |
nd_opt->nd_opt_type, nd_opt->nd_opt_len); } |
1da177e4c Linux-2.6.12-rc2 |
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
} opt_len -= l; nd_opt = ((void *)nd_opt) + l; } return ndopts; } static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, struct net_device *dev) { u8 *lladdr = (u8 *)(p + 1); int lladdrlen = p->nd_opt_len << 3; int prepad = ndisc_addr_option_pad(dev->type); if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) return NULL; |
a02cec215 net: return opera... |
309 |
return lladdr + prepad; |
1da177e4c Linux-2.6.12-rc2 |
310 |
} |
b71d1d426 inet: constify ip... |
311 |
int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
1da177e4c Linux-2.6.12-rc2 |
312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
{ switch (dev->type) { case ARPHRD_ETHER: case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */ case ARPHRD_FDDI: ipv6_eth_mc_map(addr, buf); return 0; case ARPHRD_IEEE802_TR: ipv6_tr_mc_map(addr,buf); return 0; case ARPHRD_ARCNET: ipv6_arcnet_mc_map(addr, buf); return 0; case ARPHRD_INFINIBAND: |
a9e527e3f IPoIB: improve IP... |
326 |
ipv6_ib_mc_map(addr, dev->broadcast, buf); |
1da177e4c Linux-2.6.12-rc2 |
327 |
return 0; |
93ca3bb5d net: gre: provide... |
328 329 |
case ARPHRD_IPGRE: return ipv6_ipgre_mc_map(addr, dev->broadcast, buf); |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 333 334 335 336 337 |
default: if (dir) { memcpy(buf, dev->broadcast, dev->addr_len); return 0; } } return -EINVAL; } |
7159039a1 [IPV6]: Decentral... |
338 |
EXPORT_SYMBOL(ndisc_mc_map); |
d6bf78171 net neigh: RCU co... |
339 340 |
static u32 ndisc_hash(const void *pkey, const struct net_device *dev, |
2c2aba6c5 ipv6: Use univers... |
341 |
__u32 *hash_rnd) |
1da177e4c Linux-2.6.12-rc2 |
342 |
{ |
2c2aba6c5 ipv6: Use univers... |
343 |
return ndisc_hashfn(pkey, dev, hash_rnd); |
1da177e4c Linux-2.6.12-rc2 |
344 345 346 347 348 349 350 351 352 |
} static int ndisc_constructor(struct neighbour *neigh) { struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key; struct net_device *dev = neigh->dev; struct inet6_dev *in6_dev; struct neigh_parms *parms; int is_multicast = ipv6_addr_is_multicast(addr); |
1da177e4c Linux-2.6.12-rc2 |
353 354 |
in6_dev = in6_dev_get(dev); if (in6_dev == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
355 356 357 358 359 360 |
return -EINVAL; } parms = in6_dev->nd_parms; __neigh_parms_put(neigh->parms); neigh->parms = neigh_parms_clone(parms); |
1da177e4c Linux-2.6.12-rc2 |
361 362 |
neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; |
3b04ddde0 [NET]: Move hardw... |
363 |
if (!dev->header_ops) { |
1da177e4c Linux-2.6.12-rc2 |
364 365 |
neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; |
8f40b161d neigh: Pass neigh... |
366 |
neigh->output = neigh_direct_output; |
1da177e4c Linux-2.6.12-rc2 |
367 368 369 370 371 372 373 374 375 376 377 378 379 |
} else { if (is_multicast) { neigh->nud_state = NUD_NOARP; ndisc_mc_map(addr, neigh->ha, dev, 1); } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) { neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->dev_addr, dev->addr_len); if (dev->flags&IFF_LOOPBACK) neigh->type = RTN_LOCAL; } else if (dev->flags&IFF_POINTOPOINT) { neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } |
3b04ddde0 [NET]: Move hardw... |
380 |
if (dev->header_ops->cache) |
1da177e4c Linux-2.6.12-rc2 |
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
neigh->ops = &ndisc_hh_ops; else neigh->ops = &ndisc_generic_ops; if (neigh->nud_state&NUD_VALID) neigh->output = neigh->ops->connected_output; else neigh->output = neigh->ops->output; } in6_dev_put(in6_dev); return 0; } static int pndisc_constructor(struct pneigh_entry *n) { struct in6_addr *addr = (struct in6_addr*)&n->key; struct in6_addr maddr; struct net_device *dev = n->dev; if (dev == NULL || __in6_dev_get(dev) == NULL) return -EINVAL; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_inc(dev, &maddr); return 0; } static void pndisc_destructor(struct pneigh_entry *n) { struct in6_addr *addr = (struct in6_addr*)&n->key; struct in6_addr maddr; struct net_device *dev = n->dev; if (dev == NULL || __in6_dev_get(dev) == NULL) return; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_dec(dev, &maddr); } |
305d552ac bonding: send IPv... |
417 418 419 420 421 422 |
struct sk_buff *ndisc_build_skb(struct net_device *dev, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h, const struct in6_addr *target, int llinfo) |
1da177e4c Linux-2.6.12-rc2 |
423 |
{ |
c346dca10 [NET] NETNS: Omit... |
424 |
struct net *net = dev_net(dev); |
1762f7e88 [NETNS][IPV6] ndi... |
425 |
struct sock *sk = net->ipv6.ndisc_sk; |
1ab1457c4 [NET] IPV6: Fix w... |
426 |
struct sk_buff *skb; |
e1ec7842d [IPV6] NDISC: Uni... |
427 |
struct icmp6hdr *hdr; |
a7ae19922 ipv6: Remove all ... |
428 429 |
int hlen = LL_RESERVED_SPACE(dev); int tlen = dev->needed_tailroom; |
e1ec7842d [IPV6] NDISC: Uni... |
430 |
int len; |
1da177e4c Linux-2.6.12-rc2 |
431 |
int err; |
305d552ac bonding: send IPv... |
432 |
u8 *opt; |
1da177e4c Linux-2.6.12-rc2 |
433 |
|
e1ec7842d [IPV6] NDISC: Uni... |
434 435 436 437 438 439 |
if (!dev->addr_len) llinfo = 0; len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); if (llinfo) len += ndisc_opt_addr_space(dev); |
1da177e4c Linux-2.6.12-rc2 |
440 |
|
d54a81d34 [IPV6] NDISC: Cal... |
441 442 |
skb = sock_alloc_send_skb(sk, (MAX_HEADER + sizeof(struct ipv6hdr) + |
a7ae19922 ipv6: Remove all ... |
443 |
len + hlen + tlen), |
1da177e4c Linux-2.6.12-rc2 |
444 |
1, &err); |
e1ec7842d [IPV6] NDISC: Uni... |
445 |
if (!skb) { |
1da177e4c Linux-2.6.12-rc2 |
446 |
ND_PRINTK0(KERN_ERR |
dae9de8e1 IPv6: Print error... |
447 448 449 |
"ICMPv6 ND: %s() failed to allocate an skb, err=%d. ", __func__, err); |
305d552ac bonding: send IPv... |
450 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
451 |
} |
a7ae19922 ipv6: Remove all ... |
452 |
skb_reserve(skb, hlen); |
e1ec7842d [IPV6] NDISC: Uni... |
453 |
ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); |
1da177e4c Linux-2.6.12-rc2 |
454 |
|
27a884dc3 [SK_BUFF]: Conver... |
455 |
skb->transport_header = skb->tail; |
d10ba34b0 [SK_BUFF]: More s... |
456 |
skb_put(skb, len); |
1da177e4c Linux-2.6.12-rc2 |
457 |
|
e1ec7842d [IPV6] NDISC: Uni... |
458 459 |
hdr = (struct icmp6hdr *)skb_transport_header(skb); memcpy(hdr, icmp6h, sizeof(*hdr)); |
1da177e4c Linux-2.6.12-rc2 |
460 |
|
e1ec7842d [IPV6] NDISC: Uni... |
461 462 |
opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); if (target) { |
4e3fd7a06 net: remove ipv6_... |
463 |
*(struct in6_addr *)opt = *target; |
e1ec7842d [IPV6] NDISC: Uni... |
464 465 |
opt += sizeof(*target); } |
1da177e4c Linux-2.6.12-rc2 |
466 |
|
e1ec7842d [IPV6] NDISC: Uni... |
467 468 |
if (llinfo) ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, |
1da177e4c Linux-2.6.12-rc2 |
469 |
dev->addr_len, dev->type); |
e1ec7842d [IPV6] NDISC: Uni... |
470 471 |
hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, |
07f0757a6 include/net net/ ... |
472 |
csum_partial(hdr, |
e1ec7842d [IPV6] NDISC: Uni... |
473 |
len, 0)); |
1da177e4c Linux-2.6.12-rc2 |
474 |
|
305d552ac bonding: send IPv... |
475 476 477 478 479 480 481 482 483 484 485 486 |
return skb; } EXPORT_SYMBOL(ndisc_build_skb); void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h) { |
4c9483b2f ipv6: Convert to ... |
487 |
struct flowi6 fl6; |
305d552ac bonding: send IPv... |
488 489 490 491 492 493 494 495 |
struct dst_entry *dst; struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; struct inet6_dev *idev; int err; u8 type; type = icmp6h->icmp6_type; |
4c9483b2f ipv6: Convert to ... |
496 |
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); |
87a115783 ipv6: Move xfrm_l... |
497 |
dst = icmp6_dst_alloc(dev, neigh, &fl6); |
452edd598 xfrm: Return dst ... |
498 |
if (IS_ERR(dst)) { |
305d552ac bonding: send IPv... |
499 500 501 |
kfree_skb(skb); return; } |
adf30907d net: skb->dst acc... |
502 |
skb_dst_set(skb, dst); |
e1ec7842d [IPV6] NDISC: Uni... |
503 |
|
cfdf76474 ipv6: some RCU co... |
504 505 |
rcu_read_lock(); idev = __in6_dev_get(dst->dev); |
edf391ff1 snmp: add missing... |
506 |
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
e1ec7842d [IPV6] NDISC: Uni... |
507 |
|
b2e0b385d netfilter: ipv6: ... |
508 |
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, |
6e23ae2a4 [NETFILTER]: Intr... |
509 |
dst_output); |
1da177e4c Linux-2.6.12-rc2 |
510 |
if (!err) { |
5c5d244bd ipv6: added net a... |
511 |
ICMP6MSGOUT_INC_STATS(net, idev, type); |
a862f6a6d ipv6: added net a... |
512 |
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1da177e4c Linux-2.6.12-rc2 |
513 |
} |
cfdf76474 ipv6: some RCU co... |
514 |
rcu_read_unlock(); |
1ab1457c4 [NET] IPV6: Fix w... |
515 |
} |
1da177e4c Linux-2.6.12-rc2 |
516 |
|
305d552ac bonding: send IPv... |
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
EXPORT_SYMBOL(ndisc_send_skb); /* * Send a Neighbour Discover packet */ static void __ndisc_send(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *saddr, struct icmp6hdr *icmp6h, const struct in6_addr *target, int llinfo) { struct sk_buff *skb; skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); if (!skb) return; ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); } |
e1ec7842d [IPV6] NDISC: Uni... |
537 |
static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
9acd9f3ae [IPV6]: Make addr... |
538 539 540 |
const struct in6_addr *daddr, const struct in6_addr *solicited_addr, int router, int solicited, int override, int inc_opt) |
e1ec7842d [IPV6] NDISC: Uni... |
541 542 543 |
{ struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; |
9acd9f3ae [IPV6]: Make addr... |
544 |
const struct in6_addr *src_addr; |
e1ec7842d [IPV6] NDISC: Uni... |
545 546 547 548 549 |
struct icmp6hdr icmp6h = { .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, }; /* for anycast or proxy, solicited_addr != src_addr */ |
c346dca10 [NET] NETNS: Omit... |
550 |
ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); |
e1ec7842d [IPV6] NDISC: Uni... |
551 552 553 554 |
if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) override = 0; |
9f888160b ipv6: fix NULL re... |
555 |
inc_opt |= ifp->idev->cnf.force_tllao; |
e1ec7842d [IPV6] NDISC: Uni... |
556 557 |
in6_ifa_put(ifp); } else { |
191cd5825 netns: Add networ... |
558 |
if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, |
c346dca10 [NET] NETNS: Omit... |
559 |
inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, |
7cbca67c0 [IPV6]: Support S... |
560 |
&tmpaddr)) |
e1ec7842d [IPV6] NDISC: Uni... |
561 562 563 564 565 566 567 568 569 570 |
return; src_addr = &tmpaddr; } icmp6h.icmp6_router = router; icmp6h.icmp6_solicited = solicited; icmp6h.icmp6_override = override; __ndisc_send(dev, neigh, daddr, src_addr, &icmp6h, solicited_addr, |
14878f75a [IPV6]: Add ICMPM... |
571 |
inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
e1ec7842d [IPV6] NDISC: Uni... |
572 |
} |
f47b94646 ipv6: Send unsoli... |
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
static void ndisc_send_unsol_na(struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; struct in6_addr mcaddr; idev = in6_dev_get(dev); if (!idev) return; read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { addrconf_addr_solict_mult(&ifa->addr, &mcaddr); ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, /*router=*/ !!idev->cnf.forwarding, /*solicited=*/ false, /*override=*/ true, /*inc_opt=*/ true); } read_unlock_bh(&idev->lock); in6_dev_put(idev); } |
1da177e4c Linux-2.6.12-rc2 |
595 |
void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
9acd9f3ae [IPV6]: Make addr... |
596 597 |
const struct in6_addr *solicit, const struct in6_addr *daddr, const struct in6_addr *saddr) |
1da177e4c Linux-2.6.12-rc2 |
598 |
{ |
1da177e4c Linux-2.6.12-rc2 |
599 |
struct in6_addr addr_buf; |
e1ec7842d [IPV6] NDISC: Uni... |
600 601 602 |
struct icmp6hdr icmp6h = { .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, }; |
1da177e4c Linux-2.6.12-rc2 |
603 604 |
if (saddr == NULL) { |
95c385b4d [IPV6] ADDRCONF: ... |
605 606 |
if (ipv6_get_lladdr(dev, &addr_buf, (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) |
1da177e4c Linux-2.6.12-rc2 |
607 608 609 |
return; saddr = &addr_buf; } |
e1ec7842d [IPV6] NDISC: Uni... |
610 611 |
__ndisc_send(dev, neigh, daddr, saddr, &icmp6h, solicit, |
14878f75a [IPV6]: Add ICMPM... |
612 |
!ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); |
1da177e4c Linux-2.6.12-rc2 |
613 |
} |
9acd9f3ae [IPV6]: Make addr... |
614 615 |
void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr) |
1da177e4c Linux-2.6.12-rc2 |
616 |
{ |
e1ec7842d [IPV6] NDISC: Uni... |
617 618 619 |
struct icmp6hdr icmp6h = { .icmp6_type = NDISC_ROUTER_SOLICITATION, }; |
95c385b4d [IPV6] ADDRCONF: ... |
620 |
int send_sllao = dev->addr_len; |
95c385b4d [IPV6] ADDRCONF: ... |
621 622 623 624 625 626 627 628 |
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD /* * According to section 2.2 of RFC 4429, we must not * send router solicitations with a sllao from * optimistic addresses, but we may send the solicitation * if we don't include the sllao. So here we check * if our address is optimistic, and if so, we |
bea851954 [IPV6]: Spelling ... |
629 |
* suppress the inclusion of the sllao. |
95c385b4d [IPV6] ADDRCONF: ... |
630 631 |
*/ if (send_sllao) { |
c346dca10 [NET] NETNS: Omit... |
632 |
struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, |
1cab3da6b [NETNS][IPV6]: in... |
633 |
dev, 1); |
95c385b4d [IPV6] ADDRCONF: ... |
634 635 |
if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { |
ca0435693 [IPV6] ADDRCONF: ... |
636 |
send_sllao = 0; |
95c385b4d [IPV6] ADDRCONF: ... |
637 |
} |
ca0435693 [IPV6] ADDRCONF: ... |
638 |
in6_ifa_put(ifp); |
95c385b4d [IPV6] ADDRCONF: ... |
639 640 641 642 643 |
} else { send_sllao = 0; } } #endif |
e1ec7842d [IPV6] NDISC: Uni... |
644 645 |
__ndisc_send(dev, NULL, daddr, saddr, &icmp6h, NULL, |
14878f75a [IPV6]: Add ICMPM... |
646 |
send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); |
1da177e4c Linux-2.6.12-rc2 |
647 |
} |
1ab1457c4 [NET] IPV6: Fix w... |
648 |
|
1da177e4c Linux-2.6.12-rc2 |
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) { /* * "The sender MUST return an ICMP * destination unreachable" */ dst_link_failure(skb); kfree_skb(skb); } /* Called with locked neigh: either read or both */ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) { struct in6_addr *saddr = NULL; struct in6_addr mcaddr; struct net_device *dev = neigh->dev; struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); |
c346dca10 [NET] NETNS: Omit... |
669 |
if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) |
0660e03f6 [SK_BUFF]: Introd... |
670 |
saddr = &ipv6_hdr(skb)->saddr; |
1da177e4c Linux-2.6.12-rc2 |
671 672 673 |
if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state & NUD_VALID)) { |
5b095d989 net: replace %p6 ... |
674 675 |
ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: %pI6 ", |
0c6ce78ab net: replace uses... |
676 |
__func__, target); |
1da177e4c Linux-2.6.12-rc2 |
677 678 679 680 681 682 683 684 685 686 687 |
} ndisc_send_ns(dev, neigh, target, target, saddr); } else if ((probes -= neigh->parms->app_probes) < 0) { #ifdef CONFIG_ARPD neigh_app_ns(neigh); #endif } else { addrconf_addr_solict_mult(target, &mcaddr); ndisc_send_ns(dev, NULL, target, &mcaddr, saddr); } } |
0736ffc04 [IPV6] NEIGH: Opt... |
688 689 |
static int pndisc_is_router(const void *pkey, struct net_device *dev) |
fa86d322d [NEIGH]: Fix race... |
690 691 |
{ struct pneigh_entry *n; |
0736ffc04 [IPV6] NEIGH: Opt... |
692 |
int ret = -1; |
fa86d322d [NEIGH]: Fix race... |
693 694 |
read_lock_bh(&nd_tbl.lock); |
0736ffc04 [IPV6] NEIGH: Opt... |
695 696 697 |
n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); if (n) ret = !!(n->flags & NTF_ROUTER); |
fa86d322d [NEIGH]: Fix race... |
698 |
read_unlock_bh(&nd_tbl.lock); |
0736ffc04 [IPV6] NEIGH: Opt... |
699 |
return ret; |
fa86d322d [NEIGH]: Fix race... |
700 |
} |
1da177e4c Linux-2.6.12-rc2 |
701 702 |
static void ndisc_recv_ns(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
703 |
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
b71d1d426 inet: constify ip... |
704 705 |
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
706 |
u8 *lladdr = NULL; |
27a884dc3 [SK_BUFF]: Conver... |
707 708 |
u32 ndoptlen = skb->tail - (skb->transport_header + offsetof(struct nd_msg, opt)); |
1da177e4c Linux-2.6.12-rc2 |
709 710 711 712 713 714 715 |
struct ndisc_options ndopts; struct net_device *dev = skb->dev; struct inet6_ifaddr *ifp; struct inet6_dev *idev = NULL; struct neighbour *neigh; int dad = ipv6_addr_any(saddr); int inc; |
0736ffc04 [IPV6] NEIGH: Opt... |
716 |
int is_router = -1; |
1da177e4c Linux-2.6.12-rc2 |
717 718 |
if (ipv6_addr_is_multicast(&msg->target)) { |
1ab1457c4 [NET] IPV6: Fix w... |
719 |
ND_PRINTK2(KERN_WARNING |
1da177e4c Linux-2.6.12-rc2 |
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
"ICMPv6 NS: multicast target address"); return; } /* * RFC2461 7.1.1: * DAD has to be destined for solicited node multicast address. */ if (dad && !(daddr->s6_addr32[0] == htonl(0xff020000) && daddr->s6_addr32[1] == htonl(0x00000000) && daddr->s6_addr32[2] == htonl(0x00000001) && daddr->s6_addr [12] == 0xff )) { ND_PRINTK2(KERN_WARNING "ICMPv6 NS: bad DAD packet (wrong destination) "); return; } if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) { |
1ab1457c4 [NET] IPV6: Fix w... |
740 |
ND_PRINTK2(KERN_WARNING |
1da177e4c Linux-2.6.12-rc2 |
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
"ICMPv6 NS: invalid ND options "); return; } if (ndopts.nd_opts_src_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev); if (!lladdr) { ND_PRINTK2(KERN_WARNING "ICMPv6 NS: invalid link-layer address length "); return; } /* RFC2461 7.1.1: |
1ab1457c4 [NET] IPV6: Fix w... |
756 757 |
* If the IP source address is the unspecified address, * there MUST NOT be source link-layer address option |
1da177e4c Linux-2.6.12-rc2 |
758 759 760 |
* in the message. */ if (dad) { |
1ab1457c4 [NET] IPV6: Fix w... |
761 |
ND_PRINTK2(KERN_WARNING |
1da177e4c Linux-2.6.12-rc2 |
762 763 764 765 766 767 768 |
"ICMPv6 NS: bad DAD packet (link-layer address option) "); return; } } inc = ipv6_addr_is_multicast(daddr); |
c346dca10 [NET] NETNS: Omit... |
769 |
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
a18bc6959 [NETNS][IPV6] ndi... |
770 |
if (ifp) { |
95c385b4d [IPV6] ADDRCONF: ... |
771 772 773 774 |
if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { if (dad) { if (dev->type == ARPHRD_IEEE802_TR) { |
98e399f82 [SK_BUFF]: Introd... |
775 776 |
const unsigned char *sadr; sadr = skb_mac_header(skb); |
95c385b4d [IPV6] ADDRCONF: ... |
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && sadr[9] == dev->dev_addr[1] && sadr[10] == dev->dev_addr[2] && sadr[11] == dev->dev_addr[3] && sadr[12] == dev->dev_addr[4] && sadr[13] == dev->dev_addr[5]) { /* looped-back to us */ goto out; } } /* * We are colliding with another node * who is doing DAD * so fail our DAD process */ addrconf_dad_failure(ifp); |
9e3be4b34 [IPV6]: Freeing a... |
794 |
return; |
95c385b4d [IPV6] ADDRCONF: ... |
795 796 797 798 799 800 801 802 |
} else { /* * This is not a dad solicitation. * If we are an optimistic node, * we should respond. * Otherwise, we should ignore it. */ if (!(ifp->flags & IFA_F_OPTIMISTIC)) |
1da177e4c Linux-2.6.12-rc2 |
803 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
804 |
} |
1da177e4c Linux-2.6.12-rc2 |
805 806 807 808 |
} idev = ifp->idev; } else { |
53b7997fd ipv6 netns: Make ... |
809 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
810 811 812 813 814 |
idev = in6_dev_get(dev); if (!idev) { /* XXX: count this drop? */ return; } |
53b7997fd ipv6 netns: Make ... |
815 |
if (ipv6_chk_acast_addr(net, dev, &msg->target) || |
1ab1457c4 [NET] IPV6: Fix w... |
816 |
(idev->cnf.forwarding && |
53b7997fd ipv6 netns: Make ... |
817 |
(net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && |
0736ffc04 [IPV6] NEIGH: Opt... |
818 |
(is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { |
a61bbcf28 [NET]: Store skb-... |
819 |
if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
1da177e4c Linux-2.6.12-rc2 |
820 821 822 823 824 |
skb->pkt_type != PACKET_HOST && inc != 0 && idev->nd_parms->proxy_delay != 0) { /* * for anycast or proxy, |
1ab1457c4 [NET] IPV6: Fix w... |
825 826 |
* sender should delay its response * by a random time between 0 and |
1da177e4c Linux-2.6.12-rc2 |
827 828 829 830 831 832 833 834 835 836 837 |
* MAX_ANYCAST_DELAY_TIME seconds. * (RFC2461) -- yoshfuji */ struct sk_buff *n = skb_clone(skb, GFP_ATOMIC); if (n) pneigh_enqueue(&nd_tbl, idev->nd_parms, n); goto out; } } else goto out; } |
0736ffc04 [IPV6] NEIGH: Opt... |
838 839 |
if (is_router < 0) is_router = !!idev->cnf.forwarding; |
62dd93181 [IPV6] NDISC: Set... |
840 |
|
1da177e4c Linux-2.6.12-rc2 |
841 |
if (dad) { |
f3ee4010e [IPV6]: Define co... |
842 |
ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, |
62dd93181 [IPV6] NDISC: Set... |
843 |
is_router, 0, (ifp != NULL), 1); |
1da177e4c Linux-2.6.12-rc2 |
844 845 846 847 848 849 850 |
goto out; } if (inc) NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); |
1ab1457c4 [NET] IPV6: Fix w... |
851 |
/* |
1da177e4c Linux-2.6.12-rc2 |
852 853 854 855 856 857 |
* update / create cache entry * for the source address */ neigh = __neigh_lookup(&nd_tbl, saddr, dev, !inc || lladdr || !dev->addr_len); if (neigh) |
1ab1457c4 [NET] IPV6: Fix w... |
858 |
neigh_update(neigh, lladdr, NUD_STALE, |
1da177e4c Linux-2.6.12-rc2 |
859 860 |
NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE); |
3b04ddde0 [NET]: Move hardw... |
861 |
if (neigh || !dev->header_ops) { |
1da177e4c Linux-2.6.12-rc2 |
862 |
ndisc_send_na(dev, neigh, saddr, &msg->target, |
62dd93181 [IPV6] NDISC: Set... |
863 |
is_router, |
1da177e4c Linux-2.6.12-rc2 |
864 865 866 867 868 869 870 871 872 873 |
1, (ifp != NULL && inc), inc); if (neigh) neigh_release(neigh); } out: if (ifp) in6_ifa_put(ifp); else in6_dev_put(idev); |
1da177e4c Linux-2.6.12-rc2 |
874 875 876 877 |
} static void ndisc_recv_na(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
878 |
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
b71d1d426 inet: constify ip... |
879 880 |
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
881 |
u8 *lladdr = NULL; |
27a884dc3 [SK_BUFF]: Conver... |
882 883 |
u32 ndoptlen = skb->tail - (skb->transport_header + offsetof(struct nd_msg, opt)); |
1da177e4c Linux-2.6.12-rc2 |
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 |
struct ndisc_options ndopts; struct net_device *dev = skb->dev; struct inet6_ifaddr *ifp; struct neighbour *neigh; if (skb->len < sizeof(struct nd_msg)) { ND_PRINTK2(KERN_WARNING "ICMPv6 NA: packet too short "); return; } if (ipv6_addr_is_multicast(&msg->target)) { ND_PRINTK2(KERN_WARNING "ICMPv6 NA: target address is multicast. "); return; } if (ipv6_addr_is_multicast(daddr) && msg->icmph.icmp6_solicited) { ND_PRINTK2(KERN_WARNING "ICMPv6 NA: solicited NA is multicasted. "); return; } |
1ab1457c4 [NET] IPV6: Fix w... |
910 |
|
1da177e4c Linux-2.6.12-rc2 |
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) { ND_PRINTK2(KERN_WARNING "ICMPv6 NS: invalid ND option "); return; } if (ndopts.nd_opts_tgt_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev); if (!lladdr) { ND_PRINTK2(KERN_WARNING "ICMPv6 NA: invalid link-layer address length "); return; } } |
c346dca10 [NET] NETNS: Omit... |
926 |
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
a18bc6959 [NETNS][IPV6] ndi... |
927 |
if (ifp) { |
bd015928b ipv6: ignore loop... |
928 929 930 931 |
if (skb->pkt_type != PACKET_LOOPBACK && (ifp->flags & IFA_F_TENTATIVE)) { addrconf_dad_failure(ifp); return; |
1da177e4c Linux-2.6.12-rc2 |
932 933 934 935 936 |
} /* What should we make now? The advertisement is invalid, but ndisc specs say nothing about it. It could be misconfiguration, or an smart proxy agent tries to help us :-) |
24fc7b86d ipv6: silence log... |
937 938 939 940 |
We should not print the error if NA has been received from loopback - it is just our own unsolicited advertisement. |
1da177e4c Linux-2.6.12-rc2 |
941 |
*/ |
24fc7b86d ipv6: silence log... |
942 943 |
if (skb->pkt_type != PACKET_LOOPBACK) ND_PRINTK1(KERN_WARNING |
a6fa32866 ipv6: Log the exp... |
944 945 946 |
"ICMPv6 NA: someone advertises our address %pI6 on %s! ", &ifp->addr, ifp->idev->dev->name); |
1da177e4c Linux-2.6.12-rc2 |
947 948 949 950 951 952 953 |
in6_ifa_put(ifp); return; } neigh = neigh_lookup(&nd_tbl, &msg->target, dev); if (neigh) { u8 old_flags = neigh->flags; |
53b7997fd ipv6 netns: Make ... |
954 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
955 956 957 |
if (neigh->nud_state & NUD_FAILED) goto out; |
5f3e6e9e1 [IPV6] NDISC: Avo... |
958 959 960 961 962 963 |
/* * Don't update the neighbor cache entry on a proxy NA from * ourselves because either the proxied node is off link or it * has already sent a NA to us. */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && |
53b7997fd ipv6 netns: Make ... |
964 965 |
net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { |
fbea49e1e [IPV6] NDISC: Add... |
966 |
/* XXX: idev->cnf.prixy_ndp */ |
5f3e6e9e1 [IPV6] NDISC: Avo... |
967 |
goto out; |
fbea49e1e [IPV6] NDISC: Add... |
968 |
} |
5f3e6e9e1 [IPV6] NDISC: Avo... |
969 |
|
1da177e4c Linux-2.6.12-rc2 |
970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
neigh_update(neigh, lladdr, msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)| NEIGH_UPDATE_F_OVERRIDE_ISROUTER| (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0)); if ((old_flags & ~neigh->flags) & NTF_ROUTER) { /* * Change: router to host */ struct rt6_info *rt; rt = rt6_get_dflt_router(saddr, dev); if (rt) |
e0a1ad73d [IPv6] route: Sim... |
984 |
ip6_del_rt(rt); |
1da177e4c Linux-2.6.12-rc2 |
985 986 987 988 989 990 991 992 993 |
} out: neigh_release(neigh); } } static void ndisc_recv_rs(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
994 |
struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
995 996 997 |
unsigned long ndoptlen = skb->len - sizeof(*rs_msg); struct neighbour *neigh; struct inet6_dev *idev; |
b71d1d426 inet: constify ip... |
998 |
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1da177e4c Linux-2.6.12-rc2 |
999 1000 1001 1002 1003 |
struct ndisc_options ndopts; u8 *lladdr = NULL; if (skb->len < sizeof(*rs_msg)) return; |
cfdf76474 ipv6: some RCU co... |
1004 |
idev = __in6_dev_get(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 |
if (!idev) { if (net_ratelimit()) ND_PRINTK1("ICMP6 RS: can't find in6 device "); return; } /* Don't accept RS if we're not in router mode */ if (!idev->cnf.forwarding) goto out; /* * Don't update NCE if src = ::; * this implies that the source node has no ip address assigned yet. */ if (ipv6_addr_any(saddr)) goto out; /* Parse ND options */ if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) { if (net_ratelimit()) ND_PRINTK2("ICMP6 NS: invalid ND option, ignored "); goto out; } if (ndopts.nd_opts_src_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, skb->dev); if (!lladdr) goto out; } neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1); if (neigh) { neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE_ISROUTER); neigh_release(neigh); } out: |
cfdf76474 ipv6: some RCU co... |
1047 |
return; |
1da177e4c Linux-2.6.12-rc2 |
1048 |
} |
31910575a [IPv6]: Export us... |
1049 1050 1051 1052 1053 1054 |
static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) { struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra); struct sk_buff *skb; struct nlmsghdr *nlh; struct nduseroptmsg *ndmsg; |
c346dca10 [NET] NETNS: Omit... |
1055 |
struct net *net = dev_net(ra->dev); |
31910575a [IPv6]: Export us... |
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
int err; int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + (opt->nd_opt_len << 3)); size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr)); skb = nlmsg_new(msg_size, GFP_ATOMIC); if (skb == NULL) { err = -ENOBUFS; goto errout; } nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0); if (nlh == NULL) { goto nla_put_failure; } ndmsg = nlmsg_data(nlh); ndmsg->nduseropt_family = AF_INET6; |
dbb2ed248 [IPV6]: Add ifind... |
1074 |
ndmsg->nduseropt_ifindex = ra->dev->ifindex; |
31910575a [IPv6]: Export us... |
1075 1076 1077 1078 1079 1080 1081 1082 1083 |
ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type; ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code; ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3; memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3); NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr), &ipv6_hdr(ra)->saddr); nlmsg_end(skb, nlh); |
1ce85fe40 netlink: change n... |
1084 |
rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); |
31910575a [IPv6]: Export us... |
1085 1086 1087 1088 1089 1090 |
return; nla_put_failure: nlmsg_free(skb); err = -EMSGSIZE; errout: |
a18bc6959 [NETNS][IPV6] ndi... |
1091 |
rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
31910575a [IPv6]: Export us... |
1092 |
} |
65e9b62d4 ipv6: add special... |
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 |
static inline int accept_ra(struct inet6_dev *in6_dev) { /* * If forwarding is enabled, RA are not accepted unless the special * hybrid mode (accept_ra=2) is enabled. */ if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) return 0; return in6_dev->cnf.accept_ra; } |
1da177e4c Linux-2.6.12-rc2 |
1104 1105 |
static void ndisc_router_discovery(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
1106 |
struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
1107 1108 |
struct neighbour *neigh = NULL; struct inet6_dev *in6_dev; |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1109 |
struct rt6_info *rt = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1110 1111 1112 |
int lifetime; struct ndisc_options ndopts; int optlen; |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1113 |
unsigned int pref = 0; |
1da177e4c Linux-2.6.12-rc2 |
1114 1115 |
__u8 * opt = (__u8 *)(ra_msg + 1); |
27a884dc3 [SK_BUFF]: Conver... |
1116 |
optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg); |
1da177e4c Linux-2.6.12-rc2 |
1117 |
|
0660e03f6 [SK_BUFF]: Introd... |
1118 |
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
1da177e4c Linux-2.6.12-rc2 |
1119 1120 1121 1122 1123 1124 |
ND_PRINTK2(KERN_WARNING "ICMPv6 RA: source address is not link-local. "); return; } if (optlen < 0) { |
1ab1457c4 [NET] IPV6: Fix w... |
1125 |
ND_PRINTK2(KERN_WARNING |
1da177e4c Linux-2.6.12-rc2 |
1126 1127 1128 1129 |
"ICMPv6 RA: packet too short "); return; } |
de357cc01 [IPV6] NDISC: Don... |
1130 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1131 1132 1133 1134 1135 1136 |
if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: from host or unauthorized router "); return; } |
de357cc01 [IPV6] NDISC: Don... |
1137 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1138 |
|
1da177e4c Linux-2.6.12-rc2 |
1139 1140 1141 |
/* * set the RA_RECV flag in the interface */ |
cfdf76474 ipv6: some RCU co... |
1142 |
in6_dev = __in6_dev_get(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1143 1144 1145 1146 1147 1148 1149 |
if (in6_dev == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: can't find inet6 device for %s. ", skb->dev->name); return; } |
1da177e4c Linux-2.6.12-rc2 |
1150 1151 |
if (!ndisc_parse_options(opt, optlen, &ndopts)) { |
1da177e4c Linux-2.6.12-rc2 |
1152 1153 1154 1155 1156 |
ND_PRINTK2(KERN_WARNING "ICMP6 RA: invalid ND options "); return; } |
65e9b62d4 ipv6: add special... |
1157 |
if (!accept_ra(in6_dev)) |
31ce8c71a ipv6: Update Neig... |
1158 |
goto skip_linkparms; |
de357cc01 [IPV6] NDISC: Don... |
1159 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1160 1161 1162 |
/* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto skip_linkparms; |
de357cc01 [IPV6] NDISC: Don... |
1163 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1164 |
|
1da177e4c Linux-2.6.12-rc2 |
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 |
if (in6_dev->if_flags & IF_RS_SENT) { /* * flag that an RA was received after an RS was sent * out on this interface. */ in6_dev->if_flags |= IF_RA_RCVD; } /* * Remember the managed/otherconf flags from most recently * received RA message (RFC 2462) -- yoshfuji */ in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED | IF_RA_OTHERCONF)) | (ra_msg->icmph.icmp6_addrconf_managed ? IF_RA_MANAGED : 0) | (ra_msg->icmph.icmp6_addrconf_other ? IF_RA_OTHERCONF : 0); |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1183 1184 |
if (!in6_dev->cnf.accept_ra_defrtr) goto skip_defrtr; |
9f56220fa ipv6: Do not use ... |
1185 1186 |
if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) goto skip_defrtr; |
1da177e4c Linux-2.6.12-rc2 |
1187 |
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1188 1189 1190 |
#ifdef CONFIG_IPV6_ROUTER_PREF pref = ra_msg->icmph.icmp6_router_pref; /* 10b is handled as if it were 00b (medium) */ |
930d6ff2e [IPV6]: ROUTE: Ad... |
1191 |
if (pref == ICMPV6_ROUTER_PREF_INVALID || |
6d5b78cdd [IPV6] NDISC: Fix... |
1192 |
!in6_dev->cnf.accept_ra_rtr_pref) |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1193 1194 |
pref = ICMPV6_ROUTER_PREF_MEDIUM; #endif |
0660e03f6 [SK_BUFF]: Introd... |
1195 |
rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1196 1197 |
if (rt) |
272174550 net: Rename dst_g... |
1198 |
neigh = dst_get_neighbour_noref(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
1199 1200 1201 |
if (rt && lifetime == 0) { neigh_clone(neigh); |
e0a1ad73d [IPv6] route: Sim... |
1202 |
ip6_del_rt(rt); |
1da177e4c Linux-2.6.12-rc2 |
1203 1204 1205 1206 1207 1208 1209 |
rt = NULL; } if (rt == NULL && lifetime) { ND_PRINTK3(KERN_DEBUG "ICMPv6 RA: adding default router. "); |
0660e03f6 [SK_BUFF]: Introd... |
1210 |
rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); |
1da177e4c Linux-2.6.12-rc2 |
1211 1212 1213 1214 |
if (rt == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() failed to add default route. ", |
0dc47877a net: replace rema... |
1215 |
__func__); |
1da177e4c Linux-2.6.12-rc2 |
1216 1217 |
return; } |
272174550 net: Rename dst_g... |
1218 |
neigh = dst_get_neighbour_noref(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
1219 1220 1221 1222 |
if (neigh == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() got default router without neighbour. ", |
0dc47877a net: replace rema... |
1223 |
__func__); |
d8d1f30b9 net-next: remove ... |
1224 |
dst_release(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
1225 1226 1227 |
return; } neigh->flags |= NTF_ROUTER; |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1228 |
} else if (rt) { |
22441cfa0 IPV6: Fix default... |
1229 |
rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); |
1da177e4c Linux-2.6.12-rc2 |
1230 1231 1232 |
} if (rt) |
d19185428 ipv6: Kill rt6i_d... |
1233 |
rt->dst.expires = jiffies + (HZ * lifetime); |
1da177e4c Linux-2.6.12-rc2 |
1234 1235 1236 1237 |
if (ra_msg->icmph.icmp6_hop_limit) { in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; if (rt) |
defb3519a net: Abstract awa... |
1238 1239 |
dst_metric_set(&rt->dst, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit); |
1da177e4c Linux-2.6.12-rc2 |
1240 |
} |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1241 |
skip_defrtr: |
1da177e4c Linux-2.6.12-rc2 |
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 |
/* * Update Reachable Time and Retrans Timer */ if (in6_dev->nd_parms) { unsigned long rtime = ntohl(ra_msg->retrans_timer); if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) { rtime = (rtime*HZ)/1000; if (rtime < HZ/10) rtime = HZ/10; in6_dev->nd_parms->retrans_time = rtime; in6_dev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); } rtime = ntohl(ra_msg->reachable_time); if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) { rtime = (rtime*HZ)/1000; if (rtime < HZ/10) rtime = HZ/10; if (rtime != in6_dev->nd_parms->base_reachable_time) { in6_dev->nd_parms->base_reachable_time = rtime; in6_dev->nd_parms->gc_staletime = 3 * rtime; in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); in6_dev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); } } } |
fadf6bf06 [IPV6] SIT: Add P... |
1274 |
skip_linkparms: |
1da177e4c Linux-2.6.12-rc2 |
1275 1276 1277 1278 1279 |
/* * Process options. */ if (!neigh) |
0660e03f6 [SK_BUFF]: Introd... |
1280 |
neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr, |
1da177e4c Linux-2.6.12-rc2 |
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
skb->dev, 1); if (neigh) { u8 *lladdr = NULL; if (ndopts.nd_opts_src_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, skb->dev); if (!lladdr) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: invalid link-layer address length "); goto out; } } neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE_ISROUTER| NEIGH_UPDATE_F_ISROUTER); } |
65e9b62d4 ipv6: add special... |
1300 |
if (!accept_ra(in6_dev)) |
31ce8c71a ipv6: Update Neig... |
1301 |
goto out; |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1302 |
#ifdef CONFIG_IPV6_ROUTE_INFO |
9f56220fa ipv6: Do not use ... |
1303 1304 |
if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) goto skip_routeinfo; |
09c884d4c [IPV6]: ROUTE: Ad... |
1305 |
if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1306 1307 1308 1309 |
struct nd_opt_hdr *p; for (p = ndopts.nd_opts_ri; p; p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { |
6294e0007 [IPV6] NDISC: Ign... |
1310 1311 1312 1313 1314 1315 1316 |
struct route_info *ri = (struct route_info *)p; #ifdef CONFIG_IPV6_NDISC_NODETYPE if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT && ri->prefix_len == 0) continue; #endif if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) |
09c884d4c [IPV6]: ROUTE: Ad... |
1317 |
continue; |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1318 |
rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, |
0660e03f6 [SK_BUFF]: Introd... |
1319 |
&ipv6_hdr(skb)->saddr); |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1320 1321 |
} } |
9f56220fa ipv6: Do not use ... |
1322 1323 |
skip_routeinfo: |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1324 |
#endif |
de357cc01 [IPV6] NDISC: Don... |
1325 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1326 1327 1328 |
/* skip link-specific ndopts from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto out; |
de357cc01 [IPV6] NDISC: Don... |
1329 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1330 |
|
c4fd30eb1 [IPV6]: ADDRCONF:... |
1331 |
if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { |
1da177e4c Linux-2.6.12-rc2 |
1332 1333 1334 1335 |
struct nd_opt_hdr *p; for (p = ndopts.nd_opts_pi; p; p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) { |
e6bff995f ipv6: Check RA fo... |
1336 1337 1338 |
addrconf_prefix_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, ndopts.nd_opts_src_lladdr != NULL); |
1da177e4c Linux-2.6.12-rc2 |
1339 1340 1341 1342 |
} } if (ndopts.nd_opts_mtu) { |
e69a4adc6 [IPV6]: Misc endi... |
1343 |
__be32 n; |
1da177e4c Linux-2.6.12-rc2 |
1344 |
u32 mtu; |
e69a4adc6 [IPV6]: Misc endi... |
1345 1346 |
memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); mtu = ntohl(n); |
1da177e4c Linux-2.6.12-rc2 |
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 |
if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: invalid mtu: %d ", mtu); } else if (in6_dev->cnf.mtu6 != mtu) { in6_dev->cnf.mtu6 = mtu; if (rt) |
defb3519a net: Abstract awa... |
1357 |
dst_metric_set(&rt->dst, RTAX_MTU, mtu); |
1da177e4c Linux-2.6.12-rc2 |
1358 1359 1360 1361 |
rt6_mtu_change(skb->dev, mtu); } } |
1ab1457c4 [NET] IPV6: Fix w... |
1362 |
|
31910575a [IPv6]: Export us... |
1363 |
if (ndopts.nd_useropts) { |
61cf46ad5 [IPV6] NDISC: Spa... |
1364 1365 1366 1367 1368 |
struct nd_opt_hdr *p; for (p = ndopts.nd_useropts; p; p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) { ndisc_ra_useropt(skb, p); |
31910575a [IPv6]: Export us... |
1369 1370 |
} } |
1da177e4c Linux-2.6.12-rc2 |
1371 1372 1373 1374 1375 1376 |
if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: invalid RA options"); } out: if (rt) |
d8d1f30b9 net-next: remove ... |
1377 |
dst_release(&rt->dst); |
1da177e4c Linux-2.6.12-rc2 |
1378 1379 |
else if (neigh) neigh_release(neigh); |
1da177e4c Linux-2.6.12-rc2 |
1380 1381 1382 1383 1384 1385 |
} static void ndisc_redirect_rcv(struct sk_buff *skb) { struct inet6_dev *in6_dev; struct icmp6hdr *icmph; |
b71d1d426 inet: constify ip... |
1386 1387 |
const struct in6_addr *dest; const struct in6_addr *target; /* new first hop to destination */ |
1da177e4c Linux-2.6.12-rc2 |
1388 1389 1390 1391 1392 |
struct neighbour *neigh; int on_link = 0; struct ndisc_options ndopts; int optlen; u8 *lladdr = NULL; |
de357cc01 [IPV6] NDISC: Don... |
1393 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1394 1395 1396 1397 1398 1399 1400 1401 |
switch (skb->ndisc_nodetype) { case NDISC_NODETYPE_HOST: case NDISC_NODETYPE_NODEFAULT: ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: from host or unauthorized router "); return; } |
de357cc01 [IPV6] NDISC: Don... |
1402 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1403 |
|
0660e03f6 [SK_BUFF]: Introd... |
1404 |
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
1da177e4c Linux-2.6.12-rc2 |
1405 1406 1407 1408 1409 |
ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: source address is not link-local. "); return; } |
27a884dc3 [SK_BUFF]: Conver... |
1410 |
optlen = skb->tail - skb->transport_header; |
1da177e4c Linux-2.6.12-rc2 |
1411 1412 1413 1414 1415 1416 1417 1418 |
optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); if (optlen < 0) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: packet too short "); return; } |
cc70ab261 [ICMP6]: Introduc... |
1419 |
icmph = icmp6_hdr(skb); |
b71d1d426 inet: constify ip... |
1420 |
target = (const struct in6_addr *) (icmph + 1); |
1da177e4c Linux-2.6.12-rc2 |
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 |
dest = target + 1; if (ipv6_addr_is_multicast(dest)) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: destination address is multicast. "); return; } if (ipv6_addr_equal(dest, target)) { on_link = 1; |
bf0b48dfc [IPv6]: Fix ICMPv... |
1432 1433 |
} else if (ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
1ab1457c4 [NET] IPV6: Fix w... |
1434 |
ND_PRINTK2(KERN_WARNING |
bf0b48dfc [IPv6]: Fix ICMPv... |
1435 1436 |
"ICMPv6 Redirect: target address is not link-local unicast. "); |
1da177e4c Linux-2.6.12-rc2 |
1437 1438 |
return; } |
cfdf76474 ipv6: some RCU co... |
1439 |
in6_dev = __in6_dev_get(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1440 1441 |
if (!in6_dev) return; |
cfdf76474 ipv6: some RCU co... |
1442 |
if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) |
1da177e4c Linux-2.6.12-rc2 |
1443 |
return; |
1da177e4c Linux-2.6.12-rc2 |
1444 |
|
1ab1457c4 [NET] IPV6: Fix w... |
1445 |
/* RFC2461 8.1: |
1da177e4c Linux-2.6.12-rc2 |
1446 1447 1448 |
* The IP source address of the Redirect MUST be the same as the current * first-hop router for the specified ICMP Destination Address. */ |
1ab1457c4 [NET] IPV6: Fix w... |
1449 |
|
1da177e4c Linux-2.6.12-rc2 |
1450 1451 1452 1453 |
if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: invalid ND options "); |
1da177e4c Linux-2.6.12-rc2 |
1454 1455 1456 1457 1458 1459 1460 1461 1462 |
return; } if (ndopts.nd_opts_tgt_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, skb->dev); if (!lladdr) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: invalid link-layer address length "); |
1da177e4c Linux-2.6.12-rc2 |
1463 1464 1465 1466 1467 1468 |
return; } } neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); if (neigh) { |
0660e03f6 [SK_BUFF]: Introd... |
1469 1470 |
rt6_redirect(dest, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr, neigh, lladdr, |
1da177e4c Linux-2.6.12-rc2 |
1471 1472 1473 |
on_link); neigh_release(neigh); } |
1da177e4c Linux-2.6.12-rc2 |
1474 1475 1476 |
} void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, |
9acd9f3ae [IPV6]: Make addr... |
1477 |
const struct in6_addr *target) |
1da177e4c Linux-2.6.12-rc2 |
1478 |
{ |
1762f7e88 [NETNS][IPV6] ndi... |
1479 |
struct net_device *dev = skb->dev; |
c346dca10 [NET] NETNS: Omit... |
1480 |
struct net *net = dev_net(dev); |
1762f7e88 [NETNS][IPV6] ndi... |
1481 |
struct sock *sk = net->ipv6.ndisc_sk; |
1da177e4c Linux-2.6.12-rc2 |
1482 1483 1484 1485 1486 |
int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); struct sk_buff *buff; struct icmp6hdr *icmph; struct in6_addr saddr_buf; struct in6_addr *addrp; |
1da177e4c Linux-2.6.12-rc2 |
1487 1488 1489 |
struct rt6_info *rt; struct dst_entry *dst; struct inet6_dev *idev; |
4c9483b2f ipv6: Convert to ... |
1490 |
struct flowi6 fl6; |
1da177e4c Linux-2.6.12-rc2 |
1491 |
u8 *opt; |
a7ae19922 ipv6: Remove all ... |
1492 |
int hlen, tlen; |
1da177e4c Linux-2.6.12-rc2 |
1493 1494 |
int rd_len; int err; |
1da177e4c Linux-2.6.12-rc2 |
1495 |
u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; |
95c385b4d [IPV6] ADDRCONF: ... |
1496 |
if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { |
1da177e4c Linux-2.6.12-rc2 |
1497 1498 1499 1500 |
ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: no link-local address on %s ", dev->name); |
1ab1457c4 [NET] IPV6: Fix w... |
1501 1502 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
1503 |
|
0660e03f6 [SK_BUFF]: Introd... |
1504 |
if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) && |
bf0b48dfc [IPv6]: Fix ICMPv... |
1505 |
ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
29556526b [IPV6]: fix BUG o... |
1506 |
ND_PRINTK2(KERN_WARNING |
bf0b48dfc [IPv6]: Fix ICMPv... |
1507 1508 |
"ICMPv6 Redirect: target address is not link-local unicast. "); |
29556526b [IPV6]: fix BUG o... |
1509 1510 |
return; } |
4c9483b2f ipv6: Convert to ... |
1511 |
icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT, |
95e41e93e [IPV6]: Make ndis... |
1512 |
&saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1da177e4c Linux-2.6.12-rc2 |
1513 |
|
4c9483b2f ipv6: Convert to ... |
1514 |
dst = ip6_route_output(net, NULL, &fl6); |
1da177e4c Linux-2.6.12-rc2 |
1515 1516 |
if (dst == NULL) return; |
4c9483b2f ipv6: Convert to ... |
1517 |
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
452edd598 xfrm: Return dst ... |
1518 |
if (IS_ERR(dst)) |
1da177e4c Linux-2.6.12-rc2 |
1519 |
return; |
1da177e4c Linux-2.6.12-rc2 |
1520 1521 1522 1523 1524 1525 1526 |
rt = (struct rt6_info *) dst; if (rt->rt6i_flags & RTF_GATEWAY) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: destination is not a neighbour. "); |
d73f08011 ipv6/ndisc: join ... |
1527 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1528 |
} |
92d868292 inetpeer: Move IC... |
1529 1530 |
if (!rt->rt6i_peer) rt6_bind_peer(rt, 1); |
4d65a2465 ipv6: fix a bug i... |
1531 |
if (!inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) |
d73f08011 ipv6/ndisc: join ... |
1532 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 |
if (dev->addr_len) { read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) { memcpy(ha_buf, neigh->ha, dev->addr_len); read_unlock_bh(&neigh->lock); ha = ha_buf; len += ndisc_opt_addr_space(dev); } else read_unlock_bh(&neigh->lock); } rd_len = min_t(unsigned int, IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); rd_len &= ~0x7; len += rd_len; |
a7ae19922 ipv6: Remove all ... |
1549 1550 |
hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; |
d54a81d34 [IPV6] NDISC: Cal... |
1551 1552 |
buff = sock_alloc_send_skb(sk, (MAX_HEADER + sizeof(struct ipv6hdr) + |
a7ae19922 ipv6: Remove all ... |
1553 |
len + hlen + tlen), |
1da177e4c Linux-2.6.12-rc2 |
1554 1555 1556 |
1, &err); if (buff == NULL) { ND_PRINTK0(KERN_ERR |
dae9de8e1 IPv6: Print error... |
1557 1558 1559 |
"ICMPv6 Redirect: %s() failed to allocate an skb, err=%d. ", __func__, err); |
d73f08011 ipv6/ndisc: join ... |
1560 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1561 |
} |
a7ae19922 ipv6: Remove all ... |
1562 |
skb_reserve(buff, hlen); |
0660e03f6 [SK_BUFF]: Introd... |
1563 |
ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, |
1da177e4c Linux-2.6.12-rc2 |
1564 |
IPPROTO_ICMPV6, len); |
27a884dc3 [SK_BUFF]: Conver... |
1565 |
skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); |
d10ba34b0 [SK_BUFF]: More s... |
1566 1567 |
skb_put(buff, len); icmph = icmp6_hdr(buff); |
1da177e4c Linux-2.6.12-rc2 |
1568 1569 1570 1571 1572 1573 1574 1575 1576 |
memset(icmph, 0, sizeof(struct icmp6hdr)); icmph->icmp6_type = NDISC_REDIRECT; /* * copy target and destination addresses */ addrp = (struct in6_addr *)(icmph + 1); |
4e3fd7a06 net: remove ipv6_... |
1577 |
*addrp = *target; |
1da177e4c Linux-2.6.12-rc2 |
1578 |
addrp++; |
4e3fd7a06 net: remove ipv6_... |
1579 |
*addrp = ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
opt = (u8*) (addrp + 1); /* * include target_address option */ if (ha) opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, dev->addr_len, dev->type); /* * build redirect option and copy skb over to the new packet. */ |
1ab1457c4 [NET] IPV6: Fix w... |
1594 |
memset(opt, 0, 8); |
1da177e4c Linux-2.6.12-rc2 |
1595 1596 1597 |
*(opt++) = ND_OPT_REDIRECT_HDR; *(opt++) = (rd_len >> 3); opt += 6; |
0660e03f6 [SK_BUFF]: Introd... |
1598 |
memcpy(opt, ipv6_hdr(skb), rd_len - 8); |
1da177e4c Linux-2.6.12-rc2 |
1599 |
|
0660e03f6 [SK_BUFF]: Introd... |
1600 |
icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, |
1da177e4c Linux-2.6.12-rc2 |
1601 |
len, IPPROTO_ICMPV6, |
07f0757a6 include/net net/ ... |
1602 |
csum_partial(icmph, len, 0)); |
1da177e4c Linux-2.6.12-rc2 |
1603 |
|
adf30907d net: skb->dst acc... |
1604 |
skb_dst_set(buff, dst); |
cfdf76474 ipv6: some RCU co... |
1605 1606 |
rcu_read_lock(); idev = __in6_dev_get(dst->dev); |
edf391ff1 snmp: add missing... |
1607 |
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
b2e0b385d netfilter: ipv6: ... |
1608 |
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, |
6e23ae2a4 [NETFILTER]: Intr... |
1609 |
dst_output); |
1da177e4c Linux-2.6.12-rc2 |
1610 |
if (!err) { |
5c5d244bd ipv6: added net a... |
1611 |
ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); |
a862f6a6d ipv6: added net a... |
1612 |
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1da177e4c Linux-2.6.12-rc2 |
1613 |
} |
cfdf76474 ipv6: some RCU co... |
1614 |
rcu_read_unlock(); |
d73f08011 ipv6/ndisc: join ... |
1615 1616 1617 1618 |
return; release: dst_release(dst); |
1da177e4c Linux-2.6.12-rc2 |
1619 1620 1621 1622 |
} static void pndisc_redo(struct sk_buff *skb) { |
140e26fcd [IPV6]: Fix NS ha... |
1623 |
ndisc_recv_ns(skb); |
1da177e4c Linux-2.6.12-rc2 |
1624 1625 1626 1627 1628 1629 1630 1631 1632 |
kfree_skb(skb); } int ndisc_rcv(struct sk_buff *skb) { struct nd_msg *msg; if (!pskb_may_pull(skb, skb->len)) return 0; |
9c70220b7 [SK_BUFF]: Introd... |
1633 |
msg = (struct nd_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
1634 |
|
9c70220b7 [SK_BUFF]: Introd... |
1635 |
__skb_push(skb, skb->data - skb_transport_header(skb)); |
1da177e4c Linux-2.6.12-rc2 |
1636 |
|
0660e03f6 [SK_BUFF]: Introd... |
1637 |
if (ipv6_hdr(skb)->hop_limit != 255) { |
1da177e4c Linux-2.6.12-rc2 |
1638 1639 1640 |
ND_PRINTK2(KERN_WARNING "ICMPv6 NDISC: invalid hop-limit: %d ", |
0660e03f6 [SK_BUFF]: Introd... |
1641 |
ipv6_hdr(skb)->hop_limit); |
1da177e4c Linux-2.6.12-rc2 |
1642 1643 1644 1645 |
return 0; } if (msg->icmph.icmp6_code != 0) { |
1ab1457c4 [NET] IPV6: Fix w... |
1646 |
ND_PRINTK2(KERN_WARNING |
1da177e4c Linux-2.6.12-rc2 |
1647 1648 1649 1650 1651 |
"ICMPv6 NDISC: invalid ICMPv6 code: %d ", msg->icmph.icmp6_code); return 0; } |
a61bbcf28 [NET]: Store skb-... |
1652 |
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); |
1da177e4c Linux-2.6.12-rc2 |
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 |
switch (msg->icmph.icmp6_type) { case NDISC_NEIGHBOUR_SOLICITATION: ndisc_recv_ns(skb); break; case NDISC_NEIGHBOUR_ADVERTISEMENT: ndisc_recv_na(skb); break; case NDISC_ROUTER_SOLICITATION: ndisc_recv_rs(skb); break; case NDISC_ROUTER_ADVERTISEMENT: ndisc_router_discovery(skb); break; case NDISC_REDIRECT: ndisc_redirect_rcv(skb); break; |
3ff50b799 [NET]: cleanup ex... |
1673 |
} |
1da177e4c Linux-2.6.12-rc2 |
1674 1675 1676 1677 1678 1679 1680 |
return 0; } static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; |
c346dca10 [NET] NETNS: Omit... |
1681 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
1682 1683 1684 1685 |
switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); |
5b7c931df [NETNS][IPV6] ip6... |
1686 |
fib6_run_gc(~0UL, net); |
1da177e4c Linux-2.6.12-rc2 |
1687 1688 1689 |
break; case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); |
5b7c931df [NETNS][IPV6] ip6... |
1690 |
fib6_run_gc(~0UL, net); |
1da177e4c Linux-2.6.12-rc2 |
1691 |
break; |
f47b94646 ipv6: Send unsoli... |
1692 1693 1694 |
case NETDEV_NOTIFY_PEERS: ndisc_send_unsol_na(dev); break; |
1da177e4c Linux-2.6.12-rc2 |
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 |
default: break; } return NOTIFY_DONE; } static struct notifier_block ndisc_netdev_notifier = { .notifier_call = ndisc_netdev_event, }; #ifdef CONFIG_SYSCTL static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl, const char *func, const char *dev_name) { static char warncomm[TASK_COMM_LEN]; static int warned; if (strcmp(warncomm, current->comm) && warned < 5) { strcpy(warncomm, current->comm); printk(KERN_WARNING "process `%s' is using deprecated sysctl (%s) " "net.ipv6.neigh.%s.%s; " "Use net.ipv6.neigh.%s.%s_ms " "instead. ", warncomm, func, dev_name, ctl->procname, dev_name, ctl->procname); warned++; } } |
8d65af789 sysctl: remove "s... |
1726 |
int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) |
1da177e4c Linux-2.6.12-rc2 |
1727 1728 1729 1730 |
{ struct net_device *dev = ctl->extra1; struct inet6_dev *idev; int ret; |
d12af679b sysctl: fix neigh... |
1731 1732 |
if ((strcmp(ctl->procname, "retrans_time") == 0) || (strcmp(ctl->procname, "base_reachable_time") == 0)) |
1da177e4c Linux-2.6.12-rc2 |
1733 |
ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); |
d12af679b sysctl: fix neigh... |
1734 |
if (strcmp(ctl->procname, "retrans_time") == 0) |
8d65af789 sysctl: remove "s... |
1735 |
ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1736 1737 |
else if (strcmp(ctl->procname, "base_reachable_time") == 0) |
1da177e4c Linux-2.6.12-rc2 |
1738 |
ret = proc_dointvec_jiffies(ctl, write, |
8d65af789 sysctl: remove "s... |
1739 |
buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1740 1741 |
else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || |
ad02ac145 [IPV6] NDISC: Fix... |
1742 |
(strcmp(ctl->procname, "base_reachable_time_ms") == 0)) |
1da177e4c Linux-2.6.12-rc2 |
1743 |
ret = proc_dointvec_ms_jiffies(ctl, write, |
8d65af789 sysctl: remove "s... |
1744 |
buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1745 |
else |
1da177e4c Linux-2.6.12-rc2 |
1746 |
ret = -1; |
1da177e4c Linux-2.6.12-rc2 |
1747 1748 |
if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { |
d12af679b sysctl: fix neigh... |
1749 |
if (ctl->data == &idev->nd_parms->base_reachable_time) |
1da177e4c Linux-2.6.12-rc2 |
1750 1751 1752 1753 1754 1755 1756 |
idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time); idev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, idev); in6_dev_put(idev); } return ret; } |
1da177e4c Linux-2.6.12-rc2 |
1757 1758 |
#endif |
2c8c1e729 net: spread __net... |
1759 |
static int __net_init ndisc_net_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
1760 1761 1762 |
{ struct ipv6_pinfo *np; struct sock *sk; |
1ab1457c4 [NET] IPV6: Fix w... |
1763 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
1764 |
|
1ed8516f0 [IPV6]: Simplify ... |
1765 1766 |
err = inet_ctl_sock_create(&sk, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, net); |
1da177e4c Linux-2.6.12-rc2 |
1767 1768 |
if (err < 0) { ND_PRINTK0(KERN_ERR |
1ab1457c4 [NET] IPV6: Fix w... |
1769 1770 |
"ICMPv6 NDISC: Failed to initialize the control socket (err %d). ", |
1da177e4c Linux-2.6.12-rc2 |
1771 |
err); |
1da177e4c Linux-2.6.12-rc2 |
1772 1773 |
return err; } |
1ed8516f0 [IPV6]: Simplify ... |
1774 |
net->ipv6.ndisc_sk = sk; |
1762f7e88 [NETNS][IPV6] ndi... |
1775 |
|
1da177e4c Linux-2.6.12-rc2 |
1776 |
np = inet6_sk(sk); |
1da177e4c Linux-2.6.12-rc2 |
1777 1778 1779 |
np->hop_limit = 255; /* Do not loopback ndisc messages */ np->mc_loop = 0; |
1da177e4c Linux-2.6.12-rc2 |
1780 |
|
1762f7e88 [NETNS][IPV6] ndi... |
1781 1782 |
return 0; } |
2c8c1e729 net: spread __net... |
1783 |
static void __net_exit ndisc_net_exit(struct net *net) |
1762f7e88 [NETNS][IPV6] ndi... |
1784 |
{ |
1ed8516f0 [IPV6]: Simplify ... |
1785 |
inet_ctl_sock_destroy(net->ipv6.ndisc_sk); |
1762f7e88 [NETNS][IPV6] ndi... |
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 |
} static struct pernet_operations ndisc_net_ops = { .init = ndisc_net_init, .exit = ndisc_net_exit, }; int __init ndisc_init(void) { int err; err = register_pernet_subsys(&ndisc_net_ops); if (err) return err; |
1ab1457c4 [NET] IPV6: Fix w... |
1800 1801 1802 |
/* * Initialize the neighbour table */ |
1da177e4c Linux-2.6.12-rc2 |
1803 1804 1805 |
neigh_table_init(&nd_tbl); #ifdef CONFIG_SYSCTL |
54716e3be net neigh: Decoup... |
1806 |
err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", |
f8572d8f2 sysctl net: Remov... |
1807 |
&ndisc_ifinfo_sysctl_change); |
1762f7e88 [NETNS][IPV6] ndi... |
1808 1809 |
if (err) goto out_unregister_pernet; |
1da177e4c Linux-2.6.12-rc2 |
1810 |
#endif |
1762f7e88 [NETNS][IPV6] ndi... |
1811 1812 1813 1814 1815 |
err = register_netdevice_notifier(&ndisc_netdev_notifier); if (err) goto out_unregister_sysctl; out: return err; |
1da177e4c Linux-2.6.12-rc2 |
1816 |
|
1762f7e88 [NETNS][IPV6] ndi... |
1817 1818 1819 1820 1821 1822 1823 |
out_unregister_sysctl: #ifdef CONFIG_SYSCTL neigh_sysctl_unregister(&nd_tbl.parms); out_unregister_pernet: #endif unregister_pernet_subsys(&ndisc_net_ops); goto out; |
1da177e4c Linux-2.6.12-rc2 |
1824 1825 1826 1827 |
} void ndisc_cleanup(void) { |
36f73d0c3 [IPV6]: Add ndisc... |
1828 |
unregister_netdevice_notifier(&ndisc_netdev_notifier); |
1da177e4c Linux-2.6.12-rc2 |
1829 1830 1831 1832 |
#ifdef CONFIG_SYSCTL neigh_sysctl_unregister(&nd_tbl.parms); #endif neigh_table_clear(&nd_tbl); |
1762f7e88 [NETNS][IPV6] ndi... |
1833 |
unregister_pernet_subsys(&ndisc_net_ops); |
1da177e4c Linux-2.6.12-rc2 |
1834 |
} |