Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Tue, 18 Mar 2003 13:21:57 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Tue, 18 Mar 2003 13:21:56 -0500 Received: from karaba.org ([218.219.152.88]:6291 "EHLO zanzibar.karaba.org") by vger.kernel.org with ESMTP id ; Tue, 18 Mar 2003 13:21:29 -0500 Date: Tue, 18 Mar 2003 10:32:27 -0800 Message-ID: <87of48h6f8.wl@karaba.org> From: Mitsuru KANDA / =?ISO-2022-JP?B?GyRCP0BFRBsoQiAbJEI9PBsoQg==?= To: davem@redhat.com, kuznet@ms2.inr.ac.ru Cc: linux-kernel@vger.kernel.org, netdev@oss.sgi.com, usagi-core@linux-ipv6.org Subject: [PATCH] IPv6 Extension headers (Re: [PATCH] IPv6 IPsec support) In-Reply-To: <20030305.204348.130225511.davem@redhat.com> References: <20030305233025.784feb00.kazunori@miyazawa.org> <20030305.152530.70806720.davem@redhat.com> <20030306093219.1a702868.kazunori@miyazawa.org> <20030305.204348.130225511.davem@redhat.com> MIME-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 22010 Lines: 794 Hello, At Wed, 05 Mar 2003 20:43:48 -0800 (PST), "David S. Miller" wrote: > > From: Kazunori Miyazawa > 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 @@ -44,20 +47,6 @@ #include /* - * 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 #include @@ -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 * Alexey Kuznetsov SMP races, threading, cleanup. * Patrick McHardy LRU queue of frag heads for evictor. + * Mitsuru KANDA @USAGI Register inet6_protocol{}. */ #include #include @@ -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/