Ubuntu 2.6.18 内核数据包游历过程分析(2)

if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TCP_MIB_INERRS);
inet_twsk_put((struct inet_timewait_sock *) sk);
goto discard_it;
}
switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
skb, th)) {
case TCP_TW_SYN: {
struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
skb->nh.iph->daddr,
ntohs(th->dest),
inet_iif(skb));
if (sk2) {
inet_twsk_deschedule((struct inet_timewait_sock *)sk,
&tcp_death_row);
inet_twsk_put((struct inet_timewait_sock *)sk);
sk = sk2;
goto process;
}
/* Fall through to ACK */
}
case TCP_TW_ACK:
tcp_v4_timewait_ack(sk, skb);
break;
case TCP_TW_RST:
goto no_tcp_socket;
case TCP_TW_SUCCESS:;
}
goto discard_it;
在上面的处理函数中发现,数据包通过一个名为tcp_v4_do_rcv()的函数传递了下去。下面跟踪这个函数,其原形如下:
int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
函数处理过程如下:
由于caller在查找hash链表时,有可能返回established链表中条目信息,也可能返回listener链表中的条目信息,所以这里首先判断该数据报的链接状态是否为TCP_ESTABLISHED,若是则调用tcp_rcv_established(sk, skb, skb->h.th, skb->len)函数进行处理。为项目需要,这里不是跟踪的重点,暂时暂停,使执行流继续向下执行。其实这里我应经进行了详尽的跟踪,由于时间关系,这里就先不写了,若时间宽裕,再将其补充上,嘎嘎...
if (skb->len < (skb->h.th->doff << 2) || TCP数据包校验和错误) then
goto csum_err;
if 数据包状态为 TCP_LISTEN then
struct sock *nsk = tcp_v4_hnd_req(sk, skb);    //tcp三次握手请求处理函数
if (!nsk)                    //若nsk指针值为NULL,说明该三次握手过程没有成功,可能的原因是accept链接队列已满!
goto discard;

if (nsk != sk) {                //若由tcp_v4_hnd_req返回的hash表相应链表条目地址于caller传进来的条目地址信
//息不同的话,说明已通过inet_csk_clone()生成了新的struct sock,此时则进入
//tcp_child_process()处理函数
if (tcp_child_process(sk, nsk, skb))-->    //
goto reset;
return 0;
}
tcp_rcv_state_process(sk, skb, skb->h.th, skb->len);    //数据包状态处理函数
这里跟踪三次握手处理过程函数tcp_v4_hnd_req,其原型如下:
static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwpdjj.html