netdev
[Top] [All Lists]

[PATCH] IPv6 Extension headers (Re: [PATCH] IPv6 IPsec support)

To: davem@xxxxxxxxxx, kuznet@xxxxxxxxxxxxx
Subject: [PATCH] IPv6 Extension headers (Re: [PATCH] IPv6 IPsec support)
From: Mitsuru KANDA / 神田 充 <mk@xxxxxxxxxxxxxx>
Date: Tue, 18 Mar 2003 10:32:27 -0800
Cc: linux-kernel@xxxxxxxxxxxxxxx, netdev@xxxxxxxxxxx, usagi-core@xxxxxxxxxxxxxx
In-reply-to: <20030305.204348.130225511.davem@xxxxxxxxxx>
References: <20030305233025.784feb00.kazunori@xxxxxxxxxxxx> <20030305.152530.70806720.davem@xxxxxxxxxx> <20030306093219.1a702868.kazunori@xxxxxxxxxxxx> <20030305.204348.130225511.davem@xxxxxxxxxx>
Sender: netdev-bounce@xxxxxxxxxxx
Hello,

At Wed, 05 Mar 2003 20:43:48 -0800 (PST),
"David S. Miller" <davem@xxxxxxxxxx> wrote:
> 
>    From: Kazunori Miyazawa <kazunori@xxxxxxxxxxxx>
>    Date: Thu, 6 Mar 2003 09:32:19 +0900
> 
>    - Extension Header Processing on inbound:
>      As a result of IPv6 IPsec support, Extension Header processing is devided
>      into ipv6_parse_exthdrs and ipproto->handler. I think it is better to 
> merge
>      other Extension Header handling into ipproto->handler.
>    
> Ok.

This patch merges inbound IPv6 extension header processing parts into 
inet6_protocols{} like a IPv6 AH/ESP headers.
As a result of this patch, I removed destopt parsing part in xfrm6_rcv()
and removed ipv6_parse_exthdrs().

Could you check this patch?
(This patch is against 2.5.65.)

Best Regards,
-mk

Index: include/net/ipv6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/ipv6.h,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 ipv6.h
--- include/net/ipv6.h  9 Jan 2003 11:14:19 -0000       1.1.1.4
+++ include/net/ipv6.h  18 Mar 2003 05:11:39 -0000
@@ -203,11 +203,7 @@
 
 extern int                     ip6_call_ra_chain(struct sk_buff *skb, int sel);
 
-extern int                     ipv6_reassembly(struct sk_buff **skb, int);
-
 extern int                     ipv6_parse_hopopts(struct sk_buff *skb, int);
-
-extern int                     ipv6_parse_exthdrs(struct sk_buff **skb, int);
 
 extern struct ipv6_txoptions *  ipv6_dup_options(struct sock *sk, struct 
ipv6_txoptions *opt);
 
Index: include/net/protocol.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/protocol.h,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 protocol.h
--- include/net/protocol.h      11 Nov 2002 04:08:20 -0000      1.1.1.3
+++ include/net/protocol.h      18 Mar 2003 05:11:39 -0000
@@ -44,7 +44,7 @@
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct inet6_protocol 
 {
-       int     (*handler)(struct sk_buff *skb);
+       int     (*handler)(struct sk_buff **skbp);
 
        void    (*err_handler)(struct sk_buff *skb,
                               struct inet6_skb_parm *opt,
Index: include/net/transp_v6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/transp_v6.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 transp_v6.h
--- include/net/transp_v6.h     7 Oct 2002 10:22:46 -0000       1.1.1.1
+++ include/net/transp_v6.h     18 Mar 2003 05:11:39 -0000
@@ -15,6 +15,14 @@
 
 struct flowi;
 
+/* extention headers */
+extern void                            ipv6_hopopts_init(void);
+extern void                            ipv6_rthdr_init(void);
+extern void                            ipv6_frag_init(void);
+extern void                            ipv6_nodata_init(void);
+extern void                            ipv6_destopt_init(void);
+
+/* transport protocols */
 extern void                            rawv6_init(void);
 extern void                            udpv6_init(void);
 extern void                            tcpv6_init(void);
Index: include/net/xfrm.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/xfrm.h,v
retrieving revision 1.1.1.8
diff -u -r1.1.1.8 xfrm.h
--- include/net/xfrm.h  13 Mar 2003 17:29:53 -0000      1.1.1.8
+++ include/net/xfrm.h  18 Mar 2003 05:11:39 -0000
@@ -415,7 +415,7 @@
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi 
*fl);
 extern int xfrm4_rcv(struct sk_buff *skb);
-extern int xfrm6_rcv(struct sk_buff *skb);
+extern int xfrm6_rcv(struct sk_buff **pskb);
 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: net/ipv4/xfrm_input.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv4/xfrm_input.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 xfrm_input.c
--- net/ipv4/xfrm_input.c       13 Mar 2003 17:29:03 -0000      1.1.1.4
+++ net/ipv4/xfrm_input.c       18 Mar 2003 05:11:39 -0000
@@ -311,8 +311,9 @@
        return nexthdr;
 }
 
-int xfrm6_rcv(struct sk_buff *skb)
+int xfrm6_rcv(struct sk_buff **pskb)
 {
+       struct sk_buff *skb = *pskb;
        int err;
        u32 spi, seq;
        struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
@@ -325,12 +326,8 @@
        u16 nh_offset = 0;
        u8 nexthdr = 0;
 
-       if (hdr->nexthdr == IPPROTO_AH || hdr->nexthdr == IPPROTO_ESP) {
-               nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - 
skb->nh.raw;
-               hdr_len = sizeof(struct ipv6hdr);
-       } else {
-               hdr_len = skb->h.raw - skb->nh.raw;
-       }
+       nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
+       hdr_len = sizeof(struct ipv6hdr);
 
        tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
        if (!tmp_hdr)
@@ -378,18 +375,6 @@
                xfrm_vec[xfrm_nr++] = x;
 
                iph = skb->nh.ipv6h; /* ??? */ 
-
-               if (nexthdr == NEXTHDR_DEST) {
-                       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))) {
-                               err = -EINVAL;
-                               goto drop;
-                       }
-                       nexthdr = skb->h.raw[0];
-                       nh_offset = skb->h.raw - skb->nh.raw;
-                       skb_pull(skb, (skb->h.raw[1]+1)<<3);
-                       skb->h.raw = skb->data;
-               }
 
                if (x->props.mode) { /* XXX */
                        if (iph->nexthdr != IPPROTO_IPV6)
Index: net/ipv6/af_inet6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/af_inet6.c,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 af_inet6.c
--- net/ipv6/af_inet6.c 25 Feb 2003 05:33:26 -0000      1.1.1.7
+++ net/ipv6/af_inet6.c 18 Mar 2003 05:11:40 -0000
@@ -793,6 +793,13 @@
        addrconf_init();
        sit_init();
 
+       /* Init v6 extention headers. */
+       ipv6_hopopts_init();
+       ipv6_rthdr_init();
+       ipv6_frag_init();
+       ipv6_nodata_init();
+       ipv6_destopt_init();
+
        /* Init v6 transport protocols. */
        udpv6_init();
        tcpv6_init();
Index: net/ipv6/exthdrs.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/exthdrs.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 exthdrs.c
--- net/ipv6/exthdrs.c  20 Feb 2003 08:34:32 -0000      1.1.1.3
+++ net/ipv6/exthdrs.c  18 Mar 2003 05:11:40 -0000
@@ -18,6 +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{}.
  */
 
 #include <linux/errno.h>
@@ -44,20 +47,6 @@
 #include <asm/uaccess.h>
 
 /*
- *     Parsing inbound headers.
- *
- *     Parsing function "func" returns offset wrt skb->nh of the place,
- *     where next nexthdr value is stored or NULL, if parsing
- *     failed. It should also update skb->h tp point at the next header.
- */
-
-struct hdrtype_proc
-{
-       int     type;
-       int     (*func) (struct sk_buff **, int offset);
-};
-
-/*
  *     Parsing tlv encoded headers.
  *
  *     Parsing function "func" returns 1, if parsing succeed
@@ -164,49 +153,77 @@
        {-1,                    NULL}
 };
 
-static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff)
+int ipv6_destopt_rcv(struct sk_buff **skbp) 
 {
-       struct sk_buff *skb=*skb_ptr;
+       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 -1;
+               return 0;
        }
 
+       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 opt->dst1;
+               return -nexthdr;
        }
+                                               
+       return 0;
+}
 
-       return -1;
+static struct inet6_protocol destopt_protocol =
+{
+       .handler        =       ipv6_destopt_rcv,
+};
+
+void __init ipv6_destopt_init(void)
+{
+       if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0) 
+               printk(KERN_ERR "ipv6_destopt_init: Could not register 
protocol\n");
 }
 
 /********************************
   NONE header. No data in packet.
  ********************************/
 
-static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff)
+int ipv6_nodata_rcv(struct sk_buff **skbp)
 {
-       kfree_skb(*skb_ptr);
-       return -1;
+       struct sk_buff *skb = *skbp;
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static struct inet6_protocol nodata_protocol =
+{
+       .handler        =       ipv6_nodata_rcv,
+};
+
+void __init ipv6_nodata_init(void)
+{
+       if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
+               printk(KERN_ERR "ipv6_nodata_init: Could not register 
protocol\n");
 }
 
 /********************************
   Routing header.
  ********************************/
 
-static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff)
+int ipv6_rthdr_rcv(struct sk_buff **skbp)
 {
-       struct sk_buff *skb = *skb_ptr;
+       struct sk_buff *skb = *skbp;
        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
        struct in6_addr *addr;
        struct in6_addr daddr;
        int addr_type;
        int n, i;
+       u8 nexthdr = 0;
 
        struct ipv6_rt_hdr *hdr;
        struct rt0_hdr *rthdr;
@@ -215,15 +232,16 @@
            !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) 
{
                IP6_INC_STATS_BH(Ip6InHdrErrors);
                kfree_skb(skb);
-               return -1;
+               return 0;
        }
 
        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 -1;
+               return 0;
        }
 
 looped_back:
@@ -232,24 +250,24 @@
                skb->h.raw += (hdr->hdrlen + 1) << 3;
                opt->dst0 = opt->dst1;
                opt->dst1 = 0;
-               return (&hdr->nexthdr) - skb->nh.raw;
+               return -nexthdr;
        }
 
        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 -1;
+               return 0;
        }
 
        /*
         *      This is the routing header forwarding algorithm from
-        *      RFC 1883, page 17.
+        *      RFC 2460, page 16.
         */
 
        n = hdr->hdrlen >> 1;
 
        if (hdr->segments_left > n) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) 
- skb->nh.raw);
-               return -1;
+               return 0;
        }
 
        /* We are about to mangle packet header. Be careful!
@@ -259,8 +277,8 @@
                struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
                kfree_skb(skb);
                if (skb2 == NULL)
-                       return -1;
-               *skb_ptr = skb = skb2;
+                       return 0;
+               *skbp = skb = skb2;
                opt = (struct inet6_skb_parm *)skb2->cb;
                hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
        }
@@ -278,7 +296,7 @@
 
        if (addr_type&IPV6_ADDR_MULTICAST) {
                kfree_skb(skb);
-               return -1;
+               return 0;
        }
 
        ipv6_addr_copy(&daddr, addr);
@@ -289,23 +307,34 @@
        ip6_route_input(skb);
        if (skb->dst->error) {
                dst_input(skb);
-               return -1;
+               return 0;
        }
        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 -1;
+                       return 0;
                }
                skb->nh.ipv6h->hop_limit--;
                goto looped_back;
        }
 
        dst_input(skb);
-       return -1;
+       return 0;
 }
 
+static struct inet6_protocol rthdr_protocol =
+{
+       .handler        =       ipv6_rthdr_rcv,
+};
+
+void __init ipv6_rthdr_init(void)
+{
+       if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
+               printk(KERN_ERR "ipv6_rthdr_init: Could not register 
protocol\n");
+};
+
 /*
    This function inverts received rthdr.
    NOTE: specs allow to make it automatically only if
@@ -371,97 +400,6 @@
        return opt;
 }
 
-/********************************
-  AUTH header.
- ********************************/
-
-/*
-   rfc1826 said, that if a host does not implement AUTH header
-   it MAY ignore it. We use this hole 8)
-
-   Actually, now we can implement OSPFv6 without kernel IPsec.
-   Authentication for poors may be done in user space with the same success.
-
-   Yes, it means, that we allow application to send/receive
-   raw authentication header. Apparently, we suppose, that it knows
-   what it does and calculates authentication data correctly.
-   Certainly, it is possible only for udp and raw sockets, but not for tcp.
-
-   AUTH header has 4byte granular length, which kills all the idea
-   behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
-   cpu ticks, checking that sender did not something stupid
-   and opt->hdrlen is even. Shit!              --ANK (980730)
- */
-
-static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff)
-{
-       struct sk_buff *skb=*skb_ptr;
-       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
-       int len;
-
-       if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
-               goto fail;
-
-       /*
-        * RFC2402 2.2 Payload Length
-        * The 8-bit field specifies the length of AH in 32-bit words 
-        * (4-byte units), minus "2".
-        * -- Noriaki Takamiya @USAGI Project
-        */
-       len = (skb->h.raw[1]+2)<<2;
-
-       if (len&7)
-               goto fail;
-
-       if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+len))
-               goto fail;
-
-       opt->auth = skb->h.raw - skb->nh.raw;
-       skb->h.raw += len;
-       return opt->auth;
-
-fail:
-       kfree_skb(skb);
-       return -1;
-}
-
-/* This list MUST NOT contain entry for NEXTHDR_HOP.
-   It is parsed immediately after packet received
-   and if it occurs somewhere in another place we must
-   generate error.
- */
-
-static struct hdrtype_proc hdrproc_lst[] = {
-       {NEXTHDR_FRAGMENT,      ipv6_reassembly},
-       {NEXTHDR_ROUTING,       ipv6_routing_header},
-       {NEXTHDR_DEST,          ipv6_dest_opt},
-       {NEXTHDR_NONE,          ipv6_nodata},
-       {NEXTHDR_AUTH,          ipv6_auth_hdr},
-   /*
-       {NEXTHDR_ESP,           ipv6_esp_hdr},
-    */
-       {-1,                    NULL}
-};
-
-int ipv6_parse_exthdrs(struct sk_buff **skb_in, int nhoff)
-{
-       struct hdrtype_proc *hdrt;
-       u8 nexthdr = (*skb_in)->nh.raw[nhoff];
-
-restart:
-       for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
-               if (hdrt->type == nexthdr) {
-                       if ((nhoff = hdrt->func(skb_in, nhoff)) >= 0) {
-                               nexthdr = (*skb_in)->nh.raw[nhoff];
-                               goto restart;
-                       }
-                       return -1;
-               }
-       }
-       return nhoff;
-}
-
-
 /**********************************
   Hop-by-hop options.
  **********************************/
@@ -530,6 +468,34 @@
        if (ip6_parse_tlv(tlvprochopopt_lst, skb))
                return sizeof(struct ipv6hdr);
        return -1;
+}
+
+/* This is fake. We have already parsed hopopts in ipv6_rcv(). -mk */
+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");
 }
 
 /*
Index: net/ipv6/icmp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/icmp.c,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 icmp.c
--- net/ipv6/icmp.c     13 Mar 2003 17:29:06 -0000      1.1.1.7
+++ net/ipv6/icmp.c     18 Mar 2003 05:11:40 -0000
@@ -74,7 +74,7 @@
 static struct socket *__icmpv6_socket[NR_CPUS];
 #define icmpv6_socket  __icmpv6_socket[smp_processor_id()]
 
-static int icmpv6_rcv(struct sk_buff *skb);
+static int icmpv6_rcv(struct sk_buff **pskb);
 
 static struct inet6_protocol icmpv6_protocol = {
        .handler        =       icmpv6_rcv,
@@ -458,8 +458,9 @@
  *     Handle icmp messages
  */
 
-static int icmpv6_rcv(struct sk_buff *skb)
+static int icmpv6_rcv(struct sk_buff **pskb)
 {
+       struct sk_buff *skb = *pskb;
        struct net_device *dev = skb->dev;
        struct in6_addr *saddr, *daddr;
        struct ipv6hdr *orig_hdr;
Index: net/ipv6/ip6_input.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ip6_input.c,v
retrieving revision 1.1.1.6
diff -u -r1.1.1.6 ip6_input.c
--- net/ipv6/ip6_input.c        13 Mar 2003 17:29:06 -0000      1.1.1.6
+++ net/ipv6/ip6_input.c        18 Mar 2003 05:11:40 -0000
@@ -15,6 +15,10 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
+/* Changes
+ *
+ *     Mitsuru KANDA @USAGI    : Remove ipv6_parse_exthdrs().
+ */
 
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -127,38 +131,11 @@
        struct inet6_protocol *ipprot;
        struct sock *raw_sk;
        int nhoff;
-       int nexthdr;
+       int nexthdr = hdr->nexthdr;
        u8 hash;
 
        skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
 
-       /*
-        *      Parse extension headers
-        */
-
-       nexthdr = hdr->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;
-       }
-
-       /* This check is sort of optimization.
-          It would be stupid to detect for optional headers,
-          which are missing with probability of 200%
-        */
-       if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP &&
-           nexthdr != NEXTHDR_AUTH && nexthdr != NEXTHDR_ESP) {
-               nhoff = ipv6_parse_exthdrs(&skb, nhoff);
-               if (nhoff < 0)
-                       return 0;
-               nexthdr = skb->nh.raw[nhoff];
-               hdr = skb->nh.ipv6h;
-       }
-
        if (!pskb_pull(skb, skb->h.raw - skb->data))
                goto discard;
 
@@ -173,7 +150,7 @@
 
        hash = nexthdr & (MAX_INET_PROTOS - 1);
        if ((ipprot = inet6_protos[hash]) != NULL) {
-               int ret = ipprot->handler(skb);
+               int ret = ipprot->handler(&skb);
                if (ret < 0) {
                        nexthdr = -ret;
                        goto resubmit;
@@ -182,6 +159,7 @@
        } else {
                if (!raw_sk) {
                        IP6_INC_STATS_BH(Ip6InUnknownProtos);
+                       nhoff = offsetof(struct ipv6hdr, nexthdr);
                        icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
                } else {
                        IP6_INC_STATS_BH(Ip6InDelivers);
Index: net/ipv6/reassembly.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/reassembly.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 reassembly.c
--- net/ipv6/reassembly.c       20 Feb 2003 08:34:32 -0000      1.1.1.4
+++ net/ipv6/reassembly.c       18 Mar 2003 05:11:40 -0000
@@ -23,6 +23,7 @@
  *      Horst von Brand Add missing #include <linux/string.h>
  *     Alexey Kuznetsov        SMP races, threading, cleanup.
  *     Patrick McHardy         LRU queue of frag heads for evictor.
+ *     Mitsuru KANDA @USAGI    Register inet6_protocol{}.
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -525,6 +526,7 @@
        int    remove_fraghdr = 0;
        int    payload_len;
        int    nhoff;
+       u8     nexthdr = 0;
 
        fq_kill(fq);
 
@@ -535,6 +537,8 @@
        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)
@@ -609,9 +613,13 @@
        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 nhoff;
+       return nexthdr;
 
 out_oversize:
        if (net_ratelimit())
@@ -622,16 +630,18 @@
                printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
        IP6_INC_STATS_BH(Ip6ReasmFails);
-       return -1;
+       return 0;
 }
 
-int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
+int ipv6_frag_rcv(struct sk_buff **skbp)
 {
        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;
 
@@ -640,15 +650,16 @@
        /* Jumbo payload inhibits frag. header */
        if (hdr->payload_len==0) {
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 
skb->h.raw-skb->nh.raw);
-               return -1;
+               goto discard;
        }
        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);
-               return -1;
+               goto discard;
        }
 
        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 */
@@ -674,10 +685,22 @@
 
                spin_unlock(&fq->lock);
                fq_put(fq);
-               return ret;
+               return -ret;
        }
 
+discard:
        IP6_INC_STATS_BH(Ip6ReasmFails);
        kfree_skb(skb);
-       return -1;
+       return 0;
+}
+
+static struct inet6_protocol frag_protocol =
+{
+       .handler        =       ipv6_frag_rcv,
+};
+
+void __init ipv6_frag_init(void)
+{
+       if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0)
+               printk(KERN_ERR "ipv6_frag_init: Could not register 
protocol\n");
 }
Index: net/ipv6/tcp_ipv6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/tcp_ipv6.c,v
retrieving revision 1.1.1.8
diff -u -r1.1.1.8 tcp_ipv6.c
--- net/ipv6/tcp_ipv6.c 13 Mar 2003 17:29:06 -0000      1.1.1.8
+++ net/ipv6/tcp_ipv6.c 18 Mar 2003 05:11:40 -0000
@@ -1591,8 +1591,9 @@
        return 0;
 }
 
-static int tcp_v6_rcv(struct sk_buff *skb)
+static int tcp_v6_rcv(struct sk_buff **pskb)
 {
+       struct sk_buff *skb = *pskb;
        struct tcphdr *th;      
        struct sock *sk;
        int ret;
Index: net/ipv6/udp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/udp.c,v
retrieving revision 1.1.1.7
diff -u -r1.1.1.7 udp.c
--- net/ipv6/udp.c      13 Mar 2003 17:29:06 -0000      1.1.1.7
+++ net/ipv6/udp.c      18 Mar 2003 05:11:40 -0000
@@ -641,8 +641,9 @@
        read_unlock(&udp_hash_lock);
 }
 
-static int udpv6_rcv(struct sk_buff *skb)
+static int udpv6_rcv(struct sk_buff **pskb)
 {
+       struct sk_buff *skb = *pskb;
        struct sock *sk;
        struct udphdr *uh;
        struct net_device *dev = skb->dev;


<Prev in Thread] Current Thread [Next in Thread>