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