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

From: B $B ($B?@ED(B)
Date: Tue Mar 18 2003 - 13:32:27 EST


Hello,

At Wed, 05 Mar 2003 20:43:48 -0800 (PST),
"David S. Miller" <davem@redhat.com> wrote:
>
> From: Kazunori Miyazawa <kazunori@miyazawa.org>
> 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;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Mar 23 2003 - 22:00:24 EST