Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93ca3bb5 authored by Timo Teräs's avatar Timo Teräs Committed by David S. Miller
Browse files

net: gre: provide multicast mappings for ipv4 and ipv6



My commit 6d55cb91 (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: default avatarDoug Kehn <rdkehn@yahoo.com>
Signed-off-by: default avatarTimo Teräs <timo.teras@iki.fi>
Acked-by: default avatarDoug Kehn <rdkehn@yahoo.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1459a3cc
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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);