diff options
| author | Timo Teräs <timo.teras@iki.fi> | 2011-03-28 18:40:53 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-03-30 03:10:47 -0400 |
| commit | 93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa (patch) | |
| tree | 6ccf21f8d1e4431c6be79c265fb1f9a722308f63 /include | |
| parent | 1459a3cc51d90d78027c7b5c1790e5d22751c8eb (diff) | |
net: gre: provide multicast mappings for ipv4 and ipv6
My commit 6d55cb91a0020ac0 (gre: fix hard header destination
address checking) broke multicast.
The reason is that ip_gre used to get ipgre_header() calls with
zero destination if we have NOARP or multicast destination. Instead
the actual target was decided at ipgre_tunnel_xmit() time based on
per-protocol dissection.
Instead of allowing the "abuse" of ->header() calls with invalid
destination, this creates multicast mappings for ip_gre. This also
fixes "ip neigh show nud noarp" to display the proper multicast
mappings used by the gre device.
Reported-by: Doug Kehn <rdkehn@yahoo.com>
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Acked-by: Doug Kehn <rdkehn@yahoo.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
| -rw-r--r-- | include/net/if_inet6.h | 16 | ||||
| -rw-r--r-- | include/net/ip.h | 8 |
2 files changed, 24 insertions, 0 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 04977eefb0ee..fccc2180c61b 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
| @@ -286,5 +286,21 @@ static inline void ipv6_ib_mc_map(const struct in6_addr *addr, | |||
| 286 | buf[9] = broadcast[9]; | 286 | buf[9] = broadcast[9]; |
| 287 | memcpy(buf + 10, addr->s6_addr + 6, 10); | 287 | memcpy(buf + 10, addr->s6_addr + 6, 10); |
| 288 | } | 288 | } |
| 289 | |||
| 290 | static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr, | ||
| 291 | const unsigned char *broadcast, char *buf) | ||
| 292 | { | ||
| 293 | if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) { | ||
| 294 | memcpy(buf, broadcast, 4); | ||
| 295 | } else { | ||
| 296 | /* v4mapped? */ | ||
| 297 | if ((addr->s6_addr32[0] | addr->s6_addr32[1] | | ||
| 298 | (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0) | ||
| 299 | return -EINVAL; | ||
| 300 | memcpy(buf, &addr->s6_addr32[3], 4); | ||
| 301 | } | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 289 | #endif | 305 | #endif |
| 290 | #endif | 306 | #endif |
diff --git a/include/net/ip.h b/include/net/ip.h index a4f631108c54..7c416583b710 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
| @@ -339,6 +339,14 @@ static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, ch | |||
| 339 | buf[16] = addr & 0x0f; | 339 | buf[16] = addr & 0x0f; |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf) | ||
| 343 | { | ||
| 344 | if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) | ||
| 345 | memcpy(buf, broadcast, 4); | ||
| 346 | else | ||
| 347 | memcpy(buf, &naddr, sizeof(naddr)); | ||
| 348 | } | ||
| 349 | |||
| 342 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 350 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 343 | #include <linux/ipv6.h> | 351 | #include <linux/ipv6.h> |
| 344 | #endif | 352 | #endif |
