最近研究学习linux内核对IP分片的重组处理这块,有些地方不太明白,想请教熟悉的dx。问题如下,这个函数内部对LINUX的分片last_in设置为COMPLETE标识。请结合场景流程解析下,谢谢!本来COMPLETE是用来标识所有的分片到齐的,我就是一直没明白如何判断一个分组的所有分片到齐。FIRST_IN、LAST_IN都容易理解,唯独这个COMPLETE没看懂。static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
{
struct ipq *qp; write_lock(&ipfrag_lock);
#ifdef CONFIG_SMP
/* With SMP race we have to recheck hash table, because
* such entry could be created on other cpu, while we
* promoted read lock to write lock.
*/
for(qp = ipq_hash[hash]; qp; qp = qp->next) {
if(qp->id == qp_in->id &&
qp->saddr == qp_in->saddr &&
qp->daddr == qp_in->daddr &&
qp->protocol == qp_in->protocol) {
atomic_inc(&qp->refcnt);
write_unlock(&ipfrag_lock);
qp_in->last_in |= COMPLETE;// 这里设置COMPLETE,如何理解?
ipq_put(qp_in);
return qp;
}
}
#endif
qp = qp_in; if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))
atomic_inc(&qp->refcnt); atomic_inc(&qp->refcnt);
if((qp->next = ipq_hash[hash]) != NULL)
qp->next->pprev = &qp->next;
ipq_hash[hash] = qp;
qp->pprev = &ipq_hash[hash];
INIT_LIST_HEAD(&qp->lru_list);
list_add_tail(&qp->lru_list, &ipq_lru_list);
ip_frag_nqueues++;
write_unlock(&ipfrag_lock);
return qp;
}
{
struct ipq *qp; write_lock(&ipfrag_lock);
#ifdef CONFIG_SMP
/* With SMP race we have to recheck hash table, because
* such entry could be created on other cpu, while we
* promoted read lock to write lock.
*/
for(qp = ipq_hash[hash]; qp; qp = qp->next) {
if(qp->id == qp_in->id &&
qp->saddr == qp_in->saddr &&
qp->daddr == qp_in->daddr &&
qp->protocol == qp_in->protocol) {
atomic_inc(&qp->refcnt);
write_unlock(&ipfrag_lock);
qp_in->last_in |= COMPLETE;// 这里设置COMPLETE,如何理解?
ipq_put(qp_in);
return qp;
}
}
#endif
qp = qp_in; if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))
atomic_inc(&qp->refcnt); atomic_inc(&qp->refcnt);
if((qp->next = ipq_hash[hash]) != NULL)
qp->next->pprev = &qp->next;
ipq_hash[hash] = qp;
qp->pprev = &ipq_hash[hash];
INIT_LIST_HEAD(&qp->lru_list);
list_add_tail(&qp->lru_list, &ipq_lru_list);
ip_frag_nqueues++;
write_unlock(&ipfrag_lock);
return qp;
}
解决方案 »
- 进程间通信windows下的管道(pipe)性能如何?
- 如何获取树控件的选择项并判断根?
- 很奇怪的一个问题,关于剪切板的.
- 调试出现奇怪问题。
- 在线求助:在VB里调用一个COM接口方法,方法里入参数为指针,出参数为指针,怎么调用??
- CStatic 怎么出毛病了。!!!!!!!
- 在服务程序内能用ado吗?
- 哪位大神对winpcap比较熟悉啊,帮忙看看哈?
- 请问:我请读取计算机ROM区中F000H:FFF5H-F000H:FFFFH中的内容。该怎么办?
- #include <iostream.h>与#include <iostream>有何区别?
- TCHAR类型
- 大家看看我的这个CIMAGE的LOAD为什么出错啊?
while (pep=(struct ep *)seeq(iq->ipf_q)) { //取数据报
pip = (struct ip *)pep->ep_data;
packoff = (pip->ip_fragoff & IP_FRAGOFF)<<3;
if (off < packoff) { //只要一个不满足,说明分片还没有到全
while(seeq(iq->ipf_q))
/*empty*/;
return 0;
}
off = packoff + pip->ip_len - IP_HLEN(pip); //最后总数据报长度(没有头部)
}这里不是有判断完整的代码吗?
/*
// 如果节点状态为COMPLETE,所有分片已经到齐,后续分片为无效数据
if (qp->last_in & COMPLETE)
goto err;
*/
/* Add new segment to existing queue. */
static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
{
struct sk_buff *prev, *next;
int flags, offset;
int ihl, end; // 如果节点状态为COMPLETE,所有分片已经到齐,后续分片为无效数据
if (qp->last_in & COMPLETE)
goto err; offset = ntohs(skb->nh.iph->frag_off);
flags = offset & ~IP_OFFSET;
offset &= IP_OFFSET;
offset <<= 3; /* offset is in 8-byte chunks */
ihl = skb->nh.iph->ihl * 4; /* Determine the position of this fragment. */
end = offset + skb->len - ihl; /* Is this the final fragment? */
if ((flags & IP_MF) == 0)
{
/* If we already have some bits beyond end
* or have different end, the segment is corrrupted.
*/
if (end < qp->len ||
((qp->last_in & LAST_IN) && end != qp->len))
goto err;
qp->last_in |= LAST_IN;
qp->len = end;
}
else
{
if (end&7) {
end &= ~7;
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
skb->ip_summed = CHECKSUM_NONE;
}
if (end > qp->len) {
/* Some bits beyond end -> corruption. */
if (qp->last_in & LAST_IN)
goto err;
qp->len = end;
}
}
if (end == offset)
goto err; if (pskb_pull(skb, ihl) == NULL)
goto err;
if (pskb_trim(skb, end-offset))
goto err; /* 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 (FRAG_CB(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) {
int i = (FRAG_CB(prev)->offset + prev->len) - offset; if (i > 0) {
offset += i;
if (end <= offset)
goto err;
if (!pskb_pull(skb, i))
goto err;
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
skb->ip_summed = CHECKSUM_NONE;
}
} while (next && FRAG_CB(next)->offset < end) {
int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ if (i < next->len) {
/* Eat head of the next overlapped fragment
* and leave the loop. The next ones cannot overlap.
*/
if (!pskb_pull(next, i))
goto err;
FRAG_CB(next)->offset += i;
qp->meat -= i;
if (next->ip_summed != CHECKSUM_UNNECESSARY)
next->ip_summed = CHECKSUM_NONE;
break;
} else {
struct sk_buff *free_it = next; /* Old fragmnet is completely overridden with
* new one drop it.
*/
next = next->next; if (prev)
prev->next = next;
else
qp->fragments = next; qp->meat -= free_it->len;
frag_kfree_skb(free_it);
}
} FRAG_CB(skb)->offset = offset; /* Insert this fragment in the chain of fragments. */
skb->next = next;
if (prev)
prev->next = skb;
else
qp->fragments = skb; if (skb->dev)
qp->iif = skb->dev->ifindex;
skb->dev = NULL;
qp->stamp = skb->stamp;
qp->meat += skb->len;
atomic_add(skb->truesize, &ip_frag_mem);
if (offset == 0)
qp->last_in |= FIRST_IN; write_lock(&ipfrag_lock);
list_move_tail(&qp->lru_list, &ipq_lru_list);
write_unlock(&ipfrag_lock); return;err:
kfree_skb(skb);
}