diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /net/ipv6/reassembly.c | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r-- | net/ipv6/reassembly.c | 79 |
1 files changed, 61 insertions, 18 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 55fecc676..e78cf97a2 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: reassembly.c,v 1.9 1998/02/12 07:43:48 davem Exp $ + * $Id: reassembly.c,v 1.10 1998/04/30 16:24:32 freitag Exp $ * * Based on: net/ipv4/ip_fragment.c * @@ -15,6 +15,11 @@ * 2 of the License, or (at your option) any later version. */ +/* + * Fixes: + * Andi Kleen Make it work with multiple hosts. + * More RFC compliance. + */ #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> @@ -39,8 +44,9 @@ static struct frag_queue ipv6_frag_queue = { &ipv6_frag_queue, &ipv6_frag_queue, - 0, {0}, NULL, NULL, - 0 + 0, {{{0}}}, {{{0}}}, + {0}, NULL, NULL, + 0, 0, NULL }; static void create_frag_entry(struct sk_buff *skb, @@ -72,12 +78,11 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb, * one it's the kmalloc for a struct ipv6_frag. * Feel free to try other alternatives... */ - reasm_queue(fq, *skb, fhdr); - if ((fhdr->frag_off & __constant_htons(0x0001)) == 0) { fq->last_in = 1; fq->nhptr = nhptr; } + reasm_queue(fq, *skb, fhdr); if (fq->last_in) { if ((nh = reasm_frag_1(fq, skb))) @@ -90,18 +95,27 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb, return 0; } -int ipv6_reassembly(struct sk_buff **skb, struct device *dev, __u8 *nhptr, +int ipv6_reassembly(struct sk_buff **skbp, struct device *dev, __u8 *nhptr, struct ipv6_options *opt) { - struct frag_hdr *fhdr = (struct frag_hdr *) ((*skb)->h.raw); + struct sk_buff *skb = *skbp; + struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw); struct frag_queue *fq; - + struct ipv6hdr *hdr; + + if ((u8 *)(fhdr+1) > skb->tail) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw); + return 0; + } + hdr = skb->nh.ipv6h; for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) { - if (fq->id == fhdr->identification) - return reasm_frag(fq, skb, nhptr,fhdr); + if (fq->id == fhdr->identification && + !ipv6_addr_cmp(&hdr->saddr, &fq->saddr) && + !ipv6_addr_cmp(&hdr->daddr, &fq->daddr)) + return reasm_frag(fq, skbp, nhptr,fhdr); } - create_frag_entry(*skb, dev, nhptr, fhdr); + create_frag_entry(skb, dev, nhptr, fhdr); return 0; } @@ -154,6 +168,7 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, struct frag_hdr *fhdr) { struct frag_queue *fq; + struct ipv6hdr *hdr; fq = (struct frag_queue *) kmalloc(sizeof(struct frag_queue), GFP_ATOMIC); @@ -167,6 +182,10 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, fq->id = fhdr->identification; + hdr = skb->nh.ipv6h; + ipv6_addr_copy(&fq->saddr, &hdr->saddr); + ipv6_addr_copy(&fq->daddr, &hdr->daddr); + fq->dev = dev; /* init_timer has been done by the memset */ @@ -193,14 +212,14 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev, static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr) + struct frag_hdr *fhdr) { struct ipv6_frag *nfp, *fp, **bptr; nfp = (struct ipv6_frag *) kmalloc(sizeof(struct ipv6_frag), GFP_ATOMIC); - if (nfp == NULL) { + if (nfp == NULL) { kfree_skb(skb); return; } @@ -209,6 +228,10 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, nfp->len = (ntohs(skb->nh.ipv6h->payload_len) - ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1))); + if ((u32)nfp->offset + (u32)nfp->len > 65536) { + icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off); + goto err; + } nfp->skb = skb; nfp->fhdr = fhdr; @@ -224,19 +247,37 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, } if (fp && fp->offset == nfp->offset) { - if (fp->len != nfp->len) { - /* this cannot happen */ + if (nfp->len != fp->len) { printk(KERN_DEBUG "reasm_queue: dup with wrong len\n"); } /* duplicate. discard it. */ - kfree_skb(skb); - kfree(nfp); - return; + goto err; } *bptr = nfp; nfp->next = fp; + +#ifdef STRICT_RFC + if (fhdr->frag_off & __constant_htons(0x0001)) { + /* Check if the fragment is rounded to 8 bytes. + * Required by the RFC. + */ + if (nfp->len & 0x7) { + printk(KERN_DEBUG "fragment not rounded to 8bytes\n"); + + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, + &skb->nh.ipv6h->payload_len); + goto err; + } + } +#endif + + return; + +err: + kfree(nfp); + kfree_skb(skb); } /* @@ -303,6 +344,8 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in) /* * FIXME: If we don't have a checksum we ought to be able * to defragment and checksum in this pass. [AC] + * Note that we don't really know yet whether the protocol + * needs checksums at all. It might still be a good idea. -AK */ for(fp = fq->fragments; fp; ) { struct ipv6_frag *back; |