static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
		       __u8 ipproto,
		       void (*dscp_ecn_decapsulate)(struct ip6_tnl *t,
						    struct ipv6hdr *ipv6h,
						    struct sk_buff *skb))
{
	struct ip6_tnl *t;
	struct ipv6hdr *ipv6h = ipv6_hdr(skb);

	read_lock(&ip6_tnl_lock);

	if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
					&ipv6h->daddr)) != NULL) {
		if (t->parms.proto != ipproto && t->parms.proto != 0) {
			read_unlock(&ip6_tnl_lock);
			goto discard;
		}

		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
			read_unlock(&ip6_tnl_lock);
			goto discard;
		}

		if (!ip6_tnl_rcv_ctl(t)) {
			t->dev->stats.rx_dropped++;
			read_unlock(&ip6_tnl_lock);
			goto discard;
		}
		secpath_reset(skb);
		skb->mac_header = skb->network_header;
		skb_reset_network_header(skb);
		skb->protocol = htons(protocol);
		skb->pkt_type = PACKET_HOST;
		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
		skb->dev = t->dev;
		dst_release(skb->dst);
		skb->dst = NULL;
		nf_reset(skb);

		dscp_ecn_decapsulate(t, ipv6h, skb);

		t->dev->stats.rx_packets++;
		t->dev->stats.rx_bytes += skb->len;
		netif_rx(skb);
		read_unlock(&ip6_tnl_lock);
		return 0;
	}
	read_unlock(&ip6_tnl_lock);
	return 1;

discard:
	kfree_skb(skb);
	return 0;
}
Exemple #2
0
static int
ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
{
	struct sk_buff *skb = *pskb;
	struct ipv6hdr *ipv6h;
	struct ip6_tnl *t;

	if (!pskb_may_pull(skb, sizeof (*ipv6h)))
		goto discard;

	ipv6h = skb->nh.ipv6h;

	read_lock(&ip6ip6_lock);

	if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
			read_unlock(&ip6ip6_lock);
			kfree_skb(skb);
			return 0;
		}

		if (!ip6_tnl_rcv_ctl(t)) {
			t->stat.rx_dropped++;
			read_unlock(&ip6ip6_lock);
			goto discard;
		}
		secpath_reset(skb);
		skb->mac.raw = skb->nh.raw;
		skb->nh.raw = skb->data;
		skb->protocol = htons(ETH_P_IPV6);
		skb->pkt_type = PACKET_HOST;
		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
		skb->dev = t->dev;
		dst_release(skb->dst);
		skb->dst = NULL;
		if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
			ipv6_copy_dscp(ipv6h, skb->nh.ipv6h);
		ip6ip6_ecn_decapsulate(ipv6h, skb);
		t->stat.rx_packets++;
		t->stat.rx_bytes += skb->len;
		netif_rx(skb);
		read_unlock(&ip6ip6_lock);
		return 0;
	}
	read_unlock(&ip6ip6_lock);
	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
discard:
	return 1;
}