patch-2.1.15 linux/net/ipv4/ip_fragment.c
Next file: linux/net/ipv4/ip_fw.c
Previous file: linux/net/ipv4/ip_forward.c
Back to the patch index
Back to the overall index
- Lines: 352
- Date:
Thu Dec 12 16:54:24 1996
- Orig file:
v2.1.14/linux/net/ipv4/ip_fragment.c
- Orig date:
Tue Oct 29 19:58:49 1996
diff -u --recursive --new-file v2.1.14/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
@@ -24,6 +24,7 @@
#include <net/icmp.h>
#include <linux/tcp.h>
#include <linux/udp.h>
+#include <linux/inet.h>
#include <linux/firewall.h>
#include <linux/ip_fw.h>
#include <net/checksum.h>
@@ -47,6 +48,8 @@
atomic_t ip_frag_mem = 0; /* Memory used for fragments */
+char *in_ntoa(unsigned long in);
+
/*
* Memory Tracking Functions
*/
@@ -208,7 +211,7 @@
/* This if is always true... shrug */
if(qp->fragments!=NULL)
icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, 0, qp->dev);
+ ICMP_EXC_FRAGTIME, 0);
/*
* Nuke the fragment queue.
@@ -238,7 +241,7 @@
* will insert the received fragments at their respective positions.
*/
-static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev)
+static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
{
struct ipq *qp;
int ihlen;
@@ -268,7 +271,7 @@
qp->len = 0;
qp->ihlen = ihlen;
qp->fragments = NULL;
- qp->dev = dev;
+ qp->dev = skb->dev;
/* Start a timer for this entry. */
qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */
@@ -337,7 +340,15 @@
* Allocate a new buffer for the datagram.
*/
len = qp->ihlen + qp->len;
-
+
+ if(len>65535)
+ {
+ printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr));
+ ip_statistics.IpReasmFails++;
+ ip_free(qp);
+ return NULL;
+ }
+
if ((skb = dev_alloc_skb(len)) == NULL)
{
ip_statistics.IpReasmFails++;
@@ -347,13 +358,11 @@
}
/* Fill in the basic details. */
- skb_put(skb,len);
- skb->h.raw = skb->data;
- skb->free = 1;
+ skb->mac.raw = ptr = skb->data;
+ skb->nh.iph = iph = (struct iphdr*)skb_put(skb,len);
/* Copy the original IP headers into the new buffer. */
- ptr = (unsigned char *) skb->h.raw;
- memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
+ memcpy(ptr, qp->iph, qp->ihlen);
ptr += qp->ihlen;
count = 0;
@@ -371,6 +380,10 @@
return NULL;
}
memcpy((ptr + fp->offset), fp->ptr, fp->len);
+ if (!count) {
+ skb->dst = dst_clone(fp->skb->dst);
+ skb->dev = fp->skb->dev;
+ }
count += fp->len;
fp = fp->next;
}
@@ -379,10 +392,9 @@
ip_free(qp);
/* Done with all fragments. Fixup the new IP header. */
- iph = skb->h.iph;
+ iph = skb->nh.iph;
iph->frag_off = 0;
iph->tot_len = htons((iph->ihl * 4) + count);
- skb->ip_hdr = iph;
ip_statistics.IpReasmOKs++;
return(skb);
@@ -393,8 +405,9 @@
* Process an incoming IP datagram fragment.
*/
-struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev)
+struct sk_buff *ip_defrag(struct sk_buff *skb)
{
+ struct iphdr *iph = skb->nh.iph;
struct ipfrag *prev, *next, *tmp;
struct ipfrag *tfp;
struct ipq *qp;
@@ -424,7 +437,7 @@
if (((flags & IP_MF) == 0) && (offset == 0))
{
if (qp != NULL)
- ip_free(qp); /* Huh? How could this exist?? */
+ ip_free(qp); /* Fragmented frame replaced by full unfragmented copy */
return(skb);
}
@@ -458,10 +471,9 @@
/*
* If we failed to create it, then discard the frame
*/
- if ((qp = ip_create(skb, iph, dev)) == NULL)
+ if ((qp = ip_create(skb, iph)) == NULL)
{
- skb->sk = NULL;
- frag_kfree_skb(skb, FREE_READ);
+ kfree_skb(skb, FREE_READ);
ip_statistics.IpReasmFails++;
return NULL;
}
@@ -473,7 +485,7 @@
if(ntohs(iph->tot_len)+(int)offset>65535)
{
- skb->sk = NULL;
+ printk("Oversized packet received from %s\n",in_ntoa(iph->saddr));
frag_kfree_skb(skb, FREE_READ);
ip_statistics.IpReasmFails++;
return NULL;
@@ -573,7 +585,6 @@
if (!tfp)
{
- skb->sk = NULL;
frag_kfree_skb(skb, FREE_READ);
return NULL;
}
@@ -600,200 +611,3 @@
}
return(NULL);
}
-
-
-/*
- * This IP datagram is too large to be sent in one piece. Break it up into
- * smaller pieces (each of size equal to the MAC header plus IP header plus
- * a block of the data of the original IP data part) that will yet fit in a
- * single device frame, and queue such a frame for sending by calling the
- * ip_queue_xmit(). Note that this is recursion, and bad things will happen
- * if this function causes a loop...
- *
- * Yes this is inefficient, feel free to submit a quicker one.
- *
- */
-
-void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
-{
- struct iphdr *iph;
- unsigned char *raw;
- unsigned char *ptr;
- struct sk_buff *skb2;
- int left, mtu, hlen, len;
- int offset;
-
- unsigned short true_hard_header_len;
-
- /*
- * Point into the IP datagram header.
- */
-
- raw = skb->data;
-#if 0
- iph = (struct iphdr *) (raw + dev->hard_header_len);
- skb->ip_hdr = iph;
-#else
- iph = skb->ip_hdr;
-#endif
-
- /*
- * Calculate the length of the link-layer header appended to
- * the IP-packet.
- */
- true_hard_header_len = ((unsigned char *)iph) - raw;
-
- /*
- * Setup starting values.
- */
-
- hlen = iph->ihl * 4;
- left = ntohs(iph->tot_len) - hlen; /* Space per frame */
- hlen += true_hard_header_len;
- mtu = (dev->mtu - hlen); /* Size of data space */
- ptr = (raw + hlen); /* Where to start from */
-
- /*
- * Check for any "DF" flag. [DF means do not fragment]
- */
-
- if (iph->frag_off & htons(IP_DF))
- {
- ip_statistics.IpFragFails++;
- NETDEBUG(printk("ip_queue_xmit: frag needed\n"));
- return;
- }
-
- /*
- * The protocol doesn't seem to say what to do in the case that the
- * frame + options doesn't fit the mtu. As it used to fall down dead
- * in this case we were fortunate it didn't happen
- */
-
- if(mtu<8)
- {
- /* It's wrong but it's better than nothing */
- icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,dev->mtu, dev);
- ip_statistics.IpFragFails++;
- return;
- }
-
- /*
- * Fragment the datagram.
- */
-
- /*
- * The initial offset is 0 for a complete frame. When
- * fragmenting fragments it's wherever this one starts.
- */
-
- if (is_frag & 2)
- offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;
- else
- offset = 0;
-
-
- /*
- * Keep copying data until we run out.
- */
-
- while(left > 0)
- {
- len = left;
- /* IF: it doesn't fit, use 'mtu' - the data space left */
- if (len > mtu)
- len = mtu;
- /* IF: we are not sending upto and including the packet end
- then align the next start on an eight byte boundary */
- if (len < left)
- {
- len/=8;
- len*=8;
- }
- /*
- * Allocate buffer.
- */
-
- if ((skb2 = alloc_skb(len + hlen+15,GFP_ATOMIC)) == NULL)
- {
- NETDEBUG(printk("IP: frag: no memory for new fragment!\n"));
- ip_statistics.IpFragFails++;
- return;
- }
-
- /*
- * Set up data on packet
- */
-
- skb2->arp = skb->arp;
- skb2->protocol = htons(ETH_P_IP); /* Atleast PPP needs this */
-#if 0
- if(skb->free==0)
- printk(KERN_ERR "IP fragmenter: BUG free!=1 in fragmenter\n");
-#endif
- skb2->free = 1;
- skb_put(skb2,len + hlen);
- skb2->h.raw=(char *) skb2->data;
- /*
- * Charge the memory for the fragment to any owner
- * it might possess
- */
-
- if (sk)
- {
- atomic_add(skb2->truesize, &sk->wmem_alloc);
- skb2->sk=sk;
- }
- skb2->raddr = skb->raddr; /* For rebuild_header - must be here */
-
- /*
- * Copy the packet header into the new buffer.
- */
-
- memcpy(skb2->h.raw, raw, hlen);
-
- /*
- * Copy a block of the IP datagram.
- */
- memcpy(skb2->h.raw + hlen, ptr, len);
- left -= len;
-
- skb2->h.raw+=true_hard_header_len;
-
- /*
- * Fill in the new header fields.
- */
- iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
- iph->frag_off = htons((offset >> 3));
- skb2->ip_hdr = iph;
-
- /* ANK: dirty, but effective trick. Upgrade options only if
- * the segment to be fragmented was THE FIRST (otherwise,
- * options are already fixed) and make it ONCE
- * on the initial skb, so that all the following fragments
- * will inherit fixed options.
- */
- if (offset == 0)
- ip_options_fragment(skb);
-
- /*
- * Added AC : If we are fragmenting a fragment that's not the
- * last fragment then keep MF on each bit
- */
- if (left > 0 || (is_frag & 1))
- iph->frag_off |= htons(IP_MF);
- ptr += len;
- offset += len;
-
- /*
- * Put this fragment into the sending queue.
- */
-
- ip_statistics.IpFragCreates++;
-
- ip_queue_xmit(sk, dev, skb2, 2);
- }
- ip_statistics.IpFragOKs++;
-}
-
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov