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

Mitsuru KANDA / =?ISO-2022-JP?B?GyRCP0BFRBsoQiAbJEI9PBsoQg==?= (mk@linux-ipv6.org)
Tue, 18 Mar 2003 10:32:27 -0800


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/