diff options
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.patch | 98 |
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); |