Skip to content

Commit

Permalink
net: gre: provide multicast mappings for ipv4 and ipv6
Browse files Browse the repository at this point in the history
My commit 6d55cb9 (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 <[email protected]>
Signed-off-by: Timo Teräs <[email protected]>
Acked-by: Doug Kehn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
fabled authored and davem330 committed Mar 30, 2011
1 parent 1459a3c commit 93ca3bb
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 0 deletions.
16 changes: 16 additions & 0 deletions include/net/if_inet6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 8 additions & 0 deletions include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions net/ipv4/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 93ca3bb

Please sign in to comment.