**/
static int
-ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
int *type, int *code, int *msg, __be32 *info, int offset)
{
struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
if ((t = ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
goto out;
+ if (t->parms.proto != ipproto && t->parms.proto != 0)
+ goto out;
+
err = 0;
switch (*type) {
struct flowi fl;
struct rtable *rt;
- err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info,
- offset);
+ err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
+ &rel_msg, &rel_info, offset);
if (err < 0)
return err;
dst_release(skb2->dst);
skb2->dst = NULL;
skb_pull(skb2, offset);
- skb2->nh.raw = skb2->data;
- eiph = skb2->nh.iph;
+ skb_reset_network_header(skb2);
+ eiph = ip_hdr(skb2);
/* Try to guess incoming interface */
memset(&fl, 0, sizeof(fl));
__u32 rel_info = info;
int err;
- err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info,
- offset);
+ err = ip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
+ &rel_msg, &rel_info, offset);
if (err < 0)
return err;
dst_release(skb2->dst);
skb2->dst = NULL;
skb_pull(skb2, offset);
- skb2->nh.raw = skb2->data;
+ skb_reset_network_header(skb2);
/* Try to guess incoming interface */
- rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
+ rt = rt6_lookup(&ipv6_hdr(skb2)->saddr, NULL, 0, 0);
if (rt && rt->rt6i_dev)
skb2->dev = rt->rt6i_dev;
__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
- ipv4_change_dsfield(skb->nh.iph, INET_ECN_MASK, dsfield);
+ ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
if (INET_ECN_is_ce(dsfield))
- IP_ECN_set_ce(skb->nh.iph);
+ IP_ECN_set_ce(ip_hdr(skb));
}
static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
struct sk_buff *skb)
{
if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
- ipv6_copy_dscp(ipv6h, skb->nh.ipv6h);
+ ipv6_copy_dscp(ipv6h, ipv6_hdr(skb));
if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h)))
- IP6_ECN_set_ce(skb->nh.ipv6h);
+ IP6_ECN_set_ce(ipv6_hdr(skb));
}
static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
**/
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 ipv6hdr *ipv6h;
struct ip6_tnl *t;
-
- ipv6h = skb->nh.ipv6h;
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
read_lock(&ip6_tnl_lock);
if ((t = ip6_tnl_lookup(&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;
goto discard;
}
secpath_reset(skb);
- skb->mac.raw = skb->nh.raw;
- skb->nh.raw = skb->data;
+ 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));
static int ip4ip6_rcv(struct sk_buff *skb)
{
- return ip6_tnl_rcv(skb, ETH_P_IP, ip4ip6_dscp_ecn_decapsulate);
+ return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
+ ip4ip6_dscp_ecn_decapsulate);
}
static int ip6ip6_rcv(struct sk_buff *skb)
{
- return ip6_tnl_rcv(skb, ETH_P_IPV6, ip6ip6_dscp_ecn_decapsulate);
+ return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
+ ip6ip6_dscp_ecn_decapsulate);
}
struct ipv6_tel_txoption {
{
struct ip6_tnl *t = netdev_priv(dev);
struct net_device_stats *stats = &t->stat;
- struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ipv6_tel_txoption opt;
struct dst_entry *dst;
struct net_device *tdev;
dst_release(skb->dst);
skb->dst = dst_clone(dst);
- skb->h.raw = skb->nh.raw;
+ skb->transport_header = skb->network_header;
proto = fl->proto;
if (encap_limit >= 0) {
init_tel_txopt(&opt, encap_limit);
ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
}
- skb->nh.raw = skb_push(skb, sizeof(struct ipv6hdr));
- ipv6h = skb->nh.ipv6h;
+ skb_push(skb, sizeof(struct ipv6hdr));
+ skb_reset_network_header(skb);
+ ipv6h = ipv6_hdr(skb);
*(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000);
dsfield = INET_ECN_encapsulate(0, dsfield);
ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct iphdr *iph = skb->nh.iph;
+ struct iphdr *iph = ip_hdr(skb);
int encap_limit = -1;
struct flowi fl;
__u8 dsfield;
__u32 mtu;
int err;
- if (!ip6_tnl_xmit_ctl(t))
+ if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
+ !ip6_tnl_xmit_ctl(t))
return -1;
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
int encap_limit = -1;
__u16 offset;
struct flowi fl;
__u32 mtu;
int err;
- if (!ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
+ if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
+ !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
return -1;
- if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
+ offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb));
+ if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
- tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
+ tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
if (tel->encap_limit == 0) {
icmpv6_send(skb, ICMPV6_PARAMPROB,
ICMPV6_HDR_FIELD, offset + 2, skb->dev);
t->parms.encap_limit = p->encap_limit;
t->parms.flowinfo = p->flowinfo;
t->parms.link = p->link;
+ t->parms.proto = p->proto;
ip6_tnl_dst_reset(t);
ip6_tnl_link_config(t);
return 0;
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
break;
err = -EINVAL;
- if (p.proto != IPPROTO_IPV6)
+ if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
+ p.proto != 0)
break;
t = ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL);
if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
ip6_tnl_dev_init_gen(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- t->fl.proto = IPPROTO_IPV6;
t->dev = dev;
strcpy(t->parms.name, dev->name);
}
{
struct ip6_tnl *t = netdev_priv(dev);
ip6_tnl_dev_init_gen(dev);
+ t->parms.proto = IPPROTO_IPV6;
dev_hold(dev);
tnls_wc[0] = t;
return 0;