Blame view
net/ipv6/ndisc.c
47.1 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: * |
e35f30c13 Treat ND option 3... |
18 |
* Alexey I. Froloff : RFC6106 (DNSSL) support |
31910575a [IPv6]: Export us... |
19 20 |
* Pierre Ynard : export userland ND options * through netlink (RDNSS support) |
1da177e4c Linux-2.6.12-rc2 |
21 22 |
* Lars Fenneberg : fixed MTU setting on receipt * of an RA. |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 28 |
* 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 */ |
675418d51 net: ipv6: ndisc:... |
29 |
#define pr_fmt(fmt) "ICMPv6: " fmt |
1da177e4c Linux-2.6.12-rc2 |
30 31 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 35 36 37 38 39 40 41 |
#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: ... |
42 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 |
#ifdef CONFIG_SYSCTL #include <linux/sysctl.h> #endif |
1823730fb [IPv4]: Move inte... |
46 |
#include <linux/if_addr.h> |
1da177e4c Linux-2.6.12-rc2 |
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#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... |
61 62 |
#include <net/netlink.h> #include <linux/rtnetlink.h> |
1da177e4c Linux-2.6.12-rc2 |
63 64 |
#include <net/flow.h> #include <net/ip6_checksum.h> |
1ed8516f0 [IPV6]: Simplify ... |
65 |
#include <net/inet_common.h> |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 |
#include <linux/proc_fs.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv6.h> |
d6bf78171 net neigh: RCU co... |
70 71 |
static u32 ndisc_hash(const void *pkey, const struct net_device *dev, |
2c2aba6c5 ipv6: Use univers... |
72 |
__u32 *hash_rnd); |
60395a20f neigh: Factor out... |
73 |
static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey); |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 77 78 79 |
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... |
80 |
static const struct neigh_ops ndisc_generic_ops = { |
1da177e4c Linux-2.6.12-rc2 |
81 82 83 84 85 |
.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 |
86 |
}; |
89d69d2b7 net: make neigh_o... |
87 |
static const struct neigh_ops ndisc_hh_ops = { |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 91 92 |
.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 |
93 |
}; |
89d69d2b7 net: make neigh_o... |
94 |
static const struct neigh_ops ndisc_direct_ops = { |
1da177e4c Linux-2.6.12-rc2 |
95 |
.family = AF_INET6, |
8f40b161d neigh: Pass neigh... |
96 97 |
.output = neigh_direct_output, .connected_output = neigh_direct_output, |
1da177e4c Linux-2.6.12-rc2 |
98 99 100 101 |
}; struct neigh_table nd_tbl = { .family = AF_INET6, |
1da177e4c Linux-2.6.12-rc2 |
102 |
.key_len = sizeof(struct in6_addr), |
bdf53c584 neigh: Don't requ... |
103 |
.protocol = cpu_to_be16(ETH_P_IPV6), |
1da177e4c Linux-2.6.12-rc2 |
104 |
.hash = ndisc_hash, |
60395a20f neigh: Factor out... |
105 |
.key_eq = ndisc_key_eq, |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 109 110 111 |
.constructor = ndisc_constructor, .pconstructor = pndisc_constructor, .pdestructor = pndisc_destructor, .proxy_redo = pndisc_redo, .id = "ndisc_cache", .parms = { |
b672083ed ipv6: use ND_REAC... |
112 |
.tbl = &nd_tbl, |
b672083ed ipv6: use ND_REAC... |
113 |
.reachable_time = ND_REACHABLE_TIME, |
1f9248e56 neigh: convert pa... |
114 115 116 117 118 119 120 121 122 123 124 125 |
.data = { [NEIGH_VAR_MCAST_PROBES] = 3, [NEIGH_VAR_UCAST_PROBES] = 3, [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER, [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME, [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, [NEIGH_VAR_GC_STALETIME] = 60 * HZ, [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, [NEIGH_VAR_PROXY_QLEN] = 64, [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, }, |
1da177e4c Linux-2.6.12-rc2 |
126 127 128 129 130 131 |
}, .gc_interval = 30 * HZ, .gc_thresh1 = 128, .gc_thresh2 = 512, .gc_thresh3 = 1024, }; |
c48506877 net: Export fib6_... |
132 |
EXPORT_SYMBOL_GPL(nd_tbl); |
1da177e4c Linux-2.6.12-rc2 |
133 |
|
cc84b3c6b ipv6: export seve... |
134 135 |
void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data, int data_len, int pad) |
1da177e4c Linux-2.6.12-rc2 |
136 |
{ |
8ec5da415 ndisc: add __ndis... |
137 |
int space = __ndisc_opt_addr_space(data_len, pad); |
5f5a01156 ndisc: Make ndisc... |
138 |
u8 *opt = skb_put(skb, space); |
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 143 144 145 146 147 148 149 |
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; |
e5d08d718 ipv6: coding styl... |
150 151 |
space -= data_len; if (space > 0) |
1da177e4c Linux-2.6.12-rc2 |
152 |
memset(opt, 0, space); |
1da177e4c Linux-2.6.12-rc2 |
153 |
} |
cc84b3c6b ipv6: export seve... |
154 |
EXPORT_SYMBOL_GPL(__ndisc_fill_addr_option); |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
8ec5da415 ndisc: add __ndis... |
156 |
static inline void ndisc_fill_addr_option(struct sk_buff *skb, int type, |
f997c55c1 ipv6: introduce n... |
157 |
void *data, u8 icmp6_type) |
8ec5da415 ndisc: add __ndis... |
158 159 160 |
{ __ndisc_fill_addr_option(skb, type, data, skb->dev->addr_len, ndisc_addr_option_pad(skb->dev->type)); |
f997c55c1 ipv6: introduce n... |
161 162 163 164 165 166 167 168 169 |
ndisc_ops_fill_addr_option(skb->dev, skb, icmp6_type); } static inline void ndisc_fill_redirect_addr_option(struct sk_buff *skb, void *ha, const u8 *ops_data) { ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha, NDISC_REDIRECT); ndisc_ops_fill_redirect_addr_option(skb->dev, skb, ops_data); |
8ec5da415 ndisc: add __ndis... |
170 |
} |
1da177e4c Linux-2.6.12-rc2 |
171 172 173 174 175 176 177 178 179 |
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); |
67ba4152e ipv6: White-space... |
180 |
} while (cur < end && cur->nd_opt_type != type); |
a02cec215 net: return opera... |
181 |
return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
1da177e4c Linux-2.6.12-rc2 |
182 |
} |
f997c55c1 ipv6: introduce n... |
183 184 |
static inline int ndisc_is_useropt(const struct net_device *dev, struct nd_opt_hdr *opt) |
31910575a [IPv6]: Export us... |
185 |
{ |
e35f30c13 Treat ND option 3... |
186 |
return opt->nd_opt_type == ND_OPT_RDNSS || |
f997c55c1 ipv6: introduce n... |
187 188 |
opt->nd_opt_type == ND_OPT_DNSSL || ndisc_ops_is_useropt(dev, opt->nd_opt_type); |
31910575a [IPv6]: Export us... |
189 |
} |
f997c55c1 ipv6: introduce n... |
190 191 |
static struct nd_opt_hdr *ndisc_next_useropt(const struct net_device *dev, struct nd_opt_hdr *cur, |
31910575a [IPv6]: Export us... |
192 193 194 195 196 197 |
struct nd_opt_hdr *end) { if (!cur || !end || cur >= end) return NULL; do { cur = ((void *)cur) + (cur->nd_opt_len << 3); |
f997c55c1 ipv6: introduce n... |
198 199 |
} while (cur < end && !ndisc_is_useropt(dev, cur)); return cur <= end && ndisc_is_useropt(dev, cur) ? cur : NULL; |
31910575a [IPv6]: Export us... |
200 |
} |
f997c55c1 ipv6: introduce n... |
201 202 |
struct ndisc_options *ndisc_parse_options(const struct net_device *dev, u8 *opt, int opt_len, |
30f2a5f37 ipv6: Export ndis... |
203 |
struct ndisc_options *ndopts) |
1da177e4c Linux-2.6.12-rc2 |
204 205 206 207 208 209 210 211 212 213 214 215 216 |
{ 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; |
f997c55c1 ipv6: introduce n... |
217 218 |
if (ndisc_ops_parse_options(dev, nd_opt, ndopts)) goto next_opt; |
1da177e4c Linux-2.6.12-rc2 |
219 220 221 222 |
switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LL_ADDR: case ND_OPT_TARGET_LL_ADDR: case ND_OPT_MTU: |
adc176c54 ipv6 addrconf: Im... |
223 |
case ND_OPT_NONCE: |
1da177e4c Linux-2.6.12-rc2 |
224 225 |
case ND_OPT_REDIRECT_HDR: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { |
675418d51 net: ipv6: ndisc:... |
226 227 228 229 |
ND_PRINTK(2, warn, "%s: duplicated ND6 option found: type=%d ", __func__, nd_opt->nd_opt_type); |
1da177e4c Linux-2.6.12-rc2 |
230 231 232 233 234 235 |
} 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... |
236 |
if (!ndopts->nd_opt_array[nd_opt->nd_opt_type]) |
1da177e4c Linux-2.6.12-rc2 |
237 238 |
ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; break; |
70ceb4f53 [IPV6]: ROUTE: Ad... |
239 240 241 242 243 244 245 |
#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 |
246 |
default: |
f997c55c1 ipv6: introduce n... |
247 |
if (ndisc_is_useropt(dev, nd_opt)) { |
31910575a [IPv6]: Export us... |
248 249 250 251 252 253 254 255 256 |
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. */ |
675418d51 net: ipv6: ndisc:... |
257 258 259 260 261 262 |
ND_PRINTK(2, notice, "%s: ignored unsupported option; type=%d, len=%d ", __func__, nd_opt->nd_opt_type, nd_opt->nd_opt_len); |
31910575a [IPv6]: Export us... |
263 |
} |
1da177e4c Linux-2.6.12-rc2 |
264 |
} |
f997c55c1 ipv6: introduce n... |
265 |
next_opt: |
1da177e4c Linux-2.6.12-rc2 |
266 267 268 269 270 |
opt_len -= l; nd_opt = ((void *)nd_opt) + l; } return ndopts; } |
b71d1d426 inet: constify ip... |
271 |
int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
1da177e4c Linux-2.6.12-rc2 |
272 273 274 275 276 277 278 |
{ 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; |
1da177e4c Linux-2.6.12-rc2 |
279 280 281 282 |
case ARPHRD_ARCNET: ipv6_arcnet_mc_map(addr, buf); return 0; case ARPHRD_INFINIBAND: |
a9e527e3f IPoIB: improve IP... |
283 |
ipv6_ib_mc_map(addr, dev->broadcast, buf); |
1da177e4c Linux-2.6.12-rc2 |
284 |
return 0; |
93ca3bb5d net: gre: provide... |
285 286 |
case ARPHRD_IPGRE: return ipv6_ipgre_mc_map(addr, dev->broadcast, buf); |
1da177e4c Linux-2.6.12-rc2 |
287 288 289 290 291 292 293 294 |
default: if (dir) { memcpy(buf, dev->broadcast, dev->addr_len); return 0; } } return -EINVAL; } |
7159039a1 [IPV6]: Decentral... |
295 |
EXPORT_SYMBOL(ndisc_mc_map); |
d6bf78171 net neigh: RCU co... |
296 297 |
static u32 ndisc_hash(const void *pkey, const struct net_device *dev, |
2c2aba6c5 ipv6: Use univers... |
298 |
__u32 *hash_rnd) |
1da177e4c Linux-2.6.12-rc2 |
299 |
{ |
2c2aba6c5 ipv6: Use univers... |
300 |
return ndisc_hashfn(pkey, dev, hash_rnd); |
1da177e4c Linux-2.6.12-rc2 |
301 |
} |
60395a20f neigh: Factor out... |
302 303 304 305 |
static bool ndisc_key_eq(const struct neighbour *n, const void *pkey) { return neigh_key_eq128(n, pkey); } |
1da177e4c Linux-2.6.12-rc2 |
306 307 |
static int ndisc_constructor(struct neighbour *neigh) { |
67ba4152e ipv6: White-space... |
308 |
struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key; |
1da177e4c Linux-2.6.12-rc2 |
309 310 311 |
struct net_device *dev = neigh->dev; struct inet6_dev *in6_dev; struct neigh_parms *parms; |
a50feda54 ipv6: bool/const ... |
312 |
bool is_multicast = ipv6_addr_is_multicast(addr); |
1da177e4c Linux-2.6.12-rc2 |
313 |
|
1da177e4c Linux-2.6.12-rc2 |
314 |
in6_dev = in6_dev_get(dev); |
63159f29b ipv6: coding styl... |
315 |
if (!in6_dev) { |
1da177e4c Linux-2.6.12-rc2 |
316 317 318 319 320 321 |
return -EINVAL; } parms = in6_dev->nd_parms; __neigh_parms_put(neigh->parms); neigh->parms = neigh_parms_clone(parms); |
1da177e4c Linux-2.6.12-rc2 |
322 323 |
neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; |
3b04ddde0 [NET]: Move hardw... |
324 |
if (!dev->header_ops) { |
1da177e4c Linux-2.6.12-rc2 |
325 326 |
neigh->nud_state = NUD_NOARP; neigh->ops = &ndisc_direct_ops; |
8f40b161d neigh: Pass neigh... |
327 |
neigh->output = neigh_direct_output; |
1da177e4c Linux-2.6.12-rc2 |
328 329 330 331 332 333 334 335 336 337 338 339 340 |
} 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... |
341 |
if (dev->header_ops->cache) |
1da177e4c Linux-2.6.12-rc2 |
342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
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) { |
67ba4152e ipv6: White-space... |
356 |
struct in6_addr *addr = (struct in6_addr *)&n->key; |
1da177e4c Linux-2.6.12-rc2 |
357 358 |
struct in6_addr maddr; struct net_device *dev = n->dev; |
63159f29b ipv6: coding styl... |
359 |
if (!dev || !__in6_dev_get(dev)) |
1da177e4c Linux-2.6.12-rc2 |
360 361 362 363 364 365 366 367 |
return -EINVAL; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_inc(dev, &maddr); return 0; } static void pndisc_destructor(struct pneigh_entry *n) { |
67ba4152e ipv6: White-space... |
368 |
struct in6_addr *addr = (struct in6_addr *)&n->key; |
1da177e4c Linux-2.6.12-rc2 |
369 370 |
struct in6_addr maddr; struct net_device *dev = n->dev; |
63159f29b ipv6: coding styl... |
371 |
if (!dev || !__in6_dev_get(dev)) |
1da177e4c Linux-2.6.12-rc2 |
372 373 374 375 |
return; addrconf_addr_solict_mult(addr, &maddr); ipv6_dev_mc_dec(dev, &maddr); } |
de09334b9 ndisc: Introduce ... |
376 377 378 379 380 381 382 |
static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, int len) { int hlen = LL_RESERVED_SPACE(dev); int tlen = dev->needed_tailroom; struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; struct sk_buff *skb; |
de09334b9 ndisc: Introduce ... |
383 |
|
25a6e6b84 ipv6: Don't depen... |
384 |
skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC); |
de09334b9 ndisc: Introduce ... |
385 |
if (!skb) { |
25a6e6b84 ipv6: Don't depen... |
386 387 388 |
ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb ", __func__); |
de09334b9 ndisc: Introduce ... |
389 390 |
return NULL; } |
f382d03ad ndisc: Set skb->d... |
391 392 |
skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; |
527a150fb ndisc: Defer buil... |
393 |
skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); |
5135e633f ndisc: Reset skb-... |
394 |
skb_reset_transport_header(skb); |
de09334b9 ndisc: Introduce ... |
395 |
|
25a6e6b84 ipv6: Don't depen... |
396 397 398 399 |
/* Manually assign socket ownership as we avoid calling * sock_alloc_send_pskb() to bypass wmem buffer limits */ skb_set_owner_w(skb, sk); |
de09334b9 ndisc: Introduce ... |
400 401 |
return skb; } |
f382d03ad ndisc: Set skb->d... |
402 |
static void ip6_nd_hdr(struct sk_buff *skb, |
2576f17df ipv6: Unshare ip6... |
403 404 |
const struct in6_addr *saddr, const struct in6_addr *daddr, |
c8d6c380d ndisc: Simplify a... |
405 |
int hop_limit, int len) |
2576f17df ipv6: Unshare ip6... |
406 407 |
{ struct ipv6hdr *hdr; |
527a150fb ndisc: Defer buil... |
408 |
skb_push(skb, sizeof(*hdr)); |
2576f17df ipv6: Unshare ip6... |
409 |
skb_reset_network_header(skb); |
2576f17df ipv6: Unshare ip6... |
410 411 412 413 414 |
hdr = ipv6_hdr(skb); ip6_flow_hdr(hdr, 0, 0); hdr->payload_len = htons(len); |
c8d6c380d ndisc: Simplify a... |
415 416 |
hdr->nexthdr = IPPROTO_ICMPV6; hdr->hop_limit = hop_limit; |
2576f17df ipv6: Unshare ip6... |
417 418 419 420 |
hdr->saddr = *saddr; hdr->daddr = *daddr; } |
af9a99762 ndisc: Remove dev... |
421 |
static void ndisc_send_skb(struct sk_buff *skb, |
fd0ea7dbf ndisc: Unexport n... |
422 |
const struct in6_addr *daddr, |
aa4bdd4b3 ndisc: Remove icm... |
423 |
const struct in6_addr *saddr) |
305d552ac bonding: send IPv... |
424 |
{ |
f4de84c64 ndisc: Use ndisc_... |
425 |
struct dst_entry *dst = skb_dst(skb); |
af9a99762 ndisc: Remove dev... |
426 |
struct net *net = dev_net(skb->dev); |
7b3d9b06d ndisc: Fill in IC... |
427 |
struct sock *sk = net->ipv6.ndisc_sk; |
305d552ac bonding: send IPv... |
428 429 |
struct inet6_dev *idev; int err; |
aa4bdd4b3 ndisc: Remove icm... |
430 |
struct icmp6hdr *icmp6h = icmp6_hdr(skb); |
305d552ac bonding: send IPv... |
431 432 433 |
u8 type; type = icmp6h->icmp6_type; |
f4de84c64 ndisc: Use ndisc_... |
434 |
if (!dst) { |
f4de84c64 ndisc: Use ndisc_... |
435 |
struct flowi6 fl6; |
e0d56fdd7 net: l3mdev: remo... |
436 |
int oif = skb->dev->ifindex; |
305d552ac bonding: send IPv... |
437 |
|
ca254490c net: Add VRF supp... |
438 |
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif); |
f4de84c64 ndisc: Use ndisc_... |
439 440 441 442 443 444 445 446 |
dst = icmp6_dst_alloc(skb->dev, &fl6); if (IS_ERR(dst)) { kfree_skb(skb); return; } skb_dst_set(skb, dst); } |
e1ec7842d [IPV6] NDISC: Uni... |
447 |
|
7b3d9b06d ndisc: Fill in IC... |
448 449 450 451 452 453 |
icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, csum_partial(icmp6h, skb->len, 0)); ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); |
cfdf76474 ipv6: some RCU co... |
454 455 |
rcu_read_lock(); idev = __in6_dev_get(dst->dev); |
edf391ff1 snmp: add missing... |
456 |
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
e1ec7842d [IPV6] NDISC: Uni... |
457 |
|
29a26a568 netfilter: Pass s... |
458 459 |
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, NULL, dst->dev, |
13206b6bf net: Pass net int... |
460 |
dst_output); |
1da177e4c Linux-2.6.12-rc2 |
461 |
if (!err) { |
5c5d244bd ipv6: added net a... |
462 |
ICMP6MSGOUT_INC_STATS(net, idev, type); |
a862f6a6d ipv6: added net a... |
463 |
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1da177e4c Linux-2.6.12-rc2 |
464 |
} |
cfdf76474 ipv6: some RCU co... |
465 |
rcu_read_unlock(); |
1ab1457c4 [NET] IPV6: Fix w... |
466 |
} |
1da177e4c Linux-2.6.12-rc2 |
467 |
|
38cf595b1 ipv6: remove unus... |
468 |
void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, |
f564f45c4 vxlan: add ipv6 p... |
469 470 |
const struct in6_addr *solicited_addr, bool router, bool solicited, bool override, bool inc_opt) |
e1ec7842d [IPV6] NDISC: Uni... |
471 |
{ |
b44b5f4ae ndisc: Break down... |
472 |
struct sk_buff *skb; |
e1ec7842d [IPV6] NDISC: Uni... |
473 474 |
struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; |
9acd9f3ae [IPV6]: Make addr... |
475 |
const struct in6_addr *src_addr; |
1cb3fe513 ndisc: Break down... |
476 477 |
struct nd_msg *msg; int optlen = 0; |
e1ec7842d [IPV6] NDISC: Uni... |
478 479 |
/* for anycast or proxy, solicited_addr != src_addr */ |
c346dca10 [NET] NETNS: Omit... |
480 |
ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); |
e1ec7842d [IPV6] NDISC: Uni... |
481 482 483 |
if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) |
f2f79cca1 ndisc: bool initi... |
484 |
override = false; |
9f888160b ipv6: fix NULL re... |
485 |
inc_opt |= ifp->idev->cnf.force_tllao; |
e1ec7842d [IPV6] NDISC: Uni... |
486 487 |
in6_ifa_put(ifp); } else { |
191cd5825 netns: Add networ... |
488 |
if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, |
c346dca10 [NET] NETNS: Omit... |
489 |
inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, |
7cbca67c0 [IPV6]: Support S... |
490 |
&tmpaddr)) |
e1ec7842d [IPV6] NDISC: Uni... |
491 492 493 |
return; src_addr = &tmpaddr; } |
1cb3fe513 ndisc: Break down... |
494 495 496 |
if (!dev->addr_len) inc_opt = 0; if (inc_opt) |
f997c55c1 ipv6: introduce n... |
497 498 |
optlen += ndisc_opt_addr_space(dev, NDISC_NEIGHBOUR_ADVERTISEMENT); |
e1ec7842d [IPV6] NDISC: Uni... |
499 |
|
1cb3fe513 ndisc: Break down... |
500 |
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
b44b5f4ae ndisc: Break down... |
501 502 |
if (!skb) return; |
1cb3fe513 ndisc: Break down... |
503 504 505 506 507 508 509 510 511 512 513 514 515 |
msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); *msg = (struct nd_msg) { .icmph = { .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, .icmp6_router = router, .icmp6_solicited = solicited, .icmp6_override = override, }, .target = *solicited_addr, }; if (inc_opt) ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, |
f997c55c1 ipv6: introduce n... |
516 517 |
dev->dev_addr, NDISC_NEIGHBOUR_ADVERTISEMENT); |
1cb3fe513 ndisc: Break down... |
518 |
|
b44b5f4ae ndisc: Break down... |
519 |
ndisc_send_skb(skb, daddr, src_addr); |
e1ec7842d [IPV6] NDISC: Uni... |
520 |
} |
f47b94646 ipv6: Send unsoli... |
521 522 523 524 |
static void ndisc_send_unsol_na(struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; |
f47b94646 ipv6: Send unsoli... |
525 526 527 528 529 530 531 |
idev = in6_dev_get(dev); if (!idev) return; read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { |
38cf595b1 ipv6: remove unus... |
532 |
ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr, |
f47b94646 ipv6: Send unsoli... |
533 534 535 536 537 538 539 540 |
/*router=*/ !!idev->cnf.forwarding, /*solicited=*/ false, /*override=*/ true, /*inc_opt=*/ true); } read_unlock_bh(&idev->lock); in6_dev_put(idev); } |
38cf595b1 ipv6: remove unus... |
541 |
void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, |
adc176c54 ipv6 addrconf: Im... |
542 543 |
const struct in6_addr *daddr, const struct in6_addr *saddr, u64 nonce) |
1da177e4c Linux-2.6.12-rc2 |
544 |
{ |
b44b5f4ae ndisc: Break down... |
545 |
struct sk_buff *skb; |
1da177e4c Linux-2.6.12-rc2 |
546 |
struct in6_addr addr_buf; |
1cb3fe513 ndisc: Break down... |
547 548 549 |
int inc_opt = dev->addr_len; int optlen = 0; struct nd_msg *msg; |
1da177e4c Linux-2.6.12-rc2 |
550 |
|
63159f29b ipv6: coding styl... |
551 |
if (!saddr) { |
95c385b4d [IPV6] ADDRCONF: ... |
552 553 |
if (ipv6_get_lladdr(dev, &addr_buf, (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) |
1da177e4c Linux-2.6.12-rc2 |
554 555 556 |
return; saddr = &addr_buf; } |
1cb3fe513 ndisc: Break down... |
557 |
if (ipv6_addr_any(saddr)) |
f2f79cca1 ndisc: bool initi... |
558 |
inc_opt = false; |
1cb3fe513 ndisc: Break down... |
559 |
if (inc_opt) |
f997c55c1 ipv6: introduce n... |
560 561 |
optlen += ndisc_opt_addr_space(dev, NDISC_NEIGHBOUR_SOLICITATION); |
adc176c54 ipv6 addrconf: Im... |
562 563 |
if (nonce != 0) optlen += 8; |
1cb3fe513 ndisc: Break down... |
564 565 |
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
b44b5f4ae ndisc: Break down... |
566 567 |
if (!skb) return; |
1cb3fe513 ndisc: Break down... |
568 569 570 571 572 573 574 575 576 577 |
msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); *msg = (struct nd_msg) { .icmph = { .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, }, .target = *solicit, }; if (inc_opt) ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, |
f997c55c1 ipv6: introduce n... |
578 579 |
dev->dev_addr, NDISC_NEIGHBOUR_SOLICITATION); |
adc176c54 ipv6 addrconf: Im... |
580 581 582 583 584 585 586 |
if (nonce != 0) { u8 *opt = skb_put(skb, 8); opt[0] = ND_OPT_NONCE; opt[1] = 8 >> 3; memcpy(opt + 2, &nonce, 6); } |
1cb3fe513 ndisc: Break down... |
587 |
|
b44b5f4ae ndisc: Break down... |
588 |
ndisc_send_skb(skb, daddr, saddr); |
1da177e4c Linux-2.6.12-rc2 |
589 |
} |
9acd9f3ae [IPV6]: Make addr... |
590 591 |
void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr) |
1da177e4c Linux-2.6.12-rc2 |
592 |
{ |
b44b5f4ae ndisc: Break down... |
593 |
struct sk_buff *skb; |
1cb3fe513 ndisc: Break down... |
594 |
struct rs_msg *msg; |
95c385b4d [IPV6] ADDRCONF: ... |
595 |
int send_sllao = dev->addr_len; |
1cb3fe513 ndisc: Break down... |
596 |
int optlen = 0; |
95c385b4d [IPV6] ADDRCONF: ... |
597 598 599 600 601 602 603 604 |
#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 ... |
605 |
* suppress the inclusion of the sllao. |
95c385b4d [IPV6] ADDRCONF: ... |
606 607 |
*/ if (send_sllao) { |
c346dca10 [NET] NETNS: Omit... |
608 |
struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, |
1cab3da6b [NETNS][IPV6]: in... |
609 |
dev, 1); |
95c385b4d [IPV6] ADDRCONF: ... |
610 611 |
if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { |
ca0435693 [IPV6] ADDRCONF: ... |
612 |
send_sllao = 0; |
95c385b4d [IPV6] ADDRCONF: ... |
613 |
} |
ca0435693 [IPV6] ADDRCONF: ... |
614 |
in6_ifa_put(ifp); |
95c385b4d [IPV6] ADDRCONF: ... |
615 616 617 618 619 |
} else { send_sllao = 0; } } #endif |
1cb3fe513 ndisc: Break down... |
620 |
if (send_sllao) |
f997c55c1 ipv6: introduce n... |
621 |
optlen += ndisc_opt_addr_space(dev, NDISC_ROUTER_SOLICITATION); |
1cb3fe513 ndisc: Break down... |
622 623 |
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
b44b5f4ae ndisc: Break down... |
624 625 |
if (!skb) return; |
1cb3fe513 ndisc: Break down... |
626 627 628 629 630 631 632 633 634 |
msg = (struct rs_msg *)skb_put(skb, sizeof(*msg)); *msg = (struct rs_msg) { .icmph = { .icmp6_type = NDISC_ROUTER_SOLICITATION, }, }; if (send_sllao) ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, |
f997c55c1 ipv6: introduce n... |
635 636 |
dev->dev_addr, NDISC_ROUTER_SOLICITATION); |
1cb3fe513 ndisc: Break down... |
637 |
|
b44b5f4ae ndisc: Break down... |
638 |
ndisc_send_skb(skb, daddr, saddr); |
1da177e4c Linux-2.6.12-rc2 |
639 |
} |
1ab1457c4 [NET] IPV6: Fix w... |
640 |
|
1da177e4c Linux-2.6.12-rc2 |
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
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); |
c58da4c65 net: ipv6: allow ... |
661 662 663 |
if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1, IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) |
0660e03f6 [SK_BUFF]: Introd... |
664 |
saddr = &ipv6_hdr(skb)->saddr; |
e5d08d718 ipv6: coding styl... |
665 666 |
probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); if (probes < 0) { |
1da177e4c Linux-2.6.12-rc2 |
667 |
if (!(neigh->nud_state & NUD_VALID)) { |
675418d51 net: ipv6: ndisc:... |
668 669 670 671 |
ND_PRINTK(1, dbg, "%s: trying to ucast probe in NUD_INVALID: %pI6 ", __func__, target); |
1da177e4c Linux-2.6.12-rc2 |
672 |
} |
adc176c54 ipv6 addrconf: Im... |
673 |
ndisc_send_ns(dev, target, target, saddr, 0); |
1f9248e56 neigh: convert pa... |
674 |
} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { |
1da177e4c Linux-2.6.12-rc2 |
675 |
neigh_app_ns(neigh); |
1da177e4c Linux-2.6.12-rc2 |
676 677 |
} else { addrconf_addr_solict_mult(target, &mcaddr); |
adc176c54 ipv6 addrconf: Im... |
678 |
ndisc_send_ns(dev, target, &mcaddr, saddr, 0); |
1da177e4c Linux-2.6.12-rc2 |
679 680 |
} } |
0736ffc04 [IPV6] NEIGH: Opt... |
681 682 |
static int pndisc_is_router(const void *pkey, struct net_device *dev) |
fa86d322d [NEIGH]: Fix race... |
683 684 |
{ struct pneigh_entry *n; |
0736ffc04 [IPV6] NEIGH: Opt... |
685 |
int ret = -1; |
fa86d322d [NEIGH]: Fix race... |
686 687 |
read_lock_bh(&nd_tbl.lock); |
0736ffc04 [IPV6] NEIGH: Opt... |
688 689 690 |
n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); if (n) ret = !!(n->flags & NTF_ROUTER); |
fa86d322d [NEIGH]: Fix race... |
691 |
read_unlock_bh(&nd_tbl.lock); |
0736ffc04 [IPV6] NEIGH: Opt... |
692 |
return ret; |
fa86d322d [NEIGH]: Fix race... |
693 |
} |
f997c55c1 ipv6: introduce n... |
694 695 696 697 698 699 700 701 |
void ndisc_update(const struct net_device *dev, struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, struct ndisc_options *ndopts) { neigh_update(neigh, lladdr, new, flags); /* report ndisc ops about neighbour update */ ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts); } |
1da177e4c Linux-2.6.12-rc2 |
702 703 |
static void ndisc_recv_ns(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
704 |
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
b71d1d426 inet: constify ip... |
705 706 |
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
707 |
u8 *lladdr = NULL; |
29a3cad5c ipv6: Correct com... |
708 |
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + |
27a884dc3 [SK_BUFF]: Conver... |
709 |
offsetof(struct nd_msg, opt)); |
1da177e4c Linux-2.6.12-rc2 |
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); |
a50feda54 ipv6: bool/const ... |
716 |
bool inc; |
0736ffc04 [IPV6] NEIGH: Opt... |
717 |
int is_router = -1; |
adc176c54 ipv6 addrconf: Im... |
718 |
u64 nonce = 0; |
1da177e4c Linux-2.6.12-rc2 |
719 |
|
115b0aa6b ndisc: Check NS m... |
720 721 722 723 724 |
if (skb->len < sizeof(struct nd_msg)) { ND_PRINTK(2, warn, "NS: packet too short "); return; } |
1da177e4c Linux-2.6.12-rc2 |
725 |
if (ipv6_addr_is_multicast(&msg->target)) { |
675418d51 net: ipv6: ndisc:... |
726 727 |
ND_PRINTK(2, warn, "NS: multicast target address "); |
1da177e4c Linux-2.6.12-rc2 |
728 729 730 731 732 733 734 |
return; } /* * RFC2461 7.1.1: * DAD has to be destined for solicited node multicast address. */ |
ca97a644d ipv6: Introduce i... |
735 |
if (dad && !ipv6_addr_is_solict_mult(daddr)) { |
675418d51 net: ipv6: ndisc:... |
736 737 |
ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination) "); |
1da177e4c Linux-2.6.12-rc2 |
738 739 |
return; } |
f997c55c1 ipv6: introduce n... |
740 |
if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { |
675418d51 net: ipv6: ndisc:... |
741 742 |
ND_PRINTK(2, warn, "NS: invalid ND options "); |
1da177e4c Linux-2.6.12-rc2 |
743 744 745 746 747 748 |
return; } if (ndopts.nd_opts_src_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev); if (!lladdr) { |
675418d51 net: ipv6: ndisc:... |
749 750 751 |
ND_PRINTK(2, warn, "NS: invalid link-layer address length "); |
1da177e4c Linux-2.6.12-rc2 |
752 753 754 755 |
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) { |
675418d51 net: ipv6: ndisc:... |
761 762 763 |
ND_PRINTK(2, warn, "NS: bad DAD packet (link-layer address option) "); |
1da177e4c Linux-2.6.12-rc2 |
764 765 766 |
return; } } |
adc176c54 ipv6 addrconf: Im... |
767 768 |
if (ndopts.nd_opts_nonce) memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6); |
1da177e4c Linux-2.6.12-rc2 |
769 770 |
inc = ipv6_addr_is_multicast(daddr); |
c346dca10 [NET] NETNS: Omit... |
771 |
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
a18bc6959 [NETNS][IPV6] ndi... |
772 |
if (ifp) { |
ca254490c net: Add VRF supp... |
773 |
have_ifp: |
95c385b4d [IPV6] ADDRCONF: ... |
774 775 |
if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { if (dad) { |
adc176c54 ipv6 addrconf: Im... |
776 777 778 779 780 781 782 783 784 785 |
if (nonce != 0 && ifp->dad_nonce == nonce) { u8 *np = (u8 *)&nonce; /* Matching nonce if looped back */ ND_PRINTK(2, notice, "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored ", ifp->idev->dev->name, &ifp->addr, np); goto out; } |
95c385b4d [IPV6] ADDRCONF: ... |
786 787 788 789 790 791 |
/* * We are colliding with another node * who is doing DAD * so fail our DAD process */ addrconf_dad_failure(ifp); |
9e3be4b34 [IPV6]: Freeing a... |
792 |
return; |
95c385b4d [IPV6] ADDRCONF: ... |
793 794 795 796 797 798 799 800 |
} 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 |
801 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
802 |
} |
1da177e4c Linux-2.6.12-rc2 |
803 804 805 806 |
} idev = ifp->idev; } else { |
53b7997fd ipv6 netns: Make ... |
807 |
struct net *net = dev_net(dev); |
ca254490c net: Add VRF supp... |
808 809 810 811 812 813 814 815 816 817 818 |
/* perhaps an address on the master device */ if (netif_is_l3_slave(dev)) { struct net_device *mdev; mdev = netdev_master_upper_dev_get_rcu(dev); if (mdev) { ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1); if (ifp) goto have_ifp; } } |
1da177e4c Linux-2.6.12-rc2 |
819 820 821 822 823 |
idev = in6_dev_get(dev); if (!idev) { /* XXX: count this drop? */ return; } |
53b7997fd ipv6 netns: Make ... |
824 |
if (ipv6_chk_acast_addr(net, dev, &msg->target) || |
1ab1457c4 [NET] IPV6: Fix w... |
825 |
(idev->cnf.forwarding && |
53b7997fd ipv6 netns: Make ... |
826 |
(net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && |
0736ffc04 [IPV6] NEIGH: Opt... |
827 |
(is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { |
a61bbcf28 [NET]: Store skb-... |
828 |
if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
1da177e4c Linux-2.6.12-rc2 |
829 |
skb->pkt_type != PACKET_HOST && |
f2f79cca1 ndisc: bool initi... |
830 |
inc && |
1f9248e56 neigh: convert pa... |
831 |
NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) { |
1da177e4c Linux-2.6.12-rc2 |
832 833 |
/* * for anycast or proxy, |
1ab1457c4 [NET] IPV6: Fix w... |
834 835 |
* sender should delay its response * by a random time between 0 and |
1da177e4c Linux-2.6.12-rc2 |
836 837 838 839 840 841 842 843 844 845 846 |
* 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... |
847 |
if (is_router < 0) |
fb568637e ndisc: Make sever... |
848 |
is_router = idev->cnf.forwarding; |
62dd93181 [IPV6] NDISC: Set... |
849 |
|
1da177e4c Linux-2.6.12-rc2 |
850 |
if (dad) { |
38cf595b1 ipv6: remove unus... |
851 |
ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target, |
fb568637e ndisc: Make sever... |
852 |
!!is_router, false, (ifp != NULL), true); |
1da177e4c Linux-2.6.12-rc2 |
853 854 855 856 857 858 859 |
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... |
860 |
/* |
1da177e4c Linux-2.6.12-rc2 |
861 862 863 864 865 866 |
* update / create cache entry * for the source address */ neigh = __neigh_lookup(&nd_tbl, saddr, dev, !inc || lladdr || !dev->addr_len); if (neigh) |
f997c55c1 ipv6: introduce n... |
867 |
ndisc_update(dev, neigh, lladdr, NUD_STALE, |
1da177e4c Linux-2.6.12-rc2 |
868 |
NEIGH_UPDATE_F_WEAK_OVERRIDE| |
f997c55c1 ipv6: introduce n... |
869 870 |
NEIGH_UPDATE_F_OVERRIDE, NDISC_NEIGHBOUR_SOLICITATION, &ndopts); |
3b04ddde0 [NET]: Move hardw... |
871 |
if (neigh || !dev->header_ops) { |
38cf595b1 ipv6: remove unus... |
872 |
ndisc_send_na(dev, saddr, &msg->target, !!is_router, |
fb568637e ndisc: Make sever... |
873 |
true, (ifp != NULL && inc), inc); |
1da177e4c Linux-2.6.12-rc2 |
874 875 876 877 878 879 880 881 882 |
if (neigh) neigh_release(neigh); } out: if (ifp) in6_ifa_put(ifp); else in6_dev_put(idev); |
1da177e4c Linux-2.6.12-rc2 |
883 884 885 886 |
} static void ndisc_recv_na(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
887 |
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
be7a010d6 ipv6: update Dest... |
888 |
struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
b71d1d426 inet: constify ip... |
889 |
const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
1da177e4c Linux-2.6.12-rc2 |
890 |
u8 *lladdr = NULL; |
29a3cad5c ipv6: Correct com... |
891 |
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + |
27a884dc3 [SK_BUFF]: Conver... |
892 |
offsetof(struct nd_msg, opt)); |
1da177e4c Linux-2.6.12-rc2 |
893 894 |
struct ndisc_options ndopts; struct net_device *dev = skb->dev; |
7a02bf892 ipv6: add option ... |
895 |
struct inet6_dev *idev = __in6_dev_get(dev); |
1da177e4c Linux-2.6.12-rc2 |
896 897 898 899 |
struct inet6_ifaddr *ifp; struct neighbour *neigh; if (skb->len < sizeof(struct nd_msg)) { |
675418d51 net: ipv6: ndisc:... |
900 901 |
ND_PRINTK(2, warn, "NA: packet too short "); |
1da177e4c Linux-2.6.12-rc2 |
902 903 904 905 |
return; } if (ipv6_addr_is_multicast(&msg->target)) { |
675418d51 net: ipv6: ndisc:... |
906 907 |
ND_PRINTK(2, warn, "NA: target address is multicast "); |
1da177e4c Linux-2.6.12-rc2 |
908 909 910 911 912 |
return; } if (ipv6_addr_is_multicast(daddr) && msg->icmph.icmp6_solicited) { |
675418d51 net: ipv6: ndisc:... |
913 914 |
ND_PRINTK(2, warn, "NA: solicited NA is multicasted "); |
1da177e4c Linux-2.6.12-rc2 |
915 916 |
return; } |
1ab1457c4 [NET] IPV6: Fix w... |
917 |
|
7a02bf892 ipv6: add option ... |
918 919 920 921 922 923 924 |
/* For some 802.11 wireless deployments (and possibly other networks), * there will be a NA proxy and unsolicitd packets are attacks * and thus should not be accepted. */ if (!msg->icmph.icmp6_solicited && idev && idev->cnf.drop_unsolicited_na) return; |
f997c55c1 ipv6: introduce n... |
925 |
if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { |
675418d51 net: ipv6: ndisc:... |
926 927 |
ND_PRINTK(2, warn, "NS: invalid ND option "); |
1da177e4c Linux-2.6.12-rc2 |
928 929 930 931 932 |
return; } if (ndopts.nd_opts_tgt_lladdr) { lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev); if (!lladdr) { |
675418d51 net: ipv6: ndisc:... |
933 934 935 |
ND_PRINTK(2, warn, "NA: invalid link-layer address length "); |
1da177e4c Linux-2.6.12-rc2 |
936 937 938 |
return; } } |
c346dca10 [NET] NETNS: Omit... |
939 |
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
a18bc6959 [NETNS][IPV6] ndi... |
940 |
if (ifp) { |
bd015928b ipv6: ignore loop... |
941 942 943 944 |
if (skb->pkt_type != PACKET_LOOPBACK && (ifp->flags & IFA_F_TENTATIVE)) { addrconf_dad_failure(ifp); return; |
1da177e4c Linux-2.6.12-rc2 |
945 946 947 948 949 |
} /* 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... |
950 951 952 953 |
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 |
954 |
*/ |
24fc7b86d ipv6: silence log... |
955 |
if (skb->pkt_type != PACKET_LOOPBACK) |
675418d51 net: ipv6: ndisc:... |
956 957 958 959 |
ND_PRINTK(1, warn, "NA: someone advertises our address %pI6 on %s! ", &ifp->addr, ifp->idev->dev->name); |
1da177e4c Linux-2.6.12-rc2 |
960 961 962 963 964 965 966 |
in6_ifa_put(ifp); return; } neigh = neigh_lookup(&nd_tbl, &msg->target, dev); if (neigh) { u8 old_flags = neigh->flags; |
53b7997fd ipv6 netns: Make ... |
967 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
968 969 970 |
if (neigh->nud_state & NUD_FAILED) goto out; |
5f3e6e9e1 [IPV6] NDISC: Avo... |
971 972 973 974 975 976 |
/* * 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 ... |
977 978 |
net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { |
b20b6d972 ndisc: fix a typo... |
979 |
/* XXX: idev->cnf.proxy_ndp */ |
5f3e6e9e1 [IPV6] NDISC: Avo... |
980 |
goto out; |
fbea49e1e [IPV6] NDISC: Add... |
981 |
} |
5f3e6e9e1 [IPV6] NDISC: Avo... |
982 |
|
f997c55c1 ipv6: introduce n... |
983 |
ndisc_update(dev, neigh, lladdr, |
1da177e4c Linux-2.6.12-rc2 |
984 985 986 987 |
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| |
f997c55c1 ipv6: introduce n... |
988 989 |
(msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0), NDISC_NEIGHBOUR_ADVERTISEMENT, &ndopts); |
1da177e4c Linux-2.6.12-rc2 |
990 991 992 993 994 |
if ((old_flags & ~neigh->flags) & NTF_ROUTER) { /* * Change: router to host */ |
be7a010d6 ipv6: update Dest... |
995 |
rt6_clean_tohost(dev_net(dev), saddr); |
1da177e4c Linux-2.6.12-rc2 |
996 997 998 999 1000 1001 1002 1003 1004 |
} out: neigh_release(neigh); } } static void ndisc_recv_rs(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
1005 |
struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
1006 1007 1008 |
unsigned long ndoptlen = skb->len - sizeof(*rs_msg); struct neighbour *neigh; struct inet6_dev *idev; |
b71d1d426 inet: constify ip... |
1009 |
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1da177e4c Linux-2.6.12-rc2 |
1010 1011 1012 1013 1014 |
struct ndisc_options ndopts; u8 *lladdr = NULL; if (skb->len < sizeof(*rs_msg)) return; |
cfdf76474 ipv6: some RCU co... |
1015 |
idev = __in6_dev_get(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1016 |
if (!idev) { |
675418d51 net: ipv6: ndisc:... |
1017 1018 |
ND_PRINTK(1, err, "RS: can't find in6 device "); |
1da177e4c Linux-2.6.12-rc2 |
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 |
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 */ |
f997c55c1 ipv6: introduce n... |
1034 |
if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts)) { |
675418d51 net: ipv6: ndisc:... |
1035 1036 |
ND_PRINTK(2, notice, "NS: invalid ND option, ignored "); |
1da177e4c Linux-2.6.12-rc2 |
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
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) { |
f997c55c1 ipv6: introduce n... |
1049 |
ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, |
1da177e4c Linux-2.6.12-rc2 |
1050 1051 |
NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| |
f997c55c1 ipv6: introduce n... |
1052 1053 |
NEIGH_UPDATE_F_OVERRIDE_ISROUTER, NDISC_ROUTER_SOLICITATION, &ndopts); |
1da177e4c Linux-2.6.12-rc2 |
1054 1055 1056 |
neigh_release(neigh); } out: |
cfdf76474 ipv6: some RCU co... |
1057 |
return; |
1da177e4c Linux-2.6.12-rc2 |
1058 |
} |
31910575a [IPv6]: Export us... |
1059 1060 1061 1062 1063 1064 |
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... |
1065 |
struct net *net = dev_net(ra->dev); |
31910575a [IPv6]: Export us... |
1066 1067 1068 1069 1070 1071 |
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); |
63159f29b ipv6: coding styl... |
1072 |
if (!skb) { |
31910575a [IPv6]: Export us... |
1073 1074 1075 1076 1077 |
err = -ENOBUFS; goto errout; } nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0); |
63159f29b ipv6: coding styl... |
1078 |
if (!nlh) { |
31910575a [IPv6]: Export us... |
1079 1080 1081 1082 1083 |
goto nla_put_failure; } ndmsg = nlmsg_data(nlh); ndmsg->nduseropt_family = AF_INET6; |
dbb2ed248 [IPV6]: Add ifind... |
1084 |
ndmsg->nduseropt_ifindex = ra->dev->ifindex; |
31910575a [IPv6]: Export us... |
1085 1086 1087 1088 1089 |
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); |
930345ea6 netlink: implemen... |
1090 |
if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr)) |
c78679e8f ipv6: Stop using ... |
1091 |
goto nla_put_failure; |
31910575a [IPv6]: Export us... |
1092 |
nlmsg_end(skb, nlh); |
1ce85fe40 netlink: change n... |
1093 |
rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); |
31910575a [IPv6]: Export us... |
1094 1095 1096 1097 1098 1099 |
return; nla_put_failure: nlmsg_free(skb); err = -EMSGSIZE; errout: |
a18bc6959 [NETNS][IPV6] ndi... |
1100 |
rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
31910575a [IPv6]: Export us... |
1101 |
} |
1da177e4c Linux-2.6.12-rc2 |
1102 1103 |
static void ndisc_router_discovery(struct sk_buff *skb) { |
9c70220b7 [SK_BUFF]: Introd... |
1104 |
struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
1105 1106 |
struct neighbour *neigh = NULL; struct inet6_dev *in6_dev; |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1107 |
struct rt6_info *rt = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1108 1109 1110 |
int lifetime; struct ndisc_options ndopts; int optlen; |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1111 |
unsigned int pref = 0; |
a394eef56 ipv6: send NEWLIN... |
1112 |
__u32 old_if_flags; |
2053aeb69 ipv6: send only o... |
1113 |
bool send_ifinfo_notify = false; |
1da177e4c Linux-2.6.12-rc2 |
1114 |
|
67ba4152e ipv6: White-space... |
1115 |
__u8 *opt = (__u8 *)(ra_msg + 1); |
1da177e4c Linux-2.6.12-rc2 |
1116 |
|
29a3cad5c ipv6: Correct com... |
1117 1118 |
optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - sizeof(struct ra_msg); |
1da177e4c Linux-2.6.12-rc2 |
1119 |
|
f2a762d8a ipv6: Add more de... |
1120 1121 1122 1123 |
ND_PRINTK(2, info, "RA: %s, dev: %s ", __func__, skb->dev->name); |
0660e03f6 [SK_BUFF]: Introd... |
1124 |
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
675418d51 net: ipv6: ndisc:... |
1125 1126 |
ND_PRINTK(2, warn, "RA: source address is not link-local "); |
1da177e4c Linux-2.6.12-rc2 |
1127 1128 1129 |
return; } if (optlen < 0) { |
675418d51 net: ipv6: ndisc:... |
1130 1131 |
ND_PRINTK(2, warn, "RA: packet too short "); |
1da177e4c Linux-2.6.12-rc2 |
1132 1133 |
return; } |
de357cc01 [IPV6] NDISC: Don... |
1134 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1135 |
if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { |
675418d51 net: ipv6: ndisc:... |
1136 1137 |
ND_PRINTK(2, warn, "RA: from host or unauthorized router "); |
fadf6bf06 [IPV6] SIT: Add P... |
1138 1139 |
return; } |
de357cc01 [IPV6] NDISC: Don... |
1140 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1141 |
|
1da177e4c Linux-2.6.12-rc2 |
1142 1143 1144 |
/* * set the RA_RECV flag in the interface */ |
cfdf76474 ipv6: some RCU co... |
1145 |
in6_dev = __in6_dev_get(skb->dev); |
63159f29b ipv6: coding styl... |
1146 |
if (!in6_dev) { |
675418d51 net: ipv6: ndisc:... |
1147 1148 1149 |
ND_PRINTK(0, err, "RA: can't find inet6 device for %s ", skb->dev->name); |
1da177e4c Linux-2.6.12-rc2 |
1150 1151 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
1152 |
|
f997c55c1 ipv6: introduce n... |
1153 |
if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts)) { |
675418d51 net: ipv6: ndisc:... |
1154 1155 |
ND_PRINTK(2, warn, "RA: invalid ND options "); |
1da177e4c Linux-2.6.12-rc2 |
1156 1157 |
return; } |
f2a762d8a ipv6: Add more de... |
1158 1159 1160 1161 1162 |
if (!ipv6_accept_ra(in6_dev)) { ND_PRINTK(2, info, "RA: %s, did not accept ra for dev: %s ", __func__, skb->dev->name); |
31ce8c71a ipv6: Update Neig... |
1163 |
goto skip_linkparms; |
f2a762d8a ipv6: Add more de... |
1164 |
} |
31ce8c71a ipv6: Update Neig... |
1165 |
|
de357cc01 [IPV6] NDISC: Don... |
1166 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1167 |
/* skip link-specific parameters from interior routers */ |
f2a762d8a ipv6: Add more de... |
1168 1169 1170 1171 1172 |
if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { ND_PRINTK(2, info, "RA: %s, nodetype is NODEFAULT, dev: %s ", __func__, skb->dev->name); |
fadf6bf06 [IPV6] SIT: Add P... |
1173 |
goto skip_linkparms; |
f2a762d8a ipv6: Add more de... |
1174 |
} |
de357cc01 [IPV6] NDISC: Don... |
1175 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1176 |
|
1da177e4c Linux-2.6.12-rc2 |
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
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 */ |
a394eef56 ipv6: send NEWLIN... |
1189 |
old_if_flags = in6_dev->if_flags; |
1da177e4c Linux-2.6.12-rc2 |
1190 1191 1192 1193 1194 1195 |
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); |
a394eef56 ipv6: send NEWLIN... |
1196 |
if (old_if_flags != in6_dev->if_flags) |
2053aeb69 ipv6: send only o... |
1197 |
send_ifinfo_notify = true; |
a394eef56 ipv6: send NEWLIN... |
1198 |
|
f2a762d8a ipv6: Add more de... |
1199 1200 1201 1202 1203 |
if (!in6_dev->cnf.accept_ra_defrtr) { ND_PRINTK(2, info, "RA: %s, defrtr is false for dev: %s ", __func__, skb->dev->name); |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1204 |
goto skip_defrtr; |
f2a762d8a ipv6: Add more de... |
1205 |
} |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1206 |
|
d93331965 ipv6: Allow accep... |
1207 1208 1209 |
/* Do not accept RA with source-addr found on local machine unless * accept_ra_from_local is set to true. */ |
b64288171 ipv6: fix the che... |
1210 1211 |
if (!in6_dev->cnf.accept_ra_from_local && ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, |
c1a9a291c ipv6: honor ifind... |
1212 |
in6_dev->dev, 0)) { |
f2a762d8a ipv6: Add more de... |
1213 |
ND_PRINTK(2, info, |
d93331965 ipv6: Allow accep... |
1214 1215 1216 |
"RA from local address detected on dev: %s: default router ignored ", skb->dev->name); |
9f56220fa ipv6: Do not use ... |
1217 |
goto skip_defrtr; |
f2a762d8a ipv6: Add more de... |
1218 |
} |
9f56220fa ipv6: Do not use ... |
1219 |
|
1da177e4c Linux-2.6.12-rc2 |
1220 |
lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1221 1222 1223 |
#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... |
1224 |
if (pref == ICMPV6_ROUTER_PREF_INVALID || |
6d5b78cdd [IPV6] NDISC: Fix... |
1225 |
!in6_dev->cnf.accept_ra_rtr_pref) |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1226 1227 |
pref = ICMPV6_ROUTER_PREF_MEDIUM; #endif |
0660e03f6 [SK_BUFF]: Introd... |
1228 |
rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
1229 |
|
eb857186e ipv6: ndisc: Conv... |
1230 1231 1232 |
if (rt) { neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); if (!neigh) { |
675418d51 net: ipv6: ndisc:... |
1233 1234 1235 1236 |
ND_PRINTK(0, err, "RA: %s got default router without neighbour ", __func__); |
94e187c01 ipv6: introduce i... |
1237 |
ip6_rt_put(rt); |
eb857186e ipv6: ndisc: Conv... |
1238 1239 1240 |
return; } } |
1da177e4c Linux-2.6.12-rc2 |
1241 |
if (rt && lifetime == 0) { |
e0a1ad73d [IPv6] route: Sim... |
1242 |
ip6_del_rt(rt); |
1da177e4c Linux-2.6.12-rc2 |
1243 1244 |
rt = NULL; } |
f2a762d8a ipv6: Add more de... |
1245 1246 1247 |
ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s ", rt, lifetime, skb->dev->name); |
63159f29b ipv6: coding styl... |
1248 |
if (!rt && lifetime) { |
f2a762d8a ipv6: Add more de... |
1249 1250 |
ND_PRINTK(3, info, "RA: adding default router "); |
1da177e4c Linux-2.6.12-rc2 |
1251 |
|
0660e03f6 [SK_BUFF]: Introd... |
1252 |
rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); |
63159f29b ipv6: coding styl... |
1253 |
if (!rt) { |
675418d51 net: ipv6: ndisc:... |
1254 1255 1256 1257 |
ND_PRINTK(0, err, "RA: %s failed to add default route ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
1258 1259 |
return; } |
eb857186e ipv6: ndisc: Conv... |
1260 |
neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); |
63159f29b ipv6: coding styl... |
1261 |
if (!neigh) { |
675418d51 net: ipv6: ndisc:... |
1262 1263 1264 1265 |
ND_PRINTK(0, err, "RA: %s got default router without neighbour ", __func__); |
94e187c01 ipv6: introduce i... |
1266 |
ip6_rt_put(rt); |
1da177e4c Linux-2.6.12-rc2 |
1267 1268 1269 |
return; } neigh->flags |= NTF_ROUTER; |
ebacaaa0f [IPV6]: ROUTE: Ad... |
1270 |
} else if (rt) { |
22441cfa0 IPV6: Fix default... |
1271 |
rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); |
1da177e4c Linux-2.6.12-rc2 |
1272 1273 1274 |
} if (rt) |
1716a9610 ipv6: fix problem... |
1275 |
rt6_set_expires(rt, jiffies + (HZ * lifetime)); |
8013d1d7e net/ipv6: add sys... |
1276 1277 1278 |
if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && ra_msg->icmph.icmp6_hop_limit) { if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { |
6fd99094d ipv6: Don't reduc... |
1279 |
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; |
8013d1d7e net/ipv6: add sys... |
1280 1281 1282 |
if (rt) dst_metric_set(&rt->dst, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit); |
6fd99094d ipv6: Don't reduc... |
1283 |
} else { |
8013d1d7e net/ipv6: add sys... |
1284 1285 |
ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum "); |
6fd99094d ipv6: Don't reduc... |
1286 |
} |
1da177e4c Linux-2.6.12-rc2 |
1287 |
} |
65f5c7c11 [IPV6]: ROUTE: Ad... |
1288 |
skip_defrtr: |
1da177e4c Linux-2.6.12-rc2 |
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
/* * 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; |
1f9248e56 neigh: convert pa... |
1300 |
NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime); |
1da177e4c Linux-2.6.12-rc2 |
1301 |
in6_dev->tstamp = jiffies; |
2053aeb69 ipv6: send only o... |
1302 |
send_ifinfo_notify = true; |
1da177e4c Linux-2.6.12-rc2 |
1303 1304 1305 1306 1307 1308 1309 1310 |
} 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; |
1f9248e56 neigh: convert pa... |
1311 1312 1313 1314 1315 |
if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) { NEIGH_VAR_SET(in6_dev->nd_parms, BASE_REACHABLE_TIME, rtime); NEIGH_VAR_SET(in6_dev->nd_parms, GC_STALETIME, 3 * rtime); |
1da177e4c Linux-2.6.12-rc2 |
1316 1317 |
in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); in6_dev->tstamp = jiffies; |
2053aeb69 ipv6: send only o... |
1318 |
send_ifinfo_notify = true; |
1da177e4c Linux-2.6.12-rc2 |
1319 1320 1321 |
} } } |
2053aeb69 ipv6: send only o... |
1322 1323 1324 1325 1326 |
/* * Send a notify if RA changed managed/otherconf flags or timer settings */ if (send_ifinfo_notify) inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); |
fadf6bf06 [IPV6] SIT: Add P... |
1327 |
skip_linkparms: |
1da177e4c Linux-2.6.12-rc2 |
1328 1329 1330 1331 1332 |
/* * Process options. */ if (!neigh) |
0660e03f6 [SK_BUFF]: Introd... |
1333 |
neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr, |
1da177e4c Linux-2.6.12-rc2 |
1334 1335 1336 1337 1338 1339 1340 |
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) { |
675418d51 net: ipv6: ndisc:... |
1341 1342 1343 |
ND_PRINTK(2, warn, "RA: invalid link-layer address length "); |
1da177e4c Linux-2.6.12-rc2 |
1344 1345 1346 |
goto out; } } |
f997c55c1 ipv6: introduce n... |
1347 |
ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, |
1da177e4c Linux-2.6.12-rc2 |
1348 1349 1350 |
NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE_ISROUTER| |
f997c55c1 ipv6: introduce n... |
1351 1352 |
NEIGH_UPDATE_F_ISROUTER, NDISC_ROUTER_ADVERTISEMENT, &ndopts); |
1da177e4c Linux-2.6.12-rc2 |
1353 |
} |
f2a762d8a ipv6: Add more de... |
1354 1355 1356 1357 1358 |
if (!ipv6_accept_ra(in6_dev)) { ND_PRINTK(2, info, "RA: %s, accept_ra is false for dev: %s ", __func__, skb->dev->name); |
31ce8c71a ipv6: Update Neig... |
1359 |
goto out; |
f2a762d8a ipv6: Add more de... |
1360 |
} |
31ce8c71a ipv6: Update Neig... |
1361 |
|
70ceb4f53 [IPV6]: ROUTE: Ad... |
1362 |
#ifdef CONFIG_IPV6_ROUTE_INFO |
b64288171 ipv6: fix the che... |
1363 1364 |
if (!in6_dev->cnf.accept_ra_from_local && ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, |
c1a9a291c ipv6: honor ifind... |
1365 |
in6_dev->dev, 0)) { |
f2a762d8a ipv6: Add more de... |
1366 |
ND_PRINTK(2, info, |
d93331965 ipv6: Allow accep... |
1367 1368 1369 |
"RA from local address detected on dev: %s: router info ignored. ", skb->dev->name); |
9f56220fa ipv6: Do not use ... |
1370 |
goto skip_routeinfo; |
f2a762d8a ipv6: Add more de... |
1371 |
} |
9f56220fa ipv6: Do not use ... |
1372 |
|
09c884d4c [IPV6]: ROUTE: Ad... |
1373 |
if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1374 1375 1376 1377 |
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... |
1378 1379 1380 1381 1382 1383 |
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 |
30e56918d ipv6: judge the a... |
1384 1385 1386 |
if (ri->prefix_len == 0 && !in6_dev->cnf.accept_ra_defrtr) continue; |
6294e0007 [IPV6] NDISC: Ign... |
1387 |
if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) |
09c884d4c [IPV6]: ROUTE: Ad... |
1388 |
continue; |
67ba4152e ipv6: White-space... |
1389 |
rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, |
0660e03f6 [SK_BUFF]: Introd... |
1390 |
&ipv6_hdr(skb)->saddr); |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1391 1392 |
} } |
9f56220fa ipv6: Do not use ... |
1393 1394 |
skip_routeinfo: |
70ceb4f53 [IPV6]: ROUTE: Ad... |
1395 |
#endif |
de357cc01 [IPV6] NDISC: Don... |
1396 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1397 |
/* skip link-specific ndopts from interior routers */ |
f2a762d8a ipv6: Add more de... |
1398 1399 1400 1401 1402 |
if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { ND_PRINTK(2, info, "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s ", __func__, skb->dev->name); |
fadf6bf06 [IPV6] SIT: Add P... |
1403 |
goto out; |
f2a762d8a ipv6: Add more de... |
1404 |
} |
de357cc01 [IPV6] NDISC: Don... |
1405 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1406 |
|
c4fd30eb1 [IPV6]: ADDRCONF:... |
1407 |
if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { |
1da177e4c Linux-2.6.12-rc2 |
1408 1409 1410 1411 |
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... |
1412 1413 1414 |
addrconf_prefix_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, ndopts.nd_opts_src_lladdr != NULL); |
1da177e4c Linux-2.6.12-rc2 |
1415 1416 |
} } |
c2943f145 net: ipv6: Add sy... |
1417 |
if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) { |
e69a4adc6 [IPV6]: Misc endi... |
1418 |
__be32 n; |
1da177e4c Linux-2.6.12-rc2 |
1419 |
u32 mtu; |
67ba4152e ipv6: White-space... |
1420 |
memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); |
e69a4adc6 [IPV6]: Misc endi... |
1421 |
mtu = ntohl(n); |
1da177e4c Linux-2.6.12-rc2 |
1422 1423 |
if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { |
675418d51 net: ipv6: ndisc:... |
1424 1425 |
ND_PRINTK(2, warn, "RA: invalid mtu: %d ", mtu); |
1da177e4c Linux-2.6.12-rc2 |
1426 1427 1428 1429 |
} else if (in6_dev->cnf.mtu6 != mtu) { in6_dev->cnf.mtu6 = mtu; if (rt) |
defb3519a net: Abstract awa... |
1430 |
dst_metric_set(&rt->dst, RTAX_MTU, mtu); |
1da177e4c Linux-2.6.12-rc2 |
1431 1432 1433 1434 |
rt6_mtu_change(skb->dev, mtu); } } |
1ab1457c4 [NET] IPV6: Fix w... |
1435 |
|
31910575a [IPv6]: Export us... |
1436 |
if (ndopts.nd_useropts) { |
61cf46ad5 [IPV6] NDISC: Spa... |
1437 1438 1439 |
struct nd_opt_hdr *p; for (p = ndopts.nd_useropts; p; |
f997c55c1 ipv6: introduce n... |
1440 1441 |
p = ndisc_next_useropt(skb->dev, p, ndopts.nd_useropts_end)) { |
61cf46ad5 [IPV6] NDISC: Spa... |
1442 |
ndisc_ra_useropt(skb, p); |
31910575a [IPv6]: Export us... |
1443 1444 |
} } |
1da177e4c Linux-2.6.12-rc2 |
1445 |
if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) { |
675418d51 net: ipv6: ndisc:... |
1446 1447 |
ND_PRINTK(2, warn, "RA: invalid RA options "); |
1da177e4c Linux-2.6.12-rc2 |
1448 1449 |
} out: |
94e187c01 ipv6: introduce i... |
1450 |
ip6_rt_put(rt); |
eb857186e ipv6: ndisc: Conv... |
1451 |
if (neigh) |
1da177e4c Linux-2.6.12-rc2 |
1452 |
neigh_release(neigh); |
1da177e4c Linux-2.6.12-rc2 |
1453 1454 1455 1456 |
} static void ndisc_redirect_rcv(struct sk_buff *skb) { |
093d04d42 ipv6: Change skb-... |
1457 1458 1459 |
u8 *hdr; struct ndisc_options ndopts; struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb); |
29a3cad5c ipv6: Correct com... |
1460 |
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + |
093d04d42 ipv6: Change skb-... |
1461 |
offsetof(struct rd_msg, opt)); |
de357cc01 [IPV6] NDISC: Don... |
1462 |
#ifdef CONFIG_IPV6_NDISC_NODETYPE |
fadf6bf06 [IPV6] SIT: Add P... |
1463 1464 1465 |
switch (skb->ndisc_nodetype) { case NDISC_NODETYPE_HOST: case NDISC_NODETYPE_NODEFAULT: |
675418d51 net: ipv6: ndisc:... |
1466 1467 1468 |
ND_PRINTK(2, warn, "Redirect: from host or unauthorized router "); |
fadf6bf06 [IPV6] SIT: Add P... |
1469 1470 |
return; } |
de357cc01 [IPV6] NDISC: Don... |
1471 |
#endif |
fadf6bf06 [IPV6] SIT: Add P... |
1472 |
|
0660e03f6 [SK_BUFF]: Introd... |
1473 |
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
675418d51 net: ipv6: ndisc:... |
1474 1475 1476 |
ND_PRINTK(2, warn, "Redirect: source address is not link-local "); |
1da177e4c Linux-2.6.12-rc2 |
1477 1478 |
return; } |
f997c55c1 ipv6: introduce n... |
1479 |
if (!ndisc_parse_options(skb->dev, msg->opt, ndoptlen, &ndopts)) |
093d04d42 ipv6: Change skb-... |
1480 |
return; |
c92a59eca ipv6: handle Redi... |
1481 |
if (!ndopts.nd_opts_rh) { |
b55b76b22 ipv6:introduce fu... |
1482 1483 |
ip6_redirect_no_header(skb, dev_net(skb->dev), skb->dev->ifindex, 0); |
093d04d42 ipv6: Change skb-... |
1484 |
return; |
c92a59eca ipv6: handle Redi... |
1485 |
} |
093d04d42 ipv6: Change skb-... |
1486 1487 1488 1489 1490 |
hdr = (u8 *)ndopts.nd_opts_rh; hdr += 8; if (!pskb_pull(skb, hdr - skb_transport_header(skb))) return; |
b94f1c090 ipv6: Use icmpv6_... |
1491 |
icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); |
1da177e4c Linux-2.6.12-rc2 |
1492 |
} |
5f5a01156 ndisc: Make ndisc... |
1493 1494 1495 |
static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, struct sk_buff *orig_skb, int rd_len) |
9c86dafe9 ndisc: Introduce ... |
1496 |
{ |
5f5a01156 ndisc: Make ndisc... |
1497 |
u8 *opt = skb_put(skb, rd_len); |
9c86dafe9 ndisc: Introduce ... |
1498 1499 1500 1501 1502 1503 |
memset(opt, 0, 8); *(opt++) = ND_OPT_REDIRECT_HDR; *(opt++) = (rd_len >> 3); opt += 6; memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); |
9c86dafe9 ndisc: Introduce ... |
1504 |
} |
4991969a1 ipv6: Remove neig... |
1505 |
void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) |
1da177e4c Linux-2.6.12-rc2 |
1506 |
{ |
1762f7e88 [NETNS][IPV6] ndi... |
1507 |
struct net_device *dev = skb->dev; |
c346dca10 [NET] NETNS: Omit... |
1508 |
struct net *net = dev_net(dev); |
1762f7e88 [NETNS][IPV6] ndi... |
1509 |
struct sock *sk = net->ipv6.ndisc_sk; |
2ce135761 ndisc: Calculate ... |
1510 |
int optlen = 0; |
fbfe95a42 inet: Create and ... |
1511 |
struct inet_peer *peer; |
1da177e4c Linux-2.6.12-rc2 |
1512 |
struct sk_buff *buff; |
71bcdba06 ndisc: Use struct... |
1513 |
struct rd_msg *msg; |
1da177e4c Linux-2.6.12-rc2 |
1514 |
struct in6_addr saddr_buf; |
1da177e4c Linux-2.6.12-rc2 |
1515 1516 |
struct rt6_info *rt; struct dst_entry *dst; |
4c9483b2f ipv6: Convert to ... |
1517 |
struct flowi6 fl6; |
1da177e4c Linux-2.6.12-rc2 |
1518 |
int rd_len; |
f997c55c1 ipv6: introduce n... |
1519 1520 |
u8 ha_buf[MAX_ADDR_LEN], *ha = NULL, ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; |
1d861aa4b inet: Minimize us... |
1521 |
bool ret; |
1da177e4c Linux-2.6.12-rc2 |
1522 |
|
95c385b4d [IPV6] ADDRCONF: ... |
1523 |
if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { |
675418d51 net: ipv6: ndisc:... |
1524 1525 1526 |
ND_PRINTK(2, warn, "Redirect: no link-local address on %s ", dev->name); |
1ab1457c4 [NET] IPV6: Fix w... |
1527 1528 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
1529 |
|
0660e03f6 [SK_BUFF]: Introd... |
1530 |
if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) && |
bf0b48dfc [IPv6]: Fix ICMPv... |
1531 |
ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
675418d51 net: ipv6: ndisc:... |
1532 1533 1534 |
ND_PRINTK(2, warn, "Redirect: target address is not link-local unicast "); |
29556526b [IPV6]: fix BUG o... |
1535 1536 |
return; } |
4c9483b2f ipv6: Convert to ... |
1537 |
icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT, |
e0d56fdd7 net: l3mdev: remo... |
1538 |
&saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1da177e4c Linux-2.6.12-rc2 |
1539 |
|
4c9483b2f ipv6: Convert to ... |
1540 |
dst = ip6_route_output(net, NULL, &fl6); |
5095d64db ipv6: ip6_route_o... |
1541 1542 |
if (dst->error) { dst_release(dst); |
1da177e4c Linux-2.6.12-rc2 |
1543 |
return; |
5095d64db ipv6: ip6_route_o... |
1544 |
} |
4c9483b2f ipv6: Convert to ... |
1545 |
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
452edd598 xfrm: Return dst ... |
1546 |
if (IS_ERR(dst)) |
1da177e4c Linux-2.6.12-rc2 |
1547 |
return; |
1da177e4c Linux-2.6.12-rc2 |
1548 1549 1550 1551 |
rt = (struct rt6_info *) dst; if (rt->rt6i_flags & RTF_GATEWAY) { |
675418d51 net: ipv6: ndisc:... |
1552 1553 1554 |
ND_PRINTK(2, warn, "Redirect: destination is not a neighbour "); |
d73f08011 ipv6/ndisc: join ... |
1555 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1556 |
} |
fd0273d79 ipv6: Remove exte... |
1557 |
peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1); |
1d861aa4b inet: Minimize us... |
1558 1559 1560 1561 |
ret = inet_peer_xrlim_allow(peer, 1*HZ); if (peer) inet_putpeer(peer); if (!ret) |
d73f08011 ipv6/ndisc: join ... |
1562 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1563 1564 |
if (dev->addr_len) { |
4991969a1 ipv6: Remove neig... |
1565 1566 |
struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target); if (!neigh) { |
675418d51 net: ipv6: ndisc:... |
1567 1568 1569 |
ND_PRINTK(2, warn, "Redirect: no neigh for target address "); |
4991969a1 ipv6: Remove neig... |
1570 1571 |
goto release; } |
1da177e4c Linux-2.6.12-rc2 |
1572 1573 1574 1575 1576 |
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; |
f997c55c1 ipv6: introduce n... |
1577 1578 1579 |
optlen += ndisc_redirect_opt_addr_space(dev, neigh, ops_data_buf, &ops_data); |
1da177e4c Linux-2.6.12-rc2 |
1580 1581 |
} else read_unlock_bh(&neigh->lock); |
4991969a1 ipv6: Remove neig... |
1582 1583 |
neigh_release(neigh); |
1da177e4c Linux-2.6.12-rc2 |
1584 1585 1586 |
} rd_len = min_t(unsigned int, |
2ce135761 ndisc: Calculate ... |
1587 1588 |
IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen, skb->len + 8); |
1da177e4c Linux-2.6.12-rc2 |
1589 |
rd_len &= ~0x7; |
2ce135761 ndisc: Calculate ... |
1590 |
optlen += rd_len; |
1da177e4c Linux-2.6.12-rc2 |
1591 |
|
2ce135761 ndisc: Calculate ... |
1592 |
buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
de09334b9 ndisc: Introduce ... |
1593 |
if (!buff) |
d73f08011 ipv6/ndisc: join ... |
1594 |
goto release; |
1da177e4c Linux-2.6.12-rc2 |
1595 |
|
4d5c152e8 ndisc: Use compou... |
1596 1597 1598 1599 1600 1601 1602 1603 |
msg = (struct rd_msg *)skb_put(buff, sizeof(*msg)); *msg = (struct rd_msg) { .icmph = { .icmp6_type = NDISC_REDIRECT, }, .target = *target, .dest = ipv6_hdr(skb)->daddr, }; |
1da177e4c Linux-2.6.12-rc2 |
1604 |
|
1da177e4c Linux-2.6.12-rc2 |
1605 1606 1607 1608 1609 |
/* * include target_address option */ if (ha) |
f997c55c1 ipv6: introduce n... |
1610 |
ndisc_fill_redirect_addr_option(buff, ha, ops_data); |
1da177e4c Linux-2.6.12-rc2 |
1611 1612 1613 1614 |
/* * build redirect option and copy skb over to the new packet. */ |
9c86dafe9 ndisc: Introduce ... |
1615 |
if (rd_len) |
5f5a01156 ndisc: Make ndisc... |
1616 |
ndisc_fill_redirect_hdr_option(buff, skb, rd_len); |
1da177e4c Linux-2.6.12-rc2 |
1617 |
|
adf30907d net: skb->dst acc... |
1618 |
skb_dst_set(buff, dst); |
f4de84c64 ndisc: Use ndisc_... |
1619 |
ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); |
d73f08011 ipv6/ndisc: join ... |
1620 1621 1622 1623 |
return; release: dst_release(dst); |
1da177e4c Linux-2.6.12-rc2 |
1624 1625 1626 1627 |
} static void pndisc_redo(struct sk_buff *skb) { |
140e26fcd [IPV6]: Fix NS ha... |
1628 |
ndisc_recv_ns(skb); |
1da177e4c Linux-2.6.12-rc2 |
1629 1630 |
kfree_skb(skb); } |
b800c3b96 ipv6: drop fragme... |
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 |
static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb) { struct inet6_dev *idev = __in6_dev_get(skb->dev); if (!idev) return true; if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED && idev->cnf.suppress_frag_ndisc) { net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc. "); return true; } return false; } |
1da177e4c Linux-2.6.12-rc2 |
1645 1646 1647 |
int ndisc_rcv(struct sk_buff *skb) { struct nd_msg *msg; |
b800c3b96 ipv6: drop fragme... |
1648 1649 |
if (ndisc_suppress_frag_ndisc(skb)) return 0; |
6bce6b4e1 ndisc: Use skb_li... |
1650 |
if (skb_linearize(skb)) |
1da177e4c Linux-2.6.12-rc2 |
1651 |
return 0; |
9c70220b7 [SK_BUFF]: Introd... |
1652 |
msg = (struct nd_msg *)skb_transport_header(skb); |
1da177e4c Linux-2.6.12-rc2 |
1653 |
|
9c70220b7 [SK_BUFF]: Introd... |
1654 |
__skb_push(skb, skb->data - skb_transport_header(skb)); |
1da177e4c Linux-2.6.12-rc2 |
1655 |
|
0660e03f6 [SK_BUFF]: Introd... |
1656 |
if (ipv6_hdr(skb)->hop_limit != 255) { |
675418d51 net: ipv6: ndisc:... |
1657 1658 1659 |
ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d ", ipv6_hdr(skb)->hop_limit); |
1da177e4c Linux-2.6.12-rc2 |
1660 1661 1662 1663 |
return 0; } if (msg->icmph.icmp6_code != 0) { |
675418d51 net: ipv6: ndisc:... |
1664 1665 1666 |
ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d ", msg->icmph.icmp6_code); |
1da177e4c Linux-2.6.12-rc2 |
1667 1668 |
return 0; } |
a61bbcf28 [NET]: Store skb-... |
1669 |
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); |
1da177e4c Linux-2.6.12-rc2 |
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 |
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... |
1690 |
} |
1da177e4c Linux-2.6.12-rc2 |
1691 1692 1693 1694 1695 1696 |
return 0; } static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { |
351638e7d net: pass info st... |
1697 |
struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
c8507fb23 ipv6: flush nd ca... |
1698 |
struct netdev_notifier_change_info *change_info; |
c346dca10 [NET] NETNS: Omit... |
1699 |
struct net *net = dev_net(dev); |
5cb04436e ipv6: add knob to... |
1700 |
struct inet6_dev *idev; |
1da177e4c Linux-2.6.12-rc2 |
1701 1702 1703 1704 |
switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); |
2ac3ac8f8 ipv6: prevent fib... |
1705 |
fib6_run_gc(0, net, false); |
5cb04436e ipv6: add knob to... |
1706 1707 1708 1709 1710 1711 |
idev = in6_dev_get(dev); if (!idev) break; if (idev->cnf.ndisc_notify) ndisc_send_unsol_na(dev); in6_dev_put(idev); |
1da177e4c Linux-2.6.12-rc2 |
1712 |
break; |
c8507fb23 ipv6: flush nd ca... |
1713 1714 1715 1716 1717 |
case NETDEV_CHANGE: change_info = ptr; if (change_info->flags_changed & IFF_NOARP) neigh_changeaddr(&nd_tbl, dev); break; |
1da177e4c Linux-2.6.12-rc2 |
1718 1719 |
case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); |
2ac3ac8f8 ipv6: prevent fib... |
1720 |
fib6_run_gc(0, net, false); |
1da177e4c Linux-2.6.12-rc2 |
1721 |
break; |
f47b94646 ipv6: Send unsoli... |
1722 1723 1724 |
case NETDEV_NOTIFY_PEERS: ndisc_send_unsol_na(dev); break; |
1da177e4c Linux-2.6.12-rc2 |
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 |
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); |
f32138319 net: ipv6: Standa... |
1744 1745 |
pr_warn("process `%s' is using deprecated sysctl (%s) net.ipv6.neigh.%s.%s - use net.ipv6.neigh.%s.%s_ms instead ", |
1da177e4c Linux-2.6.12-rc2 |
1746 1747 1748 1749 1750 1751 |
warncomm, func, dev_name, ctl->procname, dev_name, ctl->procname); warned++; } } |
8d65af789 sysctl: remove "s... |
1752 |
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 |
1753 1754 1755 1756 |
{ struct net_device *dev = ctl->extra1; struct inet6_dev *idev; int ret; |
d12af679b sysctl: fix neigh... |
1757 1758 |
if ((strcmp(ctl->procname, "retrans_time") == 0) || (strcmp(ctl->procname, "base_reachable_time") == 0)) |
1da177e4c Linux-2.6.12-rc2 |
1759 |
ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); |
d12af679b sysctl: fix neigh... |
1760 |
if (strcmp(ctl->procname, "retrans_time") == 0) |
cb5b09c17 neigh: wrap proc ... |
1761 |
ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1762 1763 |
else if (strcmp(ctl->procname, "base_reachable_time") == 0) |
cb5b09c17 neigh: wrap proc ... |
1764 1765 |
ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1766 1767 |
else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || |
ad02ac145 [IPV6] NDISC: Fix... |
1768 |
(strcmp(ctl->procname, "base_reachable_time_ms") == 0)) |
cb5b09c17 neigh: wrap proc ... |
1769 1770 |
ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); |
d12af679b sysctl: fix neigh... |
1771 |
else |
1da177e4c Linux-2.6.12-rc2 |
1772 |
ret = -1; |
1da177e4c Linux-2.6.12-rc2 |
1773 1774 |
if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { |
1f9248e56 neigh: convert pa... |
1775 1776 1777 |
if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) idev->nd_parms->reachable_time = neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); |
1da177e4c Linux-2.6.12-rc2 |
1778 1779 1780 1781 1782 1783 |
idev->tstamp = jiffies; inet6_ifinfo_notify(RTM_NEWLINK, idev); in6_dev_put(idev); } return ret; } |
1da177e4c Linux-2.6.12-rc2 |
1784 1785 |
#endif |
2c8c1e729 net: spread __net... |
1786 |
static int __net_init ndisc_net_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
1787 1788 1789 |
{ struct ipv6_pinfo *np; struct sock *sk; |
1ab1457c4 [NET] IPV6: Fix w... |
1790 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
1791 |
|
1ed8516f0 [IPV6]: Simplify ... |
1792 1793 |
err = inet_ctl_sock_create(&sk, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, net); |
1da177e4c Linux-2.6.12-rc2 |
1794 |
if (err < 0) { |
675418d51 net: ipv6: ndisc:... |
1795 1796 1797 1798 |
ND_PRINTK(0, err, "NDISC: Failed to initialize the control socket (err %d) ", err); |
1da177e4c Linux-2.6.12-rc2 |
1799 1800 |
return err; } |
1ed8516f0 [IPV6]: Simplify ... |
1801 |
net->ipv6.ndisc_sk = sk; |
1762f7e88 [NETNS][IPV6] ndi... |
1802 |
|
1da177e4c Linux-2.6.12-rc2 |
1803 |
np = inet6_sk(sk); |
1da177e4c Linux-2.6.12-rc2 |
1804 1805 1806 |
np->hop_limit = 255; /* Do not loopback ndisc messages */ np->mc_loop = 0; |
1da177e4c Linux-2.6.12-rc2 |
1807 |
|
1762f7e88 [NETNS][IPV6] ndi... |
1808 1809 |
return 0; } |
2c8c1e729 net: spread __net... |
1810 |
static void __net_exit ndisc_net_exit(struct net *net) |
1762f7e88 [NETNS][IPV6] ndi... |
1811 |
{ |
1ed8516f0 [IPV6]: Simplify ... |
1812 |
inet_ctl_sock_destroy(net->ipv6.ndisc_sk); |
1762f7e88 [NETNS][IPV6] ndi... |
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 |
} 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... |
1827 1828 1829 |
/* * Initialize the neighbour table */ |
d7480fd3b neigh: remove dyn... |
1830 |
neigh_table_init(NEIGH_ND_TABLE, &nd_tbl); |
1da177e4c Linux-2.6.12-rc2 |
1831 1832 |
#ifdef CONFIG_SYSCTL |
73af614ae neigh: use tbl->f... |
1833 |
err = neigh_sysctl_register(NULL, &nd_tbl.parms, |
56ec0fb10 neigh: remove exc... |
1834 |
ndisc_ifinfo_sysctl_change); |
1762f7e88 [NETNS][IPV6] ndi... |
1835 1836 |
if (err) goto out_unregister_pernet; |
1762f7e88 [NETNS][IPV6] ndi... |
1837 |
out: |
bcd081a3a net: ipv6: ndisc:... |
1838 |
#endif |
1762f7e88 [NETNS][IPV6] ndi... |
1839 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
1840 |
|
1762f7e88 [NETNS][IPV6] ndi... |
1841 |
#ifdef CONFIG_SYSCTL |
1762f7e88 [NETNS][IPV6] ndi... |
1842 |
out_unregister_pernet: |
1762f7e88 [NETNS][IPV6] ndi... |
1843 1844 |
unregister_pernet_subsys(&ndisc_net_ops); goto out; |
2c861cc65 ipv6: don't call ... |
1845 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
1846 |
} |
2c861cc65 ipv6: don't call ... |
1847 1848 1849 1850 1851 1852 |
int __init ndisc_late_init(void) { return register_netdevice_notifier(&ndisc_netdev_notifier); } void ndisc_late_cleanup(void) |
1da177e4c Linux-2.6.12-rc2 |
1853 |
{ |
36f73d0c3 [IPV6]: Add ndisc... |
1854 |
unregister_netdevice_notifier(&ndisc_netdev_notifier); |
2c861cc65 ipv6: don't call ... |
1855 1856 1857 1858 |
} void ndisc_cleanup(void) { |
1da177e4c Linux-2.6.12-rc2 |
1859 1860 1861 |
#ifdef CONFIG_SYSCTL neigh_sysctl_unregister(&nd_tbl.parms); #endif |
d7480fd3b neigh: remove dyn... |
1862 |
neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl); |
1762f7e88 [NETNS][IPV6] ndi... |
1863 |
unregister_pernet_subsys(&ndisc_net_ops); |
1da177e4c Linux-2.6.12-rc2 |
1864 |
} |