]> git.neil.brown.name Git - history.git/commitdiff
[IPV6]: Fixed multiple mistake extension header handling.
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>
Mon, 14 Apr 2003 04:26:37 +0000 (21:26 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Mon, 14 Apr 2003 04:26:37 +0000 (21:26 -0700)
 - double free if sending Parameter Problem message in reassembly code.
 - (sometimes) broken checksum
 - HbH not producing unknown header; it is only allowed at the beginning of
   the exthdrs chain.
 - wrong pointer value in Parameter Problem message.

12 files changed:
include/net/protocol.h
include/net/xfrm.h
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/ip6_input.c
net/ipv6/reassembly.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_input.c

index 6f493c4a23cc13328d474a4dfe8faeb0020820e5..6f0e4234a4426839bd2da2b7f808b76b549f8fa3 100644 (file)
@@ -44,15 +44,17 @@ struct inet_protocol
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct inet6_protocol 
 {
-       int     (*handler)(struct sk_buff **skbp);
+       int     (*handler)(struct sk_buff **skb, unsigned int *nhoffp);
 
        void    (*err_handler)(struct sk_buff *skb,
                               struct inet6_skb_parm *opt,
                               int type, int code, int offset,
                               __u32 info);
-       int     no_policy;
+       unsigned int    flags;  /* INET6_PROTO_xxx */
 };
 
+#define INET6_PROTO_NOPOLICY   0x1
+#define INET6_PROTO_FINAL      0x2
 #endif
 
 /* This is used to register socket interfaces for IP protocols.  */
index be3c652da8c7cfb920106f8fa3831e60c5746c61..6868d7a41bba6d625cf9dc2fc79a0d5530adc311 100644 (file)
@@ -760,7 +760,7 @@ extern int xfrm4_rcv(struct sk_buff *skb);
 extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv(struct sk_buff **pskb);
+extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
 
index aa5fcbd9bc9900ba9abdcd21833ab8b6353617cb..d0c11a304b797ee15ff511ed76e79af053f020c5 100644 (file)
@@ -805,7 +805,6 @@ static int __init inet6_init(void)
        sit_init();
 
        /* Init v6 extension headers. */
-       ipv6_hopopts_init();
        ipv6_rthdr_init();
        ipv6_frag_init();
        ipv6_nodata_init();
index 746dc9697b15ac58d5691c1a94b278eead65c619..19504b00adc83da7f4a5ffec532b25839da076a9 100644 (file)
@@ -330,7 +330,7 @@ static struct xfrm_type ah6_type =
 static struct inet6_protocol ah6_protocol = {
        .handler        =       xfrm6_rcv,
        .err_handler    =       ah6_err,
-       .no_policy      =       1,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 int __init ah6_init(void)
index 764a5d8ac1ea7290a93c06e1b629b8a7ad65c836..25b9e1f15542cf50520a7f5ef3beb0e4446ea718 100644 (file)
@@ -501,7 +501,7 @@ static struct xfrm_type esp6_type =
 static struct inet6_protocol esp6_protocol = {
        .handler        =       xfrm6_rcv,
        .err_handler    =       esp6_err,
-       .no_policy      =       1,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 int __init esp6_init(void)
index 24cdfb9350ec3bef4cb05bcc9429aca0084bb8da..4dfbc63a333483c2dd93a47b3f07d04dac4c1abc 100644 (file)
@@ -18,9 +18,9 @@
 /* Changes:
  *     yoshfuji                : ensure not to overrun while parsing 
  *                               tlv options.
- *     Mitsuru KANDA @USAGI    : Remove ipv6_parse_exthdrs().
- *                             : Register inbound extention header
- *                             : handlers as inet6_protocol{}.
+ *     Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
+ *     YOSHIFUJI Hideaki @USAGI  Register inbound extention header
+ *                               handlers as inet6_protocol{}.
  */
 
 #include <linux/errno.h>
@@ -153,38 +153,37 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = {
        {-1,                    NULL}
 };
 
-static int ipv6_destopt_rcv(struct sk_buff **skbp
+static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *skbp;
        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
-       u8 nexthdr = 0;
 
        if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
            !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
                kfree_skb(skb);
-               return 0;
+               return -1;
        }
 
-       nexthdr = ((struct ipv6_destopt_hdr *)skb->h.raw)->nexthdr;
-       
        opt->dst1 = skb->h.raw - skb->nh.raw;
 
        if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
                skb->h.raw += ((skb->h.raw[1]+1)<<3);
-               return -nexthdr;
+               *nhoffp = opt->dst1;
+               return 1;
        }
-                                               
-       return 0;
+
+       return -1;
 }
 
 static struct inet6_protocol destopt_protocol =
 {
-       .handler        =       ipv6_destopt_rcv,
+       .handler        =       ipv6_destopt_rcv,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_destopt_init(void)
 {
-       if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0) 
+       if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
                printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
 }
 
@@ -192,7 +191,7 @@ void __init ipv6_destopt_init(void)
   NONE header. No data in packet.
  ********************************/
 
-static int ipv6_nodata_rcv(struct sk_buff **skbp)
+static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *skbp;
 
@@ -203,6 +202,7 @@ static int ipv6_nodata_rcv(struct sk_buff **skbp)
 static struct inet6_protocol nodata_protocol =
 {
        .handler        =       ipv6_nodata_rcv,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_nodata_init(void)
@@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void)
   Routing header.
  ********************************/
 
-static int ipv6_rthdr_rcv(struct sk_buff **skbp)
+static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *skbp;
        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
@@ -223,7 +223,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
        struct in6_addr daddr;
        int addr_type;
        int n, i;
-       u8 nexthdr = 0;
 
        struct ipv6_rt_hdr *hdr;
        struct rt0_hdr *rthdr;
@@ -232,16 +231,15 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
            !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
                IP6_INC_STATS_BH(Ip6InHdrErrors);
                kfree_skb(skb);
-               return 0;
+               return -1;
        }
 
        hdr = (struct ipv6_rt_hdr *) skb->h.raw;
-       nexthdr = hdr->nexthdr;
 
        if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||
            skb->pkt_type != PACKET_HOST) {
                kfree_skb(skb);
-               return 0;
+               return -1;
        }
 
 looped_back:
@@ -250,12 +248,13 @@ looped_back:
                skb->h.raw += (hdr->hdrlen + 1) << 3;
                opt->dst0 = opt->dst1;
                opt->dst1 = 0;
-               return -nexthdr;
+               *nhoffp = (&hdr->nexthdr) - skb->nh.raw;
+               return 1;
        }
 
        if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
-               return 0;
+               return -1;
        }
 
        /*
@@ -267,7 +266,7 @@ looped_back:
 
        if (hdr->segments_left > n) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
-               return 0;
+               return -1;
        }
 
        /* We are about to mangle packet header. Be careful!
@@ -277,7 +276,7 @@ looped_back:
                struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
                kfree_skb(skb);
                if (skb2 == NULL)
-                       return 0;
+                       return -1;
                *skbp = skb = skb2;
                opt = (struct inet6_skb_parm *)skb2->cb;
                hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
@@ -296,7 +295,7 @@ looped_back:
 
        if (addr_type&IPV6_ADDR_MULTICAST) {
                kfree_skb(skb);
-               return 0;
+               return -1;
        }
 
        ipv6_addr_copy(&daddr, addr);
@@ -307,26 +306,27 @@ looped_back:
        ip6_route_input(skb);
        if (skb->dst->error) {
                dst_input(skb);
-               return 0;
+               return -1;
        }
        if (skb->dst->dev->flags&IFF_LOOPBACK) {
                if (skb->nh.ipv6h->hop_limit <= 1) {
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
                                    0, skb->dev);
                        kfree_skb(skb);
-                       return 0;
+                       return -1;
                }
                skb->nh.ipv6h->hop_limit--;
                goto looped_back;
        }
 
        dst_input(skb);
-       return 0;
+       return -1;
 }
 
 static struct inet6_protocol rthdr_protocol =
 {
        .handler        =       ipv6_rthdr_rcv,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_rthdr_init(void)
@@ -470,34 +470,6 @@ int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
        return -1;
 }
 
-/* This is fake. We have already parsed hopopts in ipv6_rcv(). -mk */
-static int ipv6_hopopts_rcv(struct sk_buff **skbp)
-{
-       struct sk_buff *skb = *skbp;
-       u8 nexthdr = 0;
-
-       if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
-           !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
-               kfree_skb(skb);
-               return 0;
-       }
-       nexthdr = ((struct ipv6_hopopt_hdr *)skb->h.raw)->nexthdr;
-       skb->h.raw += (skb->h.raw[1]+1)<<3;
-
-       return -nexthdr;
-}
-
-static struct inet6_protocol hopopts_protocol =
-{
-       .handler        =       ipv6_hopopts_rcv,
-};
-
-void __init ipv6_hopopts_init(void)
-{
-       if (inet6_add_protocol(&hopopts_protocol, IPPROTO_HOPOPTS) < 0)
-               printk(KERN_ERR "ipv6_hopopts_init: Could not register protocol\n");
-}
-
 /*
  *     Creating outbound headers.
  *
index 741c6914d8ab6982d1528db03f200e611d15a341..961560fe28d42306c387c756d1cff0b40d374d14 100644 (file)
@@ -74,10 +74,11 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
 static struct socket *__icmpv6_socket[NR_CPUS];
 #define icmpv6_socket  __icmpv6_socket[smp_processor_id()]
 
-static int icmpv6_rcv(struct sk_buff **pskb);
+static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 
 static struct inet6_protocol icmpv6_protocol = {
        .handler        =       icmpv6_rcv,
+       .flags          =       INET6_PROTO_FINAL,
 };
 
 struct icmpv6_msg {
@@ -459,7 +460,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
  *     Handle icmp messages
  */
 
-static int icmpv6_rcv(struct sk_buff **pskb)
+static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *pskb;
        struct net_device *dev = skb->dev;
index ed8efd6a3822bb94beb89dff88d71c63b0bd4892..dad093996eaa1781481b30f92bcfa3b3decd54be 100644 (file)
@@ -17,7 +17,8 @@
  */
 /* Changes
  *
- *     Mitsuru KANDA @USAGI    : Remove ipv6_parse_exthdrs().
+ *     Mitsuru KANDA @USAGI and
+ *     YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
  */
 
 #include <linux/errno.h>
@@ -128,22 +129,34 @@ out:
 
 static inline int ip6_input_finish(struct sk_buff *skb)
 {
-       struct ipv6hdr *hdr = skb->nh.ipv6h;
        struct inet6_protocol *ipprot;
        struct sock *raw_sk;
-       int nexthdr = hdr->nexthdr;
+       unsigned int nhoff;
+       int nexthdr;
        u8 hash;
+       int cksum_sub = 0;
 
        skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
 
-       if (!pskb_pull(skb, skb->h.raw - skb->data))
-               goto discard;
+       /*
+        *      Parse extension headers
+        */
 
-       if (skb->ip_summed == CHECKSUM_HW)
-               skb->csum = csum_sub(skb->csum,
-                                    csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       nhoff = offsetof(struct ipv6hdr, nexthdr);
+
+       /* Skip  hop-by-hop options, they are already parsed. */
+       if (nexthdr == NEXTHDR_HOP) {
+               nhoff = sizeof(struct ipv6hdr);
+               nexthdr = skb->h.raw[0];
+               skb->h.raw += (skb->h.raw[1]+1)<<3;
+       }
 
 resubmit:
+       if (!pskb_pull(skb, skb->h.raw - skb->data))
+               goto discard;
+       nexthdr = skb->nh.raw[nhoff];
+
        raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
        if (raw_sk)
                ipv6_raw_deliver(skb, nexthdr);
@@ -152,23 +165,29 @@ resubmit:
        if ((ipprot = inet6_protos[hash]) != NULL) {
                int ret;
                
-               if (!ipprot->no_policy &&
+               if (ipprot->flags & INET6_PROTO_FINAL) {
+                       if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
+                               skb->csum = csum_sub(skb->csum,
+                                                    csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
+                               cksum_sub++;
+                       }
+               }
+               if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
                    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                        kfree_skb(skb);
                        return 0;
                }
-               ret = ipprot->handler(&skb);
-               if (ret < 0) {
-                       nexthdr = -ret;
+               
+               ret = ipprot->handler(&skb, &nhoff);
+               if (ret > 0)
                        goto resubmit;
-               }
-               IP6_INC_STATS_BH(Ip6InDelivers);
+               else if (ret == 0)
+                       IP6_INC_STATS_BH(Ip6InDelivers);
        } else {
                if (!raw_sk) {
                        if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                                IP6_INC_STATS_BH(Ip6InUnknownProtos);
-                               icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR,
-                                                 offsetof(struct ipv6hdr, nexthdr));
+                               icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
                        }
                } else {
                        IP6_INC_STATS_BH(Ip6InDelivers);
index fd0796806d79817c23ef9176b0c8716190aa6767..cf92a8c4afc6a9158723bf8e0d21fe03511d2f13 100644 (file)
@@ -520,13 +520,13 @@ err:
  *     the last and the first frames arrived and all the bits are here.
  */
 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
+                         unsigned int *nhoffp,
                          struct net_device *dev)
 {
        struct sk_buff *fp, *head = fq->fragments;
        int    remove_fraghdr = 0;
        int    payload_len;
-       int    nhoff;
-       u8     nexthdr = 0;
+       unsigned int nhoff;
 
        fq_kill(fq);
 
@@ -537,8 +537,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
        payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
        nhoff = head->h.raw - head->nh.raw;
 
-       nexthdr = ((struct frag_hdr*)head->h.raw)->nexthdr;
-
        if (payload_len > 65535) {
                payload_len -= 8;
                if (payload_len > 65535)
@@ -613,12 +611,10 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
        if (head->ip_summed == CHECKSUM_HW)
                head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
 
-       if (!pskb_pull(head, head->h.raw - head->data))
-               goto out_fail;
-
        IP6_INC_STATS_BH(Ip6ReasmOKs);
        fq->fragments = NULL;
-       return nexthdr;
+       *nhoffp = nhoff;
+       return 1;
 
 out_oversize:
        if (net_ratelimit())
@@ -629,18 +625,16 @@ out_oom:
                printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
        IP6_INC_STATS_BH(Ip6ReasmFails);
-       return 0;
+       return -1;
 }
 
-static int ipv6_frag_rcv(struct sk_buff **skbp)
+static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *skbp; 
        struct net_device *dev = skb->dev;
        struct frag_hdr *fhdr;
        struct frag_queue *fq;
        struct ipv6hdr *hdr;
-       int nhoff = skb->h.raw - skb->nh.raw;
-       u8 nexthdr = 0;
 
        hdr = skb->nh.ipv6h;
 
@@ -649,23 +643,23 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
        /* Jumbo payload inhibits frag. header */
        if (hdr->payload_len==0) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
-               goto discard;
+               return -1;
        }
        if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
-               goto discard;
+               return -1;
        }
 
        hdr = skb->nh.ipv6h;
        fhdr = (struct frag_hdr *)skb->h.raw;
-       nexthdr = fhdr->nexthdr;
 
        if (!(fhdr->frag_off & htons(0xFFF9))) {
                /* It is not a fragmented frame */
                skb->h.raw += sizeof(struct frag_hdr);
                IP6_INC_STATS_BH(Ip6ReasmOKs);
 
-               return (u8*)fhdr - skb->nh.raw;
+               *nhoffp = (u8*)fhdr - skb->nh.raw;
+               return 1;
        }
 
        if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
@@ -676,26 +670,26 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
 
                spin_lock(&fq->lock);
 
-               ip6_frag_queue(fq, skb, fhdr, nhoff);
+               ip6_frag_queue(fq, skb, fhdr, *nhoffp);
 
                if (fq->last_in == (FIRST_IN|LAST_IN) &&
                    fq->meat == fq->len)
-                       ret = ip6_frag_reasm(fq, skbp, dev);
+                       ret = ip6_frag_reasm(fq, skbp, nhoffp, dev);
 
                spin_unlock(&fq->lock);
                fq_put(fq);
-               return -ret;
+               return ret;
        }
 
-discard:
        IP6_INC_STATS_BH(Ip6ReasmFails);
        kfree_skb(skb);
-       return 0;
+       return -1;
 }
 
 static struct inet6_protocol frag_protocol =
 {
        .handler        =       ipv6_frag_rcv,
+       .flags          =       INET6_PROTO_NOPOLICY,
 };
 
 void __init ipv6_frag_init(void)
index e3a137ba61f705948414b87cfb2becebd04838c6..0c389aa21831edb85dd2610d4dda99b99e60fcb3 100644 (file)
@@ -1591,7 +1591,7 @@ ipv6_pktoptions:
        return 0;
 }
 
-static int tcp_v6_rcv(struct sk_buff **pskb)
+static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *pskb;
        struct tcphdr *th;      
@@ -1657,7 +1657,7 @@ process:
        bh_unlock_sock(sk);
 
        sock_put(sk);
-       return ret;
+       return ret ? -1 : 0;
 
 no_tcp_socket:
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
@@ -2193,7 +2193,7 @@ struct proto tcpv6_prot = {
 static struct inet6_protocol tcpv6_protocol = {
        .handler        =       tcp_v6_rcv,
        .err_handler    =       tcp_v6_err,
-       .no_policy      =       1,
+       .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
 extern struct proto_ops inet6_stream_ops;
index 9632131bb34ab59931e29e61efde657932485960..173aa214e97ff15323914395a2bbbf97937412aa 100644 (file)
@@ -640,7 +640,7 @@ free_skb:
        read_unlock(&udp_hash_lock);
 }
 
-static int udpv6_rcv(struct sk_buff **pskb)
+static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *pskb;
        struct sock *sk;
@@ -954,7 +954,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg
 static struct inet6_protocol udpv6_protocol = {
        .handler        =       udpv6_rcv,
        .err_handler    =       udpv6_err,
-       .no_policy      =       1,
+       .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
 #define LINE_LEN 190
index e54593e58cb996580001a0e9a63808cfc47f45ac..1d5798f7db7b4ca09b122da68b3382ae94573f35 100644 (file)
@@ -123,7 +123,7 @@ int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
        return nexthdr;
 }
 
-int xfrm6_rcv(struct sk_buff **pskb)
+int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
 {
        struct sk_buff *skb = *pskb;
        int err;
@@ -233,6 +233,7 @@ int xfrm6_rcv(struct sk_buff **pskb)
 
        memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
        skb->sp->len += xfrm_nr;
+       skb->ip_summed = CHECKSUM_NONE;
 
        if (decaps) {
                if (!(skb->dev->flags&IFF_LOOPBACK)) {
@@ -240,9 +241,10 @@ int xfrm6_rcv(struct sk_buff **pskb)
                        skb->dst = NULL;
                }
                netif_rx(skb);
-               return 0;
+               return -1;
        } else {
-               return -nexthdr;
+               *nhoffp = nh_offset;
+               return 1;
        }
 
 drop_unlock:
@@ -253,7 +255,7 @@ drop:
        while (--xfrm_nr >= 0)
                xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
        kfree_skb(skb);
-       return 0;
+       return -1;
 }
 
 void __init xfrm6_input_init(void)