Exemple #1
0
void ick_interpreter_run(void)
{
	if (!fungespace_create()) {
		perror("Couldn't create funge space!?");
		exit(EXIT_FAILURE);
	}
#if (CFUNGE_API_VERSION < 2)
	fungespace_load_string(ick_iffi_befungeString);
#else
	fungespace_load_string(ick_iffi_befungeString, strlen((const char*)ick_iffi_befungeString));
#endif
	iffiIP = ip_create();
	if (iffiIP == NULL) {
		perror("Couldn't create instruction pointer!?");
		exit(EXIT_FAILURE);
	}
	{
#ifdef HAVE_clock_gettime
		struct timespec tv;
		if (clock_gettime(CLOCK_REALTIME, &tv)) {
			perror("Couldn't get time of day?!");
			exit(EXIT_FAILURE);
		}
		// Set up randomness
		srandom(tv.tv_nsec);
#else
		struct timeval tv;
		if (gettimeofday(&tv, NULL)) {
			perror("Couldn't get time of day?!");
			exit(EXIT_FAILURE);
		}
		// Set up randomness
		srandom(tv.tv_usec);
#endif
	}
	if(ick_printflow) setting_trace_level=9;
	ick_interpreter_main_loop();
}
Exemple #2
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);
}
Exemple #3
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;
}
Exemple #4
0
/**
 * @brief Parse a network packet
 *
 * @param[out] packet    The parsed packet
 * @param data           The data to parse
 * @param trace_cb       The function to call for printing traces
 * @param trace_cb_priv  An optional private context, may be NULL
 * @param trace_entity   The entity that emits the traces
 * @return               true if the packet was successfully parsed,
 *                       false if a problem occurred (a malformed packet is
 *                       not considered as an error)
 */
bool net_pkt_parse(struct net_pkt *const packet,
                   const struct rohc_buf data,
                   rohc_trace_callback2_t trace_cb,
                   void *const trace_cb_priv,
                   rohc_trace_entity_t trace_entity)
{
	packet->data = rohc_buf_data(data);
	packet->len = data.len;
	packet->ip_hdr_nr = 0;
	packet->key = 0;

	/* traces */
	packet->trace_callback = trace_cb;
	packet->trace_callback_priv = trace_cb_priv;

	/* create the outer IP packet from raw data */
	if(!ip_create(&packet->outer_ip, rohc_buf_data(data), data.len))
	{
		rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL,
		             "cannot create the outer IP header");
		goto error;
	}
	packet->ip_hdr_nr++;
	rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
	           "outer IP header: %u bytes", ip_get_totlen(&packet->outer_ip));
	rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
	           "outer IP header: version %d", ip_get_version(&packet->outer_ip));
	if(packet->outer_ip.nh.data != NULL)
	{
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "outer IP header: next header is of type %d",
		           packet->outer_ip.nh.proto);
		if(packet->outer_ip.nl.data != NULL)
		{
			rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
			           "outer IP header: next layer is of type %d",
			           packet->outer_ip.nl.proto);
		}
	}

	/* build the hash key for the packet */
	if(ip_get_version(&packet->outer_ip) == IPV4)
	{
		packet->key ^= ipv4_get_saddr(&packet->outer_ip);
		packet->key ^= ipv4_get_daddr(&packet->outer_ip);
	}
	else if(ip_get_version(&packet->outer_ip) == IPV6)
	{
		const struct ipv6_addr *const saddr = ipv6_get_saddr(&packet->outer_ip);
		const struct ipv6_addr *const daddr = ipv6_get_daddr(&packet->outer_ip);
		packet->key ^= saddr->addr.u32[0];
		packet->key ^= saddr->addr.u32[1];
		packet->key ^= saddr->addr.u32[2];
		packet->key ^= saddr->addr.u32[3];
		packet->key ^= daddr->addr.u32[0];
		packet->key ^= daddr->addr.u32[1];
		packet->key ^= daddr->addr.u32[2];
		packet->key ^= daddr->addr.u32[3];
	}

	/* get the transport protocol */
	packet->transport = &packet->outer_ip.nl;

	/* is there any inner IP header? */
	if(rohc_is_tunneling(packet->transport->proto))
	{
		/* create the second IP header */
		if(!ip_get_inner_packet(&packet->outer_ip, &packet->inner_ip))
		{
			rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL,
			             "cannot create the inner IP header");
			goto error;
		}
		packet->ip_hdr_nr++;
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "inner IP header: %u bytes", ip_get_totlen(&packet->inner_ip));
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "inner IP header: version %d", ip_get_version(&packet->inner_ip));
		if(packet->inner_ip.nh.data != NULL)
		{
			rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
			           "inner IP header: next header is of type %d",
			           packet->inner_ip.nh.proto);
			if(packet->inner_ip.nl.data != NULL)
			{
				rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
				           "inner IP header: next layer is of type %d",
				           packet->inner_ip.nl.proto);
			}
		}

		/* get the transport protocol */
		packet->transport = &packet->inner_ip.nl;
	}

	return true;

error:
	return false;
}
// 每重组一个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);
}