aboutsummaryrefslogtreecommitdiffstats
path: root/main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch')
-rw-r--r--main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch98
1 files changed, 98 insertions, 0 deletions
diff --git a/main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch b/main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch
new file mode 100644
index 0000000000..a9bff5dcfd
--- /dev/null
+++ b/main/linux-grsec/net-gre-provide-multicast-mappings-for-ipv4-and-ipv6.patch
@@ -0,0 +1,98 @@
+From: Timo Teräs <timo.teras@iki.fi>
+Date: Mon, 28 Mar 2011 22:40:53 +0000 (+0000)
+Subject: net: gre: provide multicast mappings for ipv4 and ipv6
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=93ca3bb5df9bc8b2c60485e1cc6507c3d7c8e1fa
+
+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>
+---
+
+diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
+index 04977ee..fccc218 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 a4f6311..7c41658 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
+diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
+index 090d273..1b74d3b 100644
+--- a/net/ipv4/arp.c
++++ b/net/ipv4/arp.c
+@@ -215,6 +215,9 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
+ case ARPHRD_INFINIBAND:
+ ip_ib_mc_map(addr, dev->broadcast, haddr);
+ return 0;
++ case ARPHRD_IPGRE:
++ ip_ipgre_mc_map(addr, dev->broadcast, haddr);
++ return 0;
+ default:
+ if (dir) {
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index 0e49c9d..92f952d 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -341,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
+ case ARPHRD_INFINIBAND:
+ ipv6_ib_mc_map(addr, dev->broadcast, buf);
+ return 0;
++ case ARPHRD_IPGRE:
++ return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
+ default:
+ if (dir) {
+ memcpy(buf, dev->broadcast, dev->addr_len);