and changed files
[powerpc.git] / net / ipv6 / ip6_tunnel.c
index 70684e0..a0902fb 100644 (file)
@@ -384,7 +384,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
  **/
 
 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;
@@ -404,6 +404,9 @@ ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        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) {
@@ -487,8 +490,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        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;
 
@@ -522,8 +525,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        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));
@@ -581,8 +584,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        __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;
 
@@ -596,10 +599,10 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                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;
@@ -622,10 +625,10 @@ static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
        __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,
@@ -633,10 +636,10 @@ 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)
@@ -671,18 +674,22 @@ 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;
@@ -694,8 +701,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
                        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));
@@ -722,12 +729,14 @@ discard:
 
 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 {
@@ -825,7 +834,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 {
        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;
@@ -889,15 +898,16 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        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);
@@ -932,14 +942,15 @@ static inline int
 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))
@@ -970,7 +981,7 @@ static inline int
 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;
@@ -978,12 +989,14 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        __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);
@@ -1140,6 +1153,7 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
        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;
@@ -1205,7 +1219,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                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) {
@@ -1324,7 +1339,6 @@ static inline void
 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);
 }
@@ -1355,6 +1369,7 @@ ip6_fb_tnl_dev_init(struct net_device *dev)
 {
        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;