patch-2.1.100 linux/net/ipv6/reassembly.c
Next file: linux/net/ipv6/route.c
Previous file: linux/net/ipv6/ndisc.c
Back to the patch index
Back to the overall index
- Lines: 180
- Date:
Sat May 2 14:22:30 1998
- Orig file:
v2.1.99/linux/net/ipv6/reassembly.c
- Orig date:
Tue Mar 17 22:18:16 1998
diff -u --recursive --new-file v2.1.99/linux/net/ipv6/reassembly.c linux/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 @@
* 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 @@
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 @@
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 @@
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 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 @@
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 @@
}
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 @@
/*
* 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;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov