net: gre: provide multicast mappings for ipv4 and ipv6
My commit 6d55cb91a0
(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>
This commit is contained in:
Родитель
1459a3cc51
Коммит
93ca3bb5df
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче