--- net-2.6/include/linux/skbuff.h.orig 2008-05-07 13:15:41.000000000 -0700 +++ net-2.6/include/linux/skbuff.h 2008-05-12 10:50:18.000000000 -0700 @@ -315,9 +315,11 @@ struct sk_buff { #endif #endif #ifdef CONFIG_IPV6_NDISC_NODETYPE - __u8 ndisc_nodetype:2; + __u8 ndisc_nodetype:2, + ll_noloop:1, + ll_rsvd:5; #endif - /* 14 bit hole */ + /* 8 bit hole */ #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; --- net-2.6/include/linux/if.h.orig 2008-05-07 09:36:11.000000000 -0700 +++ net-2.6/include/linux/if.h 2008-05-14 10:10:17.000000000 -0700 @@ -63,7 +63,9 @@ #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ #define IFF_BONDING 0x20 /* bonding master or slave */ #define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ -#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */ +#define IFF_ISATAP 0x80 /* ISATAP interface (RFC5214) */ +#define IFF_VET 0x0100 /* VET interface (inherits ISATAP) */ +#define IFF_SEAL 0x0200 /* SEAL interface (inherits VET) */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 --- net-2.6/include/linux/if_tunnel.h.orig 2008-05-06 13:06:16.000000000 -0700 +++ net-2.6/include/linux/if_tunnel.h 2008-05-12 10:36:38.000000000 -0700 @@ -34,6 +34,8 @@ struct ip_tunnel_parm /* SIT-mode i_flags */ #define SIT_ISATAP 0x0001 +#define SIT_VET 0x0002 +#define SIT_SEAL 0x0004 struct ip_tunnel_prl { __be32 addr; --- net-2.6/include/net/if_inet6.h.orig 2008-05-07 15:16:35.000000000 -0700 +++ net-2.6/include/net/if_inet6.h 2008-05-07 15:36:44.000000000 -0700 @@ -286,5 +286,28 @@ static inline void ipv6_ib_mc_map(const buf[9] = broadcast[9]; memcpy(buf + 10, addr->s6_addr + 6, 10); } + +static inline void ipv6_vet_mc_map(struct in6_addr *addr, char *buf) +{ + /* + * (RFC2529, Section 6) - Address Mapping -- Multicast + * + * +-------+-------+-------+-------+ + * | 239 | OLS | DST14 | DST15 | + * +-------+-------+-------+-------+ + * + * DST14, DST15 last two bytes of IPv6 multicast address. + * + * OLS from the configured Organization-Local + * Scope address block (for IPv4 - RFC2365). + * SHOULD be 192, see [ADMIN] for details. + */ + + buf[0]= 239; + buf[1]= 192; + buf[2] = addr->s6_addr[14]; + buf[3] = addr->s6_addr[15]; +} + #endif #endif --- net-2.6/include/net/ndisc.h.orig 2008-05-07 10:16:51.000000000 -0700 +++ net-2.6/include/net/ndisc.h 2008-05-07 10:17:03.000000000 -0700 @@ -13,7 +13,7 @@ /* * Router type: cross-layer information from link-layer to - * IPv6 layer reported by certain link types (e.g., RFC4214). + * IPv6 layer reported by certain link types (e.g., RFC5214). */ #define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */ #define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */ --- net-2.6/net/ipv4/ip_output.c.orig 2008-05-07 13:11:07.000000000 -0700 +++ net-2.6/net/ipv4/ip_output.c 2008-05-12 10:47:40.000000000 -0700 @@ -256,7 +256,7 @@ int ip_mc_output(struct sk_buff *skb) */ if (rt->rt_flags&RTCF_MULTICAST) { - if ((!sk || inet_sk(sk)->mc_loop) + if ((!sk || inet_sk(sk)->mc_loop) && !skb->ll_noloop #ifdef CONFIG_IP_MROUTE /* Small optimization: do not loopback not local frames, which returned after forwarding; they will be dropped --- net-2.6/net/ipv6/sit.c.orig 2008-05-06 13:15:44.000000000 -0700 +++ net-2.6/net/ipv6/sit.c 2008-05-15 09:03:19.000000000 -0700 @@ -17,6 +17,7 @@ * Roger Venning : 6to4 support * Nate Thompson : 6to4 support * Fred Templin : isatap support + * Fred Templin : vet support */ #include @@ -82,7 +83,7 @@ struct sit_net { static DEFINE_RWLOCK(ipip6_lock); static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, - __be32 remote, __be32 local) + __be32 remote, __be32 local, int ifindex) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -99,8 +100,16 @@ static struct ip_tunnel * ipip6_tunnel_l return t; } for (t = sitn->tunnels_l[h1]; t; t = t->next) { - if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) - return t; + if (ipv4_is_multicast(local)) { + if ((t->dev->iflink == ifindex) && + (t->dev->flags&IFF_MULTICAST) && + (t->dev->flags&IFF_UP)) + return t; + } else { + if (local == t->parms.iph.saddr && + (t->dev->flags&IFF_UP)) + return t; + } } if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) return t; @@ -193,8 +202,23 @@ static struct ip_tunnel * ipip6_tunnel_l dev->init = ipip6_tunnel_init; nt->parms = *parms; - if (parms->i_flags & SIT_ISATAP) + /* ISATAP interface family (priv_flags are cumulative) */ + /* + * TODO: handle multiple ISATAP family tunnel interfaces, plus + * multiple underlying IPv4 interfaces per each tunnel interface. + * (Need a *list* of underlying links instead of dev->iflink). + */ + switch (parms->i_flags) { + case SIT_VET: + if (!parms->link) + goto failed_free; + dev->flags |= IFF_MULTICAST; + dev->priv_flags |= IFF_VET; + case SIT_ISATAP: dev->priv_flags |= IFF_ISATAP; + default: + break; + } if (register_netdevice(dev) < 0) goto failed_free; @@ -446,7 +470,8 @@ static int ipip6_err(struct sk_buff *skb err = -ENOENT; read_lock(&ipip6_lock); - t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); + t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, + iph->saddr, skb->dev->ifindex); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -567,8 +592,8 @@ static int ipip6_rcv(struct sk_buff *skb iph = ip_hdr(skb); read_lock(&ipip6_lock); - if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), - iph->saddr, iph->daddr)) != NULL) { + if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), iph->saddr, + iph->daddr, skb->dev->ifindex)) != NULL) { secpath_reset(skb); skb->mac_header = skb->network_header; skb_reset_network_header(skb); @@ -577,11 +602,19 @@ static int ipip6_rcv(struct sk_buff *skb skb->pkt_type = PACKET_HOST; if ((tunnel->dev->priv_flags & IFF_ISATAP) && - !isatap_chksrc(skb, iph, tunnel)) { + !(isatap_chksrc(skb, iph, tunnel))) { tunnel->stat.rx_errors++; - read_unlock(&ipip6_lock); - kfree_skb(skb); - return 0; + goto drop; + } + + if (ipv4_is_multicast(iph->daddr)) { + + if (!(tunnel->dev->flags & IFF_MULTICAST)) + goto drop; + + /* skb->ll_noloop suppresses L2 loopback */ + tunnel->stat.multicast++; + skb->pkt_type = PACKET_MULTICAST; } tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; @@ -596,8 +629,9 @@ static int ipip6_rcv(struct sk_buff *skb } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - kfree_skb(skb); +drop: read_unlock(&ipip6_lock); + kfree_skb(skb); out: return 0; } @@ -629,7 +663,7 @@ static int ipip6_tunnel_xmit(struct sk_b struct ipv6hdr *iph6 = ipv6_hdr(skb); u8 tos = tunnel->parms.iph.tos; struct rtable *rt; /* Route to the other host */ - struct net_device *tdev; /* Device to other host */ + struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; @@ -645,7 +679,7 @@ static int ipip6_tunnel_xmit(struct sk_b if (skb->protocol != htons(ETH_P_IPV6)) goto tx_error; - /* ISATAP (RFC4214) - must come before 6to4 */ + /* ISATAP (RFC5214) - must come before 6to4 */ if (dev->priv_flags & IFF_ISATAP) { struct neighbour *neigh = NULL; @@ -662,10 +696,16 @@ static int ipip6_tunnel_xmit(struct sk_b addr_type = ipv6_addr_type(addr6); if ((addr_type & IPV6_ADDR_UNICAST) && - ipv6_addr_is_isatap(addr6)) + ipv6_addr_is_isatap(addr6)) { dst = addr6->s6_addr32[3]; - else - goto tx_error; + } else { + if ((addr_type & IPV6_ADDR_MULTICAST) && + (dev->flags & IFF_MULTICAST)) { + ndisc_mc_map(addr6, (char *)&dst, dev, 0); + skb->ll_noloop = 1; + } else + goto tx_error; + } } if (!dst) @@ -710,9 +750,12 @@ static int ipip6_tunnel_xmit(struct sk_b } } if (rt->rt_type != RTN_UNICAST) { - ip_rt_put(rt); - tunnel->stat.tx_carrier_errors++; - goto tx_error_icmp; + if (!((rt->rt_type == RTN_MULTICAST) && + (dev->flags & IFF_MULTICAST))) { + ip_rt_put(rt); + tunnel->stat.tx_carrier_errors++; + goto tx_error_icmp; + } } tdev = rt->u.dst.dev; @@ -893,6 +936,11 @@ ipip6_tunnel_ioctl (struct net_device *d if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPV6 || p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) goto done; + + /* VET must specifiy link for multicast */ + if ((p.i_flags & SIT_VET) && !(p.link)) + goto done; + if (p.iph.ttl) p.iph.frag_off |= htons(IP_DF); @@ -1016,6 +1064,25 @@ static int ipip6_tunnel_change_mtu(struc return 0; } +static void ipip6_change_rx_flags(struct net_device *dev, int change) +{ + struct ip_tunnel *tunnel; + struct net_device *tdev; + + if (!(dev->priv_flags | IFF_MULTICAST)) + return; + + if (!(tunnel = netdev_priv(dev)) || !tunnel->parms.link) + return; + + tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); + + if (change & IFF_ALLMULTI) + dev_set_allmulti(tdev, dev->flags & IFF_ALLMULTI ? 1 : -1); + if (change & IFF_PROMISC) + dev_set_promiscuity(tdev, dev->flags & IFF_PROMISC ? 1 : -1); +} + static void ipip6_tunnel_setup(struct net_device *dev) { dev->uninit = ipip6_tunnel_uninit; @@ -1024,6 +1091,9 @@ static void ipip6_tunnel_setup(struct ne dev->get_stats = ipip6_tunnel_get_stats; dev->do_ioctl = ipip6_tunnel_ioctl; dev->change_mtu = ipip6_tunnel_change_mtu; + dev->change_rx_flags = ipip6_change_rx_flags; + dev->set_rx_mode = NULL; /* IPv6-IPv4 mapping in mcast.c */ + dev->set_multicast_list = NULL; /* "" */ dev->type = ARPHRD_SIT; dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); --- net-2.6/net/ipv6/ndisc.c.orig 2008-05-07 15:10:40.000000000 -0700 +++ net-2.6/net/ipv6/ndisc.c 2008-05-12 10:39:58.000000000 -0700 @@ -338,6 +338,12 @@ int ndisc_mc_map(struct in6_addr *addr, case ARPHRD_INFINIBAND: ipv6_ib_mc_map(addr, dev->broadcast, buf); return 0; + case ARPHRD_SIT: + if (dev->priv_flags & IFF_VET) { + ipv6_vet_mc_map(addr, buf); + return 0; + } else + return -EINVAL; default: if (dir) { memcpy(buf, dev->broadcast, dev->addr_len); --- net-2.6/net/ipv6/addrconf.c.orig 2008-05-06 13:17:59.000000000 -0700 +++ net-2.6/net/ipv6/addrconf.c 2008-05-13 10:56:43.000000000 -0700 @@ -1563,7 +1563,7 @@ regen: * * - Reserved subnet anycast (RFC 2526) * 11111101 11....11 1xxxxxxx - * - ISATAP (RFC4214) 6.1 + * - ISATAP (RFC5214) 6.1 * 00-00-5E-FE-xx-xx-xx-xx * - value 0 * - XXX: already assigned to an address on the device @@ -2312,8 +2312,12 @@ static void addrconf_sit_config(struct n if (dev->priv_flags & IFF_ISATAP) { struct in6_addr addr; + /* Add default multicast route */ + if (dev->priv_flags & IFF_VET) + addrconf_add_mroute(dev); + + /* Add link local address (also adds ll route) */ ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - addrconf_prefix_route(&addr, 64, dev, 0, 0); if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) addrconf_add_linklocal(idev, &addr); return; --- net-2.6/net/ipv6/mcast.c.orig 2008-05-08 07:53:03.000000000 -0700 +++ net-2.6/net/ipv6/mcast.c 2008-05-14 09:35:48.000000000 -0700 @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include #include @@ -713,15 +715,31 @@ static void igmp6_group_added(struct ifm { struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; + struct in_device *in_dev; + int add = 0; spin_lock_bh(&mc->mca_lock); if (!(mc->mca_flags&MAF_LOADED)) { mc->mca_flags |= MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) + if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) { dev_mc_add(dev, buf, dev->addr_len, 0); + add++; + } } spin_unlock_bh(&mc->mca_lock); + /* NB: there may be many IPv6 grps per IPv4 grp */ + if (add && (dev->type == ARPHRD_SIT) && (dev->priv_flags & IFF_VET) && + (in_dev = inetdev_by_index(dev_net(dev), dev->iflink))) { + + if (!(rtnl_is_locked())) { + rtnl_lock(); + ip_mc_inc_group(in_dev, *(__be32 *)buf); + rtnl_unlock(); + } else + ip_mc_inc_group(in_dev, *(__be32 *)buf); + } + if (!(dev->flags & IFF_UP) || (mc->mca_flags & MAF_NOREPORT)) return; @@ -739,12 +757,16 @@ static void igmp6_group_dropped(struct i { struct net_device *dev = mc->idev->dev; char buf[MAX_ADDR_LEN]; + struct in_device *in_dev; + int del = 0; spin_lock_bh(&mc->mca_lock); if (mc->mca_flags&MAF_LOADED) { mc->mca_flags &= ~MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) + if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) { dev_mc_delete(dev, buf, dev->addr_len, 0); + del++; + } } if (mc->mca_flags & MAF_NOREPORT) @@ -760,6 +782,18 @@ static void igmp6_group_dropped(struct i done: ip6_mc_clear_src(mc); spin_unlock_bh(&mc->mca_lock); + + /* NB: there may be many IPv6 grps per IPv4 grp */ + if (del && (dev->type == ARPHRD_SIT) && (dev->priv_flags & IFF_VET) && + (in_dev = inetdev_by_index(dev_net(dev), dev->iflink))) { + + if (!(rtnl_is_locked())) { + rtnl_lock(); + ip_mc_dec_group(in_dev, *(__be32 *)buf); + rtnl_unlock(); + } else + ip_mc_dec_group(in_dev, *(__be32 *)buf); + } } /*