summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2011-03-28 22:40:53 +0000
committerDavid S. Miller <davem@davemloft.net>2011-03-30 00:10:47 -0700
commit93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa (patch)
tree6ccf21f8d1e4431c6be79c265fb1f9a722308f63 /include
parent1459a3cc51d90d78027c7b5c1790e5d22751c8eb (diff)
downloadlinux-3.10-93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa.tar.gz
linux-3.10-93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa.tar.bz2
linux-3.10-93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa.zip
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.h16
-rw-r--r--include/net/ip.h8
2 files changed, 24 insertions, 0 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 04977eefb0e..fccc2180c61 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,
buf[9] = broadcast[9];
memcpy(buf + 10, addr->s6_addr + 6, 10);
}
+
+static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr,
+ const unsigned char *broadcast, char *buf)
+{
+ if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) {
+ memcpy(buf, broadcast, 4);
+ } else {
+ /* v4mapped? */
+ if ((addr->s6_addr32[0] | addr->s6_addr32[1] |
+ (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0)
+ return -EINVAL;
+ memcpy(buf, &addr->s6_addr32[3], 4);
+ }
+ return 0;
+}
+
#endif
#endif
diff --git a/include/net/ip.h b/include/net/ip.h
index a4f631108c5..7c416583b71 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
buf[16] = addr & 0x0f;
}
+static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf)
+{
+ if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0)
+ memcpy(buf, broadcast, 4);
+ else
+ memcpy(buf, &naddr, sizeof(naddr));
+}
+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <linux/ipv6.h>
#endif