} 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; } 接收到SKb包后,会调用__inet_lookup_skb()查找对应的sock结构。如果套接字状态是TIME_WAIT状态,会跳转到do_time_wait标签处处理。从代码中可以看到,主要由tcp_timewait_state_process()函数来处理SKB包,处理后根据返回值来做相应的处理。 在看tcp_timewait_state_process()函数中的处理之前,需要先看一看不同的返回值会对应什么样的处理。 如果返回值是TCP_TW_SYN,则说明接收到的是一个“合法”的SYN包(也就是说这个SYN包可以接受),这时会首先查找内核中是否有对应的监听套接字,如果存在相应的监听套接字,则会释放TIME_WAIT状态的传输控制结构,跳转到process处开始处理,开始建立一个新的连接。如果没有找到监听套接字会执行到TCP_TW_ACK分支。 如果返回值是TCP_TW_ACK,则会调用tcp_v4_timewait_ack()发送ACK,然后跳转到discard_it标签处,丢掉数据包。 如果返回值是TCP_TW_RST,则会调用tcp_v4_send_reset()给对端发送RST包,然后丢掉数据包。 如果返回值是TCP_TW_SUCCESS,则会直接丢掉数据包。 接下来我们通过tcp_timewait_state_process()函数来看TIME_WAIT状态下的数据包处理。 为了方便讨论,假设数据包中没有时间戳选项,在这个前提下,tcp_timewait_state_process()中的局部变量paws_reject的值为0。 如果需要保持在FIN_WAIT_2状态的时间小于等于TCP_TIMEWAIT_LEN,则会从FIN_WAIT_2状态直接迁移到TIME_WAIT状态,也就是使用描述TIME_WAIT状态的sock结构代替当前的传输控制块。论文网 虽然这时的sock结构处于TIME_WAIT结构,但是还要区分内部状态,这个内部状态存储在inet_timewait_sock结构的tw_substate成员中。 如果内部状态为FIN_WAIT_2,tcp_timewait_state_process()中处理的关键代码片段如下所示:
[cpp] view plaincopyprint? 01. if (tw->tw_substate == TCP_FIN_WAIT2){ 02. /* Just repeat all the checks of tcp_rcv_state_process() */ 03. 04. 05. /* Out of window, send ACK */ 06. if (paws_reject || 07. !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, 08. tcptw->tw_rcv_nxt, 09. tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd)) 10. return TCP_TW_ACK; 11. 12. 13. if (th->rst) 14. goto kill; 15. 16. 17. if (th->syn && !before(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt)) 18. goto kill_with_rst; 19. 20. 21. /* Dup ACK? */ 22.&n 上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ... 下一页 >>
|