这个函数中对长度过长的数据包进行了分片,ip_fragment()函数,该函数没有详细分析。


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 long flags;

 /*
  * Point into the IP datagram header.
  */

 raw = skb->data;
 iph = (struct iphdr *) (raw + dev->hard_header_len);

 skb->ip_hdr = iph;

 /*
  * Setup starting values.
  */

 hlen = (iph->ihl * sizeof(unsigned long));
 left = ntohs(iph->tot_len) - hlen; /* Space per frame */
 hlen += dev->hard_header_len;  /* Total header size */
 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 (ntohs(iph->frag_off) & IP_DF)
 {
  /*
   * Reply giving the MTU of the failed hop.
   */
  ip_statistics.IpFragFails++;
  icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev->mtu, dev);
  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) & 0x1fff) << 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,GFP_ATOMIC)) == NULL)
  {
   printk("IP: frag: no memory for new fragment! ");
   ip_statistics.IpFragFails++;
   return;
  }

  /*
   * Set up data on packet
   */

  skb2->arp = skb->arp;
  if(skb->free==0)
   printk("IP fragmenter: BUG free!=1 in fragmenter ");
  skb2->free = 1;
  skb2->len = len + hlen;
  skb2->h.raw=(char *) skb2->data;
  /*
   * Charge the memory for the fragment to any owner
   * it might possess
   */

  save_flags(flags);
  if (sk)
  {
   cli();
   sk->wmem_alloc += skb2->mem_len;
   skb2->sk=sk;
  }
  restore_flags(flags);
  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+=dev->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));
  /*
   * Added AC : If we are fragmenting a fragment thats 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_queue_xmit()函数来发送分片后的数据
 }
 ip_statistics.IpFragOKs++;
}