Beispiel #1
0
/* Remove an entry from the "incomplete datagrams" queue, either
 * because we completed, reassembled and processed it, or because
 * it timed out.
 *
 * This is called _only_ from BH contexts, on packet reception
 * processing and from frag queue expiration timers.  -DaveM
 */
static void ip_free(struct ipq *qp)
{
	struct ipfrag *fp;

	/* Stop the timer for this entry. */
	del_timer(&qp->timer);

	/* Remove this entry from the "incomplete datagrams" queue. */
	if(qp->next)
		qp->next->pprev = qp->pprev;
	*qp->pprev = qp->next;

	/* Release all fragment data. */
	fp = qp->fragments;
	while (fp) {
		struct ipfrag *xp = fp->next;

		frag_kfree_skb(fp->skb);
		frag_kfree_s(fp, sizeof(struct ipfrag));
		fp = xp;
	}

	/* Release the IP header. */
	frag_kfree_s(qp->iph, 64 + 8);

	/* Finally, release the queue descriptor itself. */
	frag_kfree_s(qp, sizeof(struct ipq));
}
Beispiel #2
0
// 从当前host中删除掉一个给定的ip报文队列
static void
ip_free(struct ipq * qp)
{
	struct ipfrag *fp;
	struct ipfrag *xp;

	/* Stop the timer for this entry. */
	del_timer(&qp->timer);

	/* Remove this entry from the "incomplete datagrams" queue. */

	// 如果队列是host中的第一个队列
	if (qp->prev == NULL)
	{
		this_host->ipqueue = qp->next;
		// 如果后面还有,则修改后面一个为第一个
		if (this_host->ipqueue != NULL)
			this_host->ipqueue->prev = NULL;
		// 否则该删除的队列是最后一个,说明host已经没有队列了,删除host
		else
			rmthis_host();
	}
	// 否则不是第一个
	else
	{
		qp->prev->next = qp->next;
		// 如果不是最后一个,修改后一个的指针
		if (qp->next != NULL)
			qp->next->prev = qp->prev;
	}
	
	/* Release all fragment data. */
	// 将这一个队列中所有的fragments全部释放掉
	fp = qp->fragments;
	while (fp != NULL)
	{
		xp = fp->next;
		// 释放ipfrag中的ksb
		frag_kfree_skb(fp->skb, FREE_READ);
		// 再释放ipfrag结构
		frag_kfree_s(fp, sizeof(struct ipfrag));
		fp = xp;
	}
	
	/* Release the IP header. */
	frag_kfree_s(qp->iph, 64 + 8);

	/* Finally, release the queue descriptor itself. */
	frag_kfree_s(qp, sizeof(struct ipq));
}
Beispiel #3
0
// 疑问: 这一个应该要修改this_host的 ip_frag_mem变量吧????
// 输入:
//      ip头
// 返回:
//      ip队列,这个ip队列已经被挂载到host上了
static struct ipq *
ip_create(struct ip * iph)
{
	struct ipq *qp;
	int ihlen;

	// 调用malloc,申请一个空间
	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	if (qp == NULL)
	{
		// NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		return (NULL);
	}
	// 填充为0
	memset(qp, 0, sizeof(struct ipq));

	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
	// 多分配8字节,需要保存ip头以及头后面8字节,因为icmp的内容就是ip头+8字节
	ihlen = iph->ip_hl * 4;
	qp->iph = (struct ip *) frag_kmalloc(64 + 8, GFP_ATOMIC);
	if (qp->iph == NULL)
	{
		//NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		frag_kfree_s(qp, sizeof(struct ipq));
		return (NULL);
	}
	// 将ip头+8字节的内容保存在iph变量中。
	// 到时候iph变量就能够直接作为icmp的内容,如果有必要发送icmp的话
	memcpy(qp->iph, iph, ihlen + 8);
	// 队列长度=0, 头长度,碎片队列
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
	// 挂载到当前host上
	qp->hf = this_host;

	/* Start a timer for this entry. */
	// jiffies函数返回当前时间,毫秒为单位
	qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds     */
	// 设置关联
	qp->timer.data = (unsigned long) qp;	/* pointer to queue     */
	// 注册一个超时函数,当超时的时候,会回调这个函数
	qp->timer.function = ip_expire;	/* expire function      */
	// 将这个timer挂载到queue上
	add_timer(&qp->timer);

	/* Add this entry to the queue. */
	// 将这个队列挂载到当前host上
	qp->prev = NULL;
	qp->next = this_host->ipqueue;
	if (qp->next != NULL)
		qp->next->prev = qp;
	this_host->ipqueue = qp;

	return (qp);
}
Beispiel #4
0
/*
  Remove an entry from the "incomplete datagrams" queue, either
  because we completed, reassembled and processed it, or because it
  timed out.
*/
static void
//! ip_free(struct ipq * qp)
ip_free(struct ipq * qp,IP_THREAD_LOCAL_P  ip_thread_local_p)
{
	struct ipfrag *fp;
	struct ipfrag *xp;

	/* Stop the timer for this entry. */
//!   del_timer(&qp->timer);
	del_timer(&qp->timer,ip_thread_local_p);

	/* Remove this entry from the "incomplete datagrams" queue. */
	if (qp->prev == NULL) {
//!     this_host->ipqueue = qp->next;
		ip_thread_local_p->this_host->ipqueue = qp->next;
//!     if (this_host->ipqueue != NULL)
		if (ip_thread_local_p->this_host->ipqueue != NULL)
//!       this_host->ipqueue->prev = NULL;
			ip_thread_local_p->this_host->ipqueue->prev = NULL;
		else
//!       rmthis_host();

			rmthis_host(ip_thread_local_p);
	} else {
		qp->prev->next = qp->next;
		if (qp->next != NULL)
			qp->next->prev = qp->prev;
	}
	/* Release all fragment data. */
	fp = qp->fragments;
	while (fp != NULL) {
		xp = fp->next;
//!     frag_kfree_skb(fp->skb, FREE_READ);
		frag_kfree_skb(fp->skb, FREE_READ,ip_thread_local_p);
//!     frag_kfree_s(fp, sizeof(struct ipfrag));
		frag_kfree_s(fp, sizeof(struct ipfrag),ip_thread_local_p);
		fp = xp;
	}
	/* Release the IP header. */
	frag_kfree_s(qp->iph, 64 + 8, ip_thread_local_p);

	/* Finally, release the queue descriptor itself. */
//!   frag_kfree_s(qp, sizeof(struct ipq));
	frag_kfree_s(qp, sizeof(struct ipq),ip_thread_local_p);
}
Beispiel #5
0
static void ip_free(struct ipq *qp)
{
	struct ipfrag *fp;
	struct ipfrag *xp;

	/*
	 * Stop the timer for this entry.
	 */

	del_timer(&qp->timer);

	/* Remove this entry from the "incomplete datagrams" queue. */
	cli();
	if (qp->prev == NULL)
	{
		ipqueue = qp->next;
		if (ipqueue != NULL)
			ipqueue->prev = NULL;
	}
	else
	{
		qp->prev->next = qp->next;
		if (qp->next != NULL)
			qp->next->prev = qp->prev;
	}

	/* Release all fragment data. */

	fp = qp->fragments;
	while (fp != NULL)
	{
		xp = fp->next;
		IS_SKB(fp->skb);
		frag_kfree_skb(fp->skb,FREE_READ);
		frag_kfree_s(fp, sizeof(struct ipfrag));
		fp = xp;
	}

	/* Release the IP header. */
	frag_kfree_s(qp->iph, 64 + 8);

	/* Finally, release the queue descriptor itself. */
	frag_kfree_s(qp, sizeof(struct ipq));
	sti();
}
Beispiel #6
0
static void fq_free(struct frag_queue *fq)
{
	struct ipv6_frag *fp, *back;

	del_timer(&fq->timer);

	for (fp = fq->fragments; fp; ) {
		frag_kfree_skb(fp->skb);
		back = fp;
		fp=fp->next;
		frag_kfree_s(back, sizeof(*back));
	}

	fq->prev->next = fq->next;
	fq->next->prev = fq->prev;

	fq->prev = fq->next = NULL;
	
	frag_kfree_s(fq, sizeof(*fq));
}
Beispiel #7
0
/*
  Add an entry to the 'ipq' queue for a newly received IP datagram.
  We will (hopefully :-) receive all other fragments of this datagram
  in time, so we just create a queue for this datagram, in which we
  will insert the received fragments at their respective positions.
*/
static struct ipq *
//! ip_create(struct ip * iph)
			ip_create(struct ip * iph,IP_THREAD_LOCAL_P  ip_thread_local_p) {
	struct ipq *qp;
	int ihlen;

//!   qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC,ip_thread_local_p);
	if (qp == NULL) {
		// NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		return (NULL);
	}
	memset(qp, 0, sizeof(struct ipq));

	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
	ihlen = iph->ip_hl * 4;
	qp->iph = (struct ip *) frag_kmalloc(64 + 8, GFP_ATOMIC, ip_thread_local_p);
	if (qp->iph == NULL) {
		//NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
//!     frag_kfree_s(qp, sizeof(struct ipq));
		frag_kfree_s(qp, sizeof(struct ipq),ip_thread_local_p);
		return (NULL);
	}
	memcpy(qp->iph, iph, ihlen + 8);
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
//!   qp->hf = this_host;
	qp->hf = ip_thread_local_p->this_host;

	/* Start a timer for this entry. */
//!   qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds     */
	qp->timer.expires = jiffies(ip_thread_local_p) + IP_FRAG_TIME;	/* about 30 seconds     */
	qp->timer.data = (unsigned long) qp;	/* pointer to queue     */
	qp->timer.function = ip_expire;	/* expire function      */
//!   add_timer(&qp->timer);
	add_timer(&qp->timer,ip_thread_local_p);

	/* Add this entry to the queue. */
	qp->prev = NULL;
//!   qp->next = this_host->ipqueue;
	qp->next = ip_thread_local_p->this_host->ipqueue;
	if (qp->next != NULL)
		qp->next->prev = qp;
//!   this_host->ipqueue = qp;
	ip_thread_local_p->this_host->ipqueue = qp;

	return (qp);
}
Beispiel #8
0
static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev)
{
	struct ipq *qp;
	int ihlen;

	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	if (qp == NULL)
	{
		NETDEBUG(printk("IP: create: no memory left !\n"));
		return(NULL);
	}
	memset(qp, 0, sizeof(struct ipq));

	/*
	 *	Allocate memory for the IP header (plus 8 octets for ICMP).
	 */

	ihlen = iph->ihl * 4;
	qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
	if (qp->iph == NULL)
	{
		NETDEBUG(printk("IP: create: no memory left !\n"));
		frag_kfree_s(qp, sizeof(struct ipq));
		return(NULL);
	}

	memcpy(qp->iph, iph, ihlen + 8);
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
	qp->dev = dev;

	/* Start a timer for this entry. */
	qp->timer.expires = jiffies + IP_FRAG_TIME;	/* about 30 seconds	*/
	qp->timer.data = (unsigned long) qp;		/* pointer to queue	*/
	qp->timer.function = ip_expire;			/* expire function	*/
	add_timer(&qp->timer);

	/* Add this entry to the queue. */
	qp->prev = NULL;
	cli();
	qp->next = ipqueue;
	if (qp->next != NULL)
		qp->next->prev = qp;
	ipqueue = qp;
	sti();
	return(qp);
}
Beispiel #9
0
/* Add an entry to the 'ipq' queue for a newly received IP datagram.
 * We will (hopefully :-) receive all other fragments of this datagram
 * in time, so we just create a queue for this datagram, in which we
 * will insert the received fragments at their respective positions.
 */
static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
{
	struct ipq *qp;
	unsigned int hash;
	int ihlen;

	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	if (qp == NULL)
		goto out_nomem;

	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
	ihlen = iph->ihl * 4;

	qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
	if (qp->iph == NULL)
		goto out_free;

	memcpy(qp->iph, iph, ihlen + 8);
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
	qp->dev = skb->dev;

	/* Initialize a timer for this entry. */
	init_timer(&qp->timer);
	qp->timer.expires = 0;			/* (to be set later)	*/
	qp->timer.data = (unsigned long) qp;	/* pointer to queue	*/
	qp->timer.function = ip_expire;		/* expire function	*/

	/* Add this entry to the queue. */
	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);

	/* We are in a BH context, no locking necessary.  -DaveM */
	if((qp->next = ipq_hash[hash]) != NULL)
		qp->next->pprev = &qp->next;
	ipq_hash[hash] = qp;
	qp->pprev = &ipq_hash[hash];

	return qp;

out_free:
	frag_kfree_s(qp, sizeof(struct ipq));
out_nomem:
	NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
	return(NULL);
}
Beispiel #10
0
static void create_frag_entry(struct sk_buff *skb,
			      __u8 *nhptr,
			      struct frag_hdr *fhdr)
{
	struct frag_queue *fq;
	struct ipv6hdr *hdr; 

	fq = (struct frag_queue *) frag_kmalloc(sizeof(struct frag_queue), 
						GFP_ATOMIC);

	if (fq == NULL) {
		ipv6_statistics.Ip6ReasmFails++;
		kfree_skb(skb);
		return;
	}

	memset(fq, 0, sizeof(struct frag_queue));

	fq->id = fhdr->identification;

	hdr = skb->nh.ipv6h;
	ipv6_addr_copy(&fq->saddr, &hdr->saddr);
	ipv6_addr_copy(&fq->daddr, &hdr->daddr);

	/* init_timer has been done by the memset */
	fq->timer.function = frag_expire;
	fq->timer.data = (long) fq;
	fq->timer.expires = jiffies + sysctl_ip6frag_time;

	reasm_queue(fq, skb, fhdr, nhptr);

	if (fq->fragments) {
		fq->prev = ipv6_frag_queue.prev;
		fq->next = &ipv6_frag_queue;
		fq->prev->next = fq;
		ipv6_frag_queue.prev = fq;

		add_timer(&fq->timer);
	} else
		frag_kfree_s(fq, sizeof(*fq));
}
Beispiel #11
0
/* Process an incoming IP datagram fragment. */
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
  struct ipfrag *prev, *next, *tmp;
  struct ipfrag *tfp;
  struct ipq *qp;
  char *skb2;
  unsigned char *ptr;
  int flags, offset;
  int i, ihl, end;

  if (!hostfrag_find(iph) && skb)
    hostfrag_create(iph);

  /* Start by cleaning up the memory. */
  if (this_host)
    if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
      ip_evictor();

  /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
  if (this_host)
    qp = ip_find(iph);
  else
    qp = 0;

  /* Is this a non-fragmented datagram? */
  offset = ntohs(iph->ip_off);
  flags = offset & ~IP_OFFSET;
  offset &= IP_OFFSET;
  if (((flags & IP_MF) == 0) && (offset == 0)) {
    if (qp != NULL)
      ip_free(qp);		/* Fragmented frame replaced by full
				   unfragmented copy */
    return 0;
  }

  /* ip_evictor() could have removed all queues for the current host */
  if (!this_host)
    hostfrag_create(iph);

  offset <<= 3;			/* offset is in 8-byte chunks */
  ihl = iph->ip_hl * 4;

  /*
    If the queue already existed, keep restarting its timer as long as
    we still are receiving fragments.  Otherwise, create a fresh queue
    entry.
  */
  if (qp != NULL) {
    /* ANK. If the first fragment is received, we should remember the correct
       IP header (with options) */
    if (offset == 0) {
      qp->ihlen = ihl;
      memcpy(qp->iph, iph, ihl + 8);
    }
    del_timer(&qp->timer);
    qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
    qp->timer.data = (unsigned long) qp;	/* pointer to queue */
    qp->timer.function = ip_expire;	/* expire function */
    add_timer(&qp->timer);
  }
  else {
    /* If we failed to create it, then discard the frame. */
    if ((qp = ip_create(iph)) == NULL) {
      kfree_skb(skb, FREE_READ);
      return NULL;
    }
  }
  /* Attempt to construct an oversize packet. */
  if (ntohs(iph->ip_len) + (int) offset > 65535) {
    // NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* Determine the position of this fragment. */
  end = offset + ntohs(iph->ip_len) - ihl;

  /* Point into the IP datagram 'data' part. */
  ptr = (unsigned char *)(skb->data + ihl);

  /* Is this the final fragment? */
  if ((flags & IP_MF) == 0)
    qp->len = end;

  /*
    Find out which fragments are in front and at the back of us in the
    chain of fragments so far.  We must know where to put this
    fragment, right?
  */
  prev = NULL;
  for (next = qp->fragments; next != NULL; next = next->next) {
    if (next->offset >= offset)
      break;			/* bingo! */
    prev = next;
  }
  /*
    We found where to put this one.  Check for overlap with preceding
    fragment, and, if needed, align things so that any overlaps are
    eliminated.
  */
  if (prev != NULL && offset < prev->end) {
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
    i = prev->end - offset;
    offset += i;		/* ptr into datagram */
    ptr += i;			/* ptr into fragment data */
  }
  /*
    Look for overlap with succeeding segments.
    If we can merge fragments, do it.
  */
  for (tmp = next; tmp != NULL; tmp = tfp) {
    tfp = tmp->next;
    if (tmp->offset >= end)
      break;			/* no overlaps at all */
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);

    i = end - next->offset;	/* overlap is 'i' bytes */
    tmp->len -= i;		/* so reduce size of    */
    tmp->offset += i;		/* next fragment        */
    tmp->ptr += i;
    /*
      If we get a frag size of <= 0, remove it and the packet that it
      goes with. We never throw the new frag away, so the frag being
      dumped has always been charged for.
    */
    if (tmp->len <= 0) {
      if (tmp->prev != NULL)
	tmp->prev->next = tmp->next;
      else
	qp->fragments = tmp->next;

      if (tmp->next != NULL)
	tmp->next->prev = tmp->prev;

      next = tfp;		/* We have killed the original next frame */

      frag_kfree_skb(tmp->skb, FREE_READ);
      frag_kfree_s(tmp, sizeof(struct ipfrag));
    }
  }
  /* Insert this fragment in the chain of fragments. */
  tfp = NULL;
  tfp = ip_frag_create(offset, end, skb, ptr);

  /*
    No memory to save the fragment - so throw the lot. If we failed
    the frag_create we haven't charged the queue.
  */
  if (!tfp) {
    nids_params.no_mem("ip_defrag");
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* From now on our buffer is charged to the queues. */
  tfp->prev = prev;
  tfp->next = next;
  if (prev != NULL)
    prev->next = tfp;
  else
    qp->fragments = tfp;

  if (next != NULL)
    next->prev = tfp;

  /*
    OK, so we inserted this new fragment into the chain.  Check if we
    now have a full IP datagram which we can bump up to the IP
    layer...
  */
  if (ip_done(qp)) {
    skb2 = ip_glue(qp);		/* glue together the fragments */
    fprintf(stderr,"this is ipfragment.sd");
	return (skb2);
  }
  return (NULL);
}
Beispiel #12
0
/* Process an incoming IP datagram fragment. */
struct sk_buff *ip_defrag(struct sk_buff *skb)
{
	struct iphdr *iph = skb->nh.iph;
	struct ipfrag *prev, *next, *tmp, *tfp;
	struct ipq *qp;
	unsigned char *ptr;
	int flags, offset;
	int i, ihl, end;
	
	ip_statistics.IpReasmReqds++;

	/* Start by cleaning up the memory. */
	if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
		ip_evictor();

	/*
	 * Look for the entry for this IP datagram in the
	 * "incomplete datagrams" queue. If found, the
	 * timer is removed.
	 */
	qp = ip_find(iph, skb->dst);

	/* Is this a non-fragmented datagram? */
	offset = ntohs(iph->frag_off);
	flags = offset & ~IP_OFFSET;
	offset &= IP_OFFSET;

	offset <<= 3;		/* offset is in 8-byte chunks */
	ihl = iph->ihl * 4;

	/*
	 * Check whether to create a fresh queue entry. If the
	 * queue already exists, its timer will be restarted as
	 * long as we continue to receive fragments.
	 */
	if (qp) {
		/* ANK. If the first fragment is received,
		 * we should remember the correct IP header (with options)
		 */
	        if (offset == 0) {
			/* Fragmented frame replaced by unfragmented copy? */
			if ((flags & IP_MF) == 0)
				goto out_freequeue;
			qp->ihlen = ihl;
			memcpy(qp->iph, iph, (ihl + 8));
		}
	} else {
		/* Fragmented frame replaced by unfragmented copy? */
		if ((offset == 0) && ((flags & IP_MF) == 0))
			goto out_skb;

		/* If we failed to create it, then discard the frame. */
		qp = ip_create(skb, iph);
		if (!qp)
			goto out_freeskb;
	}
	
	/* Attempt to construct an oversize packet. */
	if((ntohs(iph->tot_len) + ((int) offset)) > 65535)
		goto out_oversize;

	/* Determine the position of this fragment. */
	end = offset + ntohs(iph->tot_len) - ihl;

	/* Is this the final fragment? */
	if ((flags & IP_MF) == 0)
		qp->len = end;

	/* Find out which fragments are in front and at the back of us
	 * in the chain of fragments so far.  We must know where to put
	 * this fragment, right?
	 */
	prev = NULL;
	for(next = qp->fragments; next != NULL; next = next->next) {
		if (next->offset >= offset)
			break;	/* bingo! */
		prev = next;
	}

	/* Point into the IP datagram 'data' part. */
	ptr = skb->data + ihl;

	/* We found where to put this one.  Check for overlap with
	 * preceding fragment, and, if needed, align things so that
	 * any overlaps are eliminated.
	 */
	if ((prev != NULL) && (offset < prev->end)) {
		i = prev->end - offset;
		offset += i;	/* ptr into datagram */
		ptr += i;	/* ptr into fragment data */
	}

	/* Look for overlap with succeeding segments.
	 * If we can merge fragments, do it.
	 */
	for (tmp = next; tmp != NULL; tmp = tfp) {
		tfp = tmp->next;
		if (tmp->offset >= end)
			break;		/* no overlaps at all	*/

		i = end - next->offset;	/* overlap is 'i' bytes */
		tmp->len -= i;		/* so reduce size of	*/
		tmp->offset += i;	/* next fragment	*/
		tmp->ptr += i;

		/* If we get a frag size of <= 0, remove it and the packet
		 * that it goes with.
		 */
		if (tmp->len <= 0) {
			if (tmp->prev != NULL)
				tmp->prev->next = tmp->next;
			else
				qp->fragments = tmp->next;

			if (tmp->next != NULL)
				tmp->next->prev = tmp->prev;
			
			/* We have killed the original next frame. */
			next = tfp;

			frag_kfree_skb(tmp->skb);
			frag_kfree_s(tmp, sizeof(struct ipfrag));
		}
	}

	/*
	 * Create a fragment to hold this skb.
	 * No memory to save the fragment? throw the lot ...
	 */
	tfp = ip_frag_create(offset, end, skb, ptr);
	if (!tfp)
		goto out_freeskb;

	/* Insert this fragment in the chain of fragments. */
	tfp->prev = prev;
	tfp->next = next;
	if (prev != NULL)
		prev->next = tfp;
	else
		qp->fragments = tfp;

	if (next != NULL)
		next->prev = tfp;

	/* OK, so we inserted this new fragment into the chain.
	 * Check if we now have a full IP datagram which we can
	 * bump up to the IP layer...
	 */
	if (ip_done(qp)) {
		/* Glue together the fragments. */
 		skb = ip_glue(qp);
		/* Free the queue entry. */
out_freequeue:
		ip_free(qp);
out_skb:
		return skb;
	}

	/*
	 * The queue is still active ... reset its timer.
	 */
out_timer:
	mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
out:
	return NULL;

	/*
	 * Error exits ... we need to reset the timer if there's a queue.
	 */
out_oversize:
	if (net_ratelimit())
		printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
			NIPQUAD(iph->saddr));
	/* the skb isn't in a fragment, so fall through to free it */
out_freeskb:
	kfree_skb(skb);
	ip_statistics.IpReasmFails++;
	if (qp)
		goto out_timer;
	goto out;
}
Beispiel #13
0
// 每重组一个ip碎片,就会更新对应ipq的timer
//
//
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
	struct ipfrag *prev, *next, *tmp;
	// 指向一个碎片
	struct ipfrag *tfp;
	// 指向一个队列
	struct ipq *qp;
	// 用来放返回值
	char *skb2;
	// 用来进行字节操作
	unsigned char *ptr;
	int flags, offset;
	int i, ihl, end;

	// 如果成功更新全局变量this_host, 并且skb是有内容的
	if (!hostfrag_find(iph) && skb)
		// 生成一个碎片
		hostfrag_create(iph);

	/* Start by cleaning up the memory. */
	// 如果当前host不为空
	if (this_host)
		// 如果大于上限
		if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
			// 裁剪掉一些ip碎片,直到 ip_frag_mem < IPFRAG_LOW_THRESH
			ip_evictor();

	/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
	// 如果host存在
	if (this_host)
		// 找到与这个ip头相关的ip队列
		qp = ip_find(iph);
	else
		// 否则设置队列为空
		qp = 0;
	

	/* Is this a non-fragmented datagram? */
	// ip_off是一个16位的字段,高3位用来保存标志信息,低12位用来保存当前碎片的偏移
	offset = ntohs(iph->ip_off);  /* 先把ip_offset这个字段取出来 */
	// 把高3位取出来
	flags = offset & ~IP_OFFSET;
	// 把低13位取出来
	offset &= IP_OFFSET;
	// IP_MF==0表示当前收到是碎片后面没有碎片了,并且当前收到碎片是第一个碎片,
	// 显然当前碎片虽在的ip报文仅仅有一个碎片
	// 那么当前碎片(刚刚收到的碎片)并不需要重组,因此可以返回了
	if (((flags & IP_MF) == 0) && (offset == 0))
	{
		// 如果队列不为空就释放掉
		if (qp != NULL)
			ip_free(qp);		/* Fragmented frame replaced by full unfragmented copy */
		return 0;
	}

	/* ip_evictor() could have removed all queues for the current host */
	// 如果host全部被移出了,那么重新创建一个,针对当前ip头的host
	// 但是,这个host并不会包括任何东西,它是一个空的,没有ip队列
	if (!this_host)
		hostfrag_create(iph);
	// 计算offset和头长度
	// 这个offset是刚刚收到的这个碎片的offset
	offset <<= 3;			/* offset is in 8-byte chunks */
	ihl = iph->ip_hl * 4;


	/*
	  If the queue already existed, keep restarting its timer as long as
	  we still are receiving fragments.  Otherwise, create a fresh queue
	  entry.
	*/
	// 如果队列存在
	if (qp != NULL)
	{
		/* ANK. If the first fragment is received, we should remember the correct
		   IP header (with options) */
		// 如果偏移量为0,可能是该pi报文中的第一个碎片,因此要把前8字节保存下来
		if (offset == 0)
		{
			// 保存头长度
			qp->ihlen = ihl;
			// 拷贝头信息+8字节
			memcpy(qp->iph, iph, ihl + 8);
		}
		// 停止计时
		del_timer(&qp->timer);
		// 重新计时
		qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
		// 设置关联
		qp->timer.data = (unsigned long) qp;	/* pointer to queue */
		// 注册回调函数
		qp->timer.function = ip_expire;	/* expire function */
		// 添加计数器
		add_timer(&qp->timer);
	}
	// 否则队列不存在
	else
	{
		/* If we failed to create it, then discard the frame. */
		// 试图创建一个
		if ((qp = ip_create(iph)) == NULL)
		{
			// 如果创建队列失败,那么释放当前碎片的空间并返回
			kfree_skb(skb, FREE_READ);
			return NULL;
		}
	}

	
	/* Attempt to construct an oversize packet. */
	// 如果头+长度 超长, 释放空间
	if (ntohs(iph->ip_len) + (int) offset > 65535)
	{
		// NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
		kfree_skb(skb, FREE_READ);
		return NULL;
	}

	
	/* Determine the position of this fragment. */
	// 刚刚收到的碎片分组 + 刚刚收到的碎片ip包大小 - 刚刚收到的碎片ip包头大小
	// = 刚刚收到的分组的结尾
	end = offset + ntohs(iph->ip_len) - ihl;

	/* Point into the IP datagram 'data' part. */
	// 将指针,指向刚刚收到的碎片ip包的数据开头部分
	// prt 指向肉
	ptr = (unsigned char *)(skb->data + ihl);

	/* Is this the final fragment? */
	// 如果这是最后一个碎片,那么,整个队列的长度,就是当前的end
	// 否则qp->len会在后面更改,因为会有重叠部分
	if ((flags & IP_MF) == 0)
		qp->len = end;

	/*
	  Find out which fragments are in front and at the back of us in the
	  chain of fragments so far.  We must know where to put this
	  fragment, right?
	*/
	prev = NULL;
	// 给定一个offset,在所有的fragments中找到第一个
	// 拥有不小于给定offset的offset的碎片,然后终止循环
	// 由此可以猜测,这一个函数,其实是将某一个新来的碎片插入到
	// 队列合适的位置,保证offset升序排列
	// next 指向的是第一个不小于当前offset的碎片
	// pre指向的是前一个碎片
	for (next = qp->fragments; next != NULL; next = next->next)
	{
		if (next->offset >= offset)
			break;			/* bingo! */
		prev = next;
	}
	/*--------------------------------------------------------------
	注意: 
		next 指向的是第一个排在当前碎片后面的 碎片;
		pre  指向的是第一个排在当前碎片前面的 碎片。
		next 有可能offset与当前碎片的offset一样
	----------------------------------------------------------------*/
	
	
	/*
	  We found where to put this one.  Check for overlap with preceding
	  fragment, and, if needed, align things so that any overlaps are
	  eliminated.
	*/
	// 如果有排在当前碎片前面的分组,并且, 该分组的结束比当前分组的offset大
	// 说明有重叠,应噶修正当前offset,以先来的为准
	if (prev != NULL && offset < prev->end)
	{
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		i = prev->end - offset;
		// 将当前收到的碎片的offset增加i
		offset += i;		/* ptr into datagram */
		// 将当前收到的碎片的指正向后移动i
		ptr += i;			/* ptr into fragment data */
	}
	
	/*
	  Look for overlap with succeeding segments.
	  If we can merge fragments, do it.
	*/
	// 现在往后查看是否有重叠的
	// 从next开始
	for (tmp = next; tmp != NULL; tmp = tfp)
	{
		// temp总是等于next
		tfp = tmp->next;
		// 如果next的 offset >= 当前分组的end,那就没有问题
		if (tmp->offset >= end)
			break;			/* no overlaps at all */

		// 否则警报
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		// 记录当前的结束与下一个碎片的开始重叠多少
		i = end - next->offset;	/* overlap is 'i' bytes */
		// 将next碎片的长度减少i
		tmp->len -= i;		/* so reduce size of    */
		// 将next碎片的开始增加i
		tmp->offset += i;		/* next fragment        */
		// 将指针也要向后移动i
		tmp->ptr += i;
		/*
		  If we get a frag size of <= 0, remove it and the packet that it
		  goes with. We never throw the new frag away, so the frag being
		  dumped has always been charged for.
		*/
		// 如果此时next碎片的长度小于0, 那么摘掉next节点
		if (tmp->len <= 0)
		{
			if (tmp->prev != NULL)
				tmp->prev->next = tmp->next;
			else
				qp->fragments = tmp->next;

			if (tmp->next != NULL)
				tmp->next->prev = tmp->prev;

			// tfp原来就等于next->next,所以原来的next节点被摘掉了
			next = tfp;		/* We have killed the original "next" frame */

			// 释放掉frag节点对应的内存
			frag_kfree_skb(tmp->skb, FREE_READ);
			// 释放掉frag节点
			frag_kfree_s(tmp, sizeof(struct ipfrag));
		}
	}

	
	/* Insert this fragment in the chain of fragments. */
	tfp = NULL;
	// offset是刚刚接收到的碎片偏移,按字节
	// end   是刚刚接收到的碎片的结束字节
	// skb   是传进来的一个内存空间,应该事先分配好
	// prt   是指向这个碎片第一个数据的指针
	tfp = ip_frag_create(offset, end, skb, ptr);
	/*---------------------------------------------------
	注意:  
		ip_frag_create函数只是创建一个ip_frag,还没有吧
		它挂载到队列中
	-----------------------------------------------------*/

	/*
	  No memory to save the fragment - so throw the lot. If we failed
	  the frag_create we haven't charged the queue.
	*/
	if (!tfp)
	{
		nids_params.no_mem("ip_defrag");
		kfree_skb(skb, FREE_READ);
		return NULL;
	}
	
	/* From now on our buffer is charged to the queues. */
	// 将刚刚创建的ip_frag挂载到队列中去了
	tfp->prev = prev;
	tfp->next = next;
	if (prev != NULL)
		prev->next = tfp;
	else
		qp->fragments = tfp;

	if (next != NULL)
		next->prev = tfp;

	/*
	  OK, so we inserted this new fragment into the chain.  Check if we
	  now have a full IP datagram which we can bump up to the IP
	  layer...
	*/
	// 检查是否完整
	if (ip_done(qp))
	{
		skb2 = ip_glue(qp);		/* glue together the fragments */
		return (skb2);
	}

	// 如果没有完整,那么返回空,继续执行
	return (NULL);
}
Beispiel #14
0
/*
 *	check if this fragment completes the packet
 *	returns true on success
 */
static u8* reasm_frag(struct frag_queue *fq, struct sk_buff **skb_in)
{
	struct ipv6_frag *fp;
	struct ipv6_frag *head = fq->fragments;
	struct ipv6_frag *tail = NULL;
	struct sk_buff *skb;
	__u32  offset = 0;
	__u32  payload_len;
	__u16  unfrag_len;
	__u16  copy;
	u8     *nhptr;

	for(fp = head; fp; fp=fp->next) {
		if (offset != fp->offset)
			return NULL;

		offset += fp->len;
		tail = fp;
	}

	/* 
	 * we know the m_flag arrived and we have a queue,
	 * starting from 0, without gaps.
	 * this means we have all fragments.
	 */

	/* Unfragmented part is taken from the first segment.
	   (fixed --ANK (980728))
	 */
	unfrag_len = (u8 *) (head->fhdr) - (u8 *) (head->skb->nh.ipv6h + 1);

	payload_len = (unfrag_len + tail->offset + 
		       (tail->skb->tail - (__u8 *) (tail->fhdr + 1)));

	if (payload_len > 65535) {
		if (net_ratelimit())
			printk(KERN_DEBUG "reasm_frag: payload len = %d\n", payload_len);
		ipv6_statistics.Ip6ReasmFails++;
		fq_free(fq);
		return NULL;
	}

	if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) {
		if (net_ratelimit())
			printk(KERN_DEBUG "reasm_frag: no memory for reassembly\n");
		ipv6_statistics.Ip6ReasmFails++;
		fq_free(fq);
		return NULL;
	}

	copy = unfrag_len + sizeof(struct ipv6hdr);

	skb->nh.ipv6h = (struct ipv6hdr *) skb->data;
	skb->dev = fq->dev;
	skb->protocol = __constant_htons(ETH_P_IPV6);
	skb->pkt_type = head->skb->pkt_type;
	memcpy(skb->cb, head->skb->cb, sizeof(skb->cb));
	skb->dst = dst_clone(head->skb->dst);

	memcpy(skb_put(skb, copy), head->skb->nh.ipv6h, copy);
	nhptr = skb->nh.raw + fq->nhoffset;
	*nhptr = fq->nexthdr;

	skb->h.raw = skb->tail;

	skb->nh.ipv6h->payload_len = ntohs(payload_len);

	*skb_in = skb;

	/*
	 *	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;

		memcpy(skb_put(skb, fp->len), (__u8*)(fp->fhdr + 1), fp->len);
		frag_kfree_skb(fp->skb);
		back = fp;
		fp=fp->next;
		frag_kfree_s(back, sizeof(*back));
	}

	del_timer(&fq->timer);
	fq->prev->next = fq->next;
	fq->next->prev = fq->prev;
	fq->prev = fq->next = NULL;

	frag_kfree_s(fq, sizeof(*fq));

	ipv6_statistics.Ip6ReasmOKs++;
	return nhptr;
}
Beispiel #15
0
static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb, 
				     struct frag_hdr *fhdr, u8 *nhptr)
{
	struct ipv6_frag *nfp, *fp, **bptr;

	nfp = (struct ipv6_frag *) frag_kmalloc(sizeof(struct ipv6_frag), 
						GFP_ATOMIC);

	if (nfp == NULL) {		
		kfree_skb(skb);
		return;
	}

	nfp->offset = ntohs(fhdr->frag_off) & ~0x7;
	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;
	}
	if (fhdr->frag_off & __constant_htons(0x0001)) {
		/* Check if the fragment is rounded to 8 bytes.
		 * Required by the RFC.
		 * ... and would break our defragmentation algorithm 8)
		 */
		if (nfp->len & 0x7) {
			printk(KERN_DEBUG "fragment not rounded to 8bytes\n");

			/*
			   It is not in specs, but I see no reasons
			   to send an error in this case. --ANK
			 */
			if (nfp->offset == 0)
				icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 
						  &skb->nh.ipv6h->payload_len);
			goto err;
		}
	}

	nfp->skb  = skb;
	nfp->fhdr = fhdr;
	nfp->next = NULL;

	bptr = &fq->fragments;

	for (fp = fq->fragments; fp; fp=fp->next) {
		if (nfp->offset <= fp->offset)
			break;
		bptr = &fp->next;
	}
	if (fp && fp->offset == nfp->offset) {
		if (nfp->len != fp->len) {
			printk(KERN_DEBUG "reasm_queue: dup with wrong len\n");
		}

		/* duplicate. discard it. */
		goto err;
	}

	atomic_add(skb->truesize, &ip6_frag_mem);

	/* All the checks are done, fragment is acepted.
	   Only now we are allowed to update reassembly data!
	   (fixed --ANK (980728))
	 */

	/* iif always set to one of the last arrived segment */
	fq->dev = skb->dev;
	fq->iif = skb->dev->ifindex;

	/* Last fragment */
	if ((fhdr->frag_off & __constant_htons(0x0001)) == 0)
		fq->last_in |= LAST_IN;

	/* First fragment.
	   nexthdr and nhptr are get from the first fragment.
	   Moreover, nexthdr is UNDEFINED for all the fragments but the
	   first one.
	   (fixed --ANK (980728))
	 */
	if (nfp->offset == 0) {
		fq->nexthdr = fhdr->nexthdr;
		fq->last_in |= FIRST_IN;
		fq->nhoffset = nhptr - skb->nh.raw;
	}

	*bptr = nfp;
	nfp->next = fp;
	return;

err:
	frag_kfree_s(nfp, sizeof(*nfp));
	kfree_skb(skb);
}