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>
        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
 
        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
 
        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);
 
        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);