TCP三步握手建立连接(2)-----被动连接方发送SYN/ACK

来源:互联网 发布:linux vncserver 编辑:程序博客网 时间:2024/05/13 07:57

本过程分析的基础建立在本地TCP已经调用了listen进入了监听状态,至于数据包如何进入tcp这里暂且不表。

tcp数据包的入口函数tcp_v4_rcv,该函数在检验数据包的正确性后,找到对应的INET SOCKET,对于SYN包,

找到的是对应的Listen状态的sock。后面的处理无论是数据包进入backlog,还是prequeue,最后都会进入

tcp_v4_do_rcv函数进行处理。

 

[cpp] view plaincopy
  1. /* The socket must have it's spinlock held when we get 
  2.  * here. 
  3.  * 
  4.  * We have a potential double-lock case here, so even when 
  5.  * doing backlog processing we use the BH locking scheme. 
  6.  * This is because we cannot sleep with the original spinlock 
  7.  * held. 
  8.  */  
  9. int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  
  10. {  
  11.     struct sock *rsk;  
  12. #ifdef CONFIG_TCP_MD5SIG  
  13.     /* 
  14.      * We really want to reject the packet as early as possible 
  15.      * if: 
  16.      *  o We're expecting an MD5'd packet and this is no MD5 tcp option 
  17.      *  o There is an MD5 option and we're not expecting one 
  18.      */  
  19.     if (tcp_v4_inbound_md5_hash(sk, skb))  
  20.         goto discard;  
  21. #endif  
  22.         /* 该路径进入连接建立后的处理 */  
  23.     if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */  
  24.         TCP_CHECK_TIMER(sk);  
  25.         if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {  
  26.             rsk = sk;  
  27.             goto reset;  
  28.         }  
  29.         TCP_CHECK_TIMER(sk);  
  30.         return 0;  
  31.     }  
  32.   
  33.     if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))  
  34.         goto csum_err;  
  35.         /* SYN 和SYN/ACK都进入此路径 */  
  36.     if (sk->sk_state == TCP_LISTEN) {  
  37.         struct sock *nsk = tcp_v4_hnd_req(sk, skb);  
  38.         if (!nsk)  
  39.             goto discard;  
  40.   
  41.         if (nsk != sk) {  
  42.             if (tcp_child_process(sk, nsk, skb)) {  
  43.                 rsk = nsk;  
  44.                 goto reset;  
  45.             }  
  46.             return 0;  
  47.         }  
  48.     }  
  49.   
  50.     TCP_CHECK_TIMER(sk);  
  51.     if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {  
  52.         rsk = sk;  
  53.         goto reset;  
  54.     }  
  55.     TCP_CHECK_TIMER(sk);  
  56.     return 0;  
  57.   
  58. reset:  
  59.     tcp_v4_send_reset(rsk, skb);  
  60. discard:  
  61.     kfree_skb(skb);  
  62.     /* Be careful here. If this function gets more complicated and 
  63.      * gcc suffers from register pressure on the x86, sk (in %ebx) 
  64.      * might be destroyed here. This current version compiles correctly, 
  65.      * but you have been warned. 
  66.      */  
  67.     return 0;  
  68.   
  69. csum_err:  
  70.     TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);  
  71.     goto discard;  
  72. }  

 

现在进入tcp_v4_hnd_req函数,该函数处理listen sock的连接请求。

[cpp] view plaincopy
  1. static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)  
  2. {  
  3.     struct tcphdr *th = tcp_hdr(skb);  
  4.     const struct iphdr *iph = ip_hdr(skb);  
  5.     struct sock *nsk;  
  6.     struct request_sock **prev;  
  7.     /* Find possible connection requests. */  
  8.     struct request_sock *req = inet_csk_search_req(sk, &prev, th->source,  
  9.                                iph->saddr, iph->daddr);  
  10.     if (req)  
  11.         return tcp_check_req(sk, skb, req, prev);  
  12.   
  13.     nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr,  
  14.             th->source, iph->daddr, th->dest, inet_iif(skb));  
  15.   
  16.     if (nsk) {  
  17.         if (nsk->sk_state != TCP_TIME_WAIT) {  
  18.             bh_lock_sock(nsk);  
  19.             return nsk;  
  20.         }  
  21.         inet_twsk_put(inet_twsk(nsk));  
  22.         return NULL;  
  23.     }  
  24.   
  25. #ifdef CONFIG_SYN_COOKIES  
  26.     if (!th->rst && !th->syn && th->ack)  
  27.         sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));  
  28. #endif  
  29.     return sk;  
  30. }  

很显然,由于是第一次连接,所以该sock没有此次请求的信息,所以该函数返回参数中sk。

然后在tcp_v4_do_rcv中进入tcp_rcv_state_process。

tcp_rcv_state_process函数是个状态机。对该函数我们分开来说,对于此次连接进入下面的case语句中。

[cpp] view plaincopy
  1. case TCP_LISTEN:  
  2.                 /* Listen 下受到的是个ACK包,重置该连接 */  
  3.         if (th->ack)  
  4.             return 1;  
  5.   
  6.         if (th->rst)  
  7.             goto discard;  
  8.                 /* 进入新的连接请求的处理 */  
  9.         if (th->syn) {  
  10.             if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)  
  11.                 return 1;  
  12.   
  13.             /* Now we have several options: In theory there is 
  14.              * nothing else in the frame. KA9Q has an option to 
  15.              * send data with the syn, BSD accepts data with the 
  16.              * syn up to the [to be] advertised window and 
  17.              * Solaris 2.1 gives you a protocol error. For now 
  18.              * we just ignore it, that fits the spec precisely 
  19.              * and avoids incompatibilities. It would be nice in 
  20.              * future to drop through and process the data. 
  21.              * 丢弃SYN包中存在的数据,不过有的协议中支持SYN包就发送数据 
  22.              * Now that TTCP is starting to be used we ought to 
  23.              * queue this data. 
  24.              * But, this leaves one open to an easy denial of 
  25.              * service attack, and SYN cookies can't defend 
  26.              * against this problem. So, we drop the data 
  27.              * in the interest of security over speed unless 
  28.              * it's still in use. 
  29.              */  
  30.             kfree_skb(skb);  
  31.             return 0;  
  32.         }  
  33.         goto discard;  

 

 icsk_af_ops是有连接类型的SOCKET的特点操作符,在tcp连接时对于的是

[cpp] view plaincopy
  1. struct inet_connection_sock_af_ops ipv4_specific = {  
  2.     .queue_xmit    = ip_queue_xmit,  
  3.     .send_check    = tcp_v4_send_check,  
  4.     .rebuild_header    = inet_sk_rebuild_header,  
  5.     .conn_request      = tcp_v4_conn_request,  
  6.     .syn_recv_sock     = tcp_v4_syn_recv_sock,  
  7.     .remember_stamp    = tcp_v4_remember_stamp,  
  8.     .net_header_len    = sizeof(struct iphdr),  
  9.     .setsockopt    = ip_setsockopt,  
  10.     .getsockopt    = ip_getsockopt,  
  11.     .addr2sockaddr     = inet_csk_addr2sockaddr,  
  12.     .sockaddr_len      = sizeof(struct sockaddr_in),  
  13.     .bind_conflict     = inet_csk_bind_conflict,  
  14. #ifdef CONFIG_COMPAT  
  15.     .compat_setsockopt = compat_ip_setsockopt,  
  16.     .compat_getsockopt = compat_ip_getsockopt,  
  17. #endif  
  18. };  

所以对应的函数是tcp_v4_conn_request

[cpp] view plaincopy
  1. int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)  
  2. {  
  3.     struct inet_request_sock *ireq;  
  4.     struct tcp_options_received tmp_opt;  
  5.     struct request_sock *req;  
  6.     __be32 saddr = ip_hdr(skb)->saddr;  
  7.     __be32 daddr = ip_hdr(skb)->daddr;  
  8.     __u32 isn = TCP_SKB_CB(skb)->when;  
  9.     struct dst_entry *dst = NULL;  
  10. #ifdef CONFIG_SYN_COOKIES  
  11.     int want_cookie = 0;  
  12. #else  
  13. #define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */  
  14. #endif  
  15.   
  16.     /* Never answer to SYNs send to broadcast or multicast */  
  17.     if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))  
  18.         goto drop;  
  19.   
  20.     /* TW buckets are converted to open requests without 
  21.      * limitations, they conserve resources and peer is 
  22.      * evidently real one. 
  23.      */  
  24.     if (inet_csk_reqsk_queue_is_full(sk) && !isn) {  
  25. #ifdef CONFIG_SYN_COOKIES  
  26.         if (sysctl_tcp_syncookies) {  
  27.             want_cookie = 1;  
  28.         } else  
  29. #endif  
  30.         goto drop;  
  31.     }  
  32.   
  33.     /* Accept backlog is full. If we have already queued enough 
  34.      * of warm entries in syn queue, drop request. It is better than 
  35.      * clogging syn queue with openreqs with exponentially increasing 
  36.      * timeout. 
  37.      */  
  38.     if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)  
  39.         goto drop;  
  40.         /* 分配一个request_sock*/  
  41.     req = inet_reqsk_alloc(&tcp_request_sock_ops);  
  42.     if (!req)  
  43.         goto drop;  
  44.   
  45. #ifdef CONFIG_TCP_MD5SIG  
  46.     tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops;  
  47. #endif  
  48.   
  49.     tcp_clear_options(&tmp_opt);  
  50.     tmp_opt.mss_clamp = 536;  
  51.     tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss;  
  52.         /* 解析TCP选项 */  
  53.     tcp_parse_options(skb, &tmp_opt, 0);  
  54.   
  55.     if (want_cookie && !tmp_opt.saw_tstamp)  
  56.         tcp_clear_options(&tmp_opt);  
  57.   
  58.     if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) {  
  59.         /* Some OSes (unknown ones, but I see them on web server, which 
  60.          * contains information interesting only for windows' 
  61.          * users) do not send their stamp in SYN. It is easy case. 
  62.          * We simply do not advertise TS support. 
  63.          */  
  64.         tmp_opt.saw_tstamp = 0;  
  65.         tmp_opt.tstamp_ok  = 0;  
  66.     }  
  67.     tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;  
  68.         /* 保存相关连接信息 */  
  69.     tcp_openreq_init(req, &tmp_opt, skb);  
  70.   
  71.     ireq = inet_rsk(req);  
  72.     ireq->loc_addr = daddr;  
  73.     ireq->rmt_addr = saddr;  
  74.     ireq->no_srccheck = inet_sk(sk)->transparent;  
  75.     ireq->opt = tcp_v4_save_options(sk, skb);  
  76.   
  77.     if (security_inet_conn_request(sk, skb, req))  
  78.         goto drop_and_free;  
  79.   
  80.     if (!want_cookie)  
  81.         TCP_ECN_create_request(req, tcp_hdr(skb));  
  82.   
  83.     if (want_cookie) {  
  84. #ifdef CONFIG_SYN_COOKIES  
  85.         syn_flood_warning(skb);  
  86.         req->cookie_ts = tmp_opt.tstamp_ok;  
  87. #endif  
  88.         isn = cookie_v4_init_sequence(sk, skb, &req->mss);  
  89.     } else if (!isn) {  
  90.         struct inet_peer *peer = NULL;  
  91.   
  92.         /* VJ's idea. We save last timestamp seen 
  93.          * from the destination in peer table, when entering 
  94.          * state TIME-WAIT, and check against it before 
  95.          * accepting new connection request. 
  96.          * 
  97.          * If "isn" is not zero, this request hit alive 
  98.          * timewait bucket, so that all the necessary checks 
  99.          * are made in the function processing timewait state. 
  100.          */  
  101.         if (tmp_opt.saw_tstamp &&  
  102.             tcp_death_row.sysctl_tw_recycle &&  
  103.             (dst = inet_csk_route_req(sk, req)) != NULL &&  
  104.             (peer = rt_get_peer((struct rtable *)dst)) != NULL &&  
  105.             peer->v4daddr == saddr) {  
  106.             if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&  
  107.                 (s32)(peer->tcp_ts - req->ts_recent) >  
  108.                             TCP_PAWS_WINDOW) {  
  109.                 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);  
  110.                 goto drop_and_release;  
  111.             }  
  112.         }  
  113.         /* Kill the following clause, if you dislike this way. */  
  114.         else if (!sysctl_tcp_syncookies &&  
  115.              (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <  
  116.               (sysctl_max_syn_backlog >> 2)) &&  
  117.              (!peer || !peer->tcp_ts_stamp) &&  
  118.              (!dst || !dst_metric(dst, RTAX_RTT))) {  
  119.             /* Without syncookies last quarter of 
  120.              * backlog is filled with destinations, 
  121.              * proven to be alive. 
  122.              * It means that we continue to communicate 
  123.              * to destinations, already remembered 
  124.              * to the moment of synflood. 
  125.              */  
  126.             LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI4/%u/n",  
  127.                        &saddr, ntohs(tcp_hdr(skb)->source));  
  128.             goto drop_and_release;  
  129.         }  
  130.   
  131.         isn = tcp_v4_init_sequence(skb);  
  132.     }  
  133.     tcp_rsk(req)->snt_isn = isn;  
  134.         /* 发送SYNACK包,如果设置SYN_COOKIES,就直接返回,并释放open_request */  
  135.     if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)  
  136.         goto drop_and_free;  
  137.   
  138.     inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);  
  139.     return 0;  
  140.   
  141. drop_and_release:  
  142.     dst_release(dst);  
  143. drop_and_free:  
  144.     reqsk_free(req);  
  145. drop:  
  146.     return 0;  
  147. }  

 linux中的做法是监听方对于新建的连接在3步握手完成前不建立对于的INET SOCKET,而是建立一个request_sock结构。该结构保存了

连接双方的相关信息,相互的结构关系如下图

 监听套接字连接请求结构说明

另外tcp中对synflood的应当机制也是在这里实现的,如果系统设置了syn_cookies的话。对于没有启用syn_cookies时,这该函数中会对应建立

一个request_sock结构,并加入到hash表中;否则,该函数并不建立这样一个结构,而是运用syn_cookies机制产生一个isn,然后发送了syn/ack

包后就直接返回,当下次client发送ACK包过来时,在tcp_v4_hnd_req函数中调用cookie_v4_check,该函数在验证通过后建立INET socket结构。

 

主动连接方收到SYNACK包后,也进入tcp_rcv_state_process,不过它有自己对应的INET SOCKET,并且处于SYN_SENT状态

[cpp] view plaincopy
  1. case TCP_SYN_SENT:  
  2.         queued = tcp_rcv_synsent_state_process(sk, skb, th, len);  
  3.         if (queued >= 0)  
  4.             return queued;  
  5.   
  6.         /* Do step6 onward by hand. */  
  7.         tcp_urg(sk, skb, th);  
  8.         __kfree_skb(skb);  
  9.         tcp_data_snd_check(sk);  
  10.         return 0;  

 

tcp_rcv_synsent_state_process函数处理在SYN_SENT状态的SOCKET。

[cpp] view plaincopy
  1. static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,  
  2.                      struct tcphdr *th, unsigned len)  
  3. {  
  4.     struct tcp_sock *tp = tcp_sk(sk);  
  5.     struct inet_connection_sock *icsk = inet_csk(sk);  
  6.     int saved_clamp = tp->rx_opt.mss_clamp;  
  7.   
  8.     tcp_parse_options(skb, &tp->rx_opt, 0);  
  9.   
  10.     if (th->ack) {  
  11.         /* rfc793: 
  12.          * "If the state is SYN-SENT then 
  13.          *    first check the ACK bit 
  14.          *      If the ACK bit is set 
  15.          *    If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send 
  16.          *        a reset (unless the RST bit is set, if so drop 
  17.          *        the segment and return)" 
  18.          * 
  19.          *  We do not send data with SYN, so that RFC-correct 
  20.          *  test reduces to: 
  21.          */  
  22.         if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)  
  23.             goto reset_and_undo;  
  24.                 /*如果时戳存在,则坚持时戳是否合法,retrans_stamp记录上次重传时间*/  
  25.         if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&  
  26.             !between(tp->rx_opt.rcv_tsecr, tp->retrans_stamp,  
  27.                  tcp_time_stamp)) {  
  28.             NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSACTIVEREJECTED);  
  29.             goto reset_and_undo;  
  30.         }  
  31.   
  32.         /* Now ACK is acceptable. 
  33.          * 
  34.          * "If the RST bit is set 
  35.          *    If the ACK was acceptable then signal the user "error: 
  36.          *    connection reset", drop the segment, enter CLOSED state, 
  37.          *    delete TCB, and return." 
  38.          */  
  39.   
  40.         if (th->rst) {  
  41.             tcp_reset(sk);  
  42.             goto discard;  
  43.         }  
  44.   
  45.         /* rfc793: 
  46.          *   "fifth, if neither of the SYN or RST bits is set then 
  47.          *    drop the segment and return." 
  48.          * 
  49.          *    See note below! 
  50.          *                                        --ANK(990513) 
  51.          */  
  52.         if (!th->syn)  
  53.             goto discard_and_undo;  
  54.   
  55.         /* rfc793: 
  56.          *   "If the SYN bit is on ... 
  57.          *    are acceptable then ... 
  58.          *    (our SYN has been ACKed), change the connection 
  59.          *    state to ESTABLISHED..." 
  60.          */  
  61.   
  62.         TCP_ECN_rcv_synack(tp, th);  
  63.                 /* snd_wl1记录对方窗口更新时的对方数据包序号*/  
  64.         tp->snd_wl1 = TCP_SKB_CB(skb)->seq;  
  65.                 /* 处理ACK,稍后详细讲解,注意最后一个参数是FLAG_SLOWPATH */  
  66.         tcp_ack(sk, skb, FLAG_SLOWPATH);  
  67.   
  68.         /* Ok.. it's good. Set up sequence numbers and 
  69.          * move to established. 
  70.          */  
  71.                 /* rcv_wup是窗口更新时记录的当前rcv_nxt */  
  72.         tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;  
  73.         tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;  
  74.   
  75.         /* RFC1323: The window in SYN & SYN/ACK segments is 
  76.          * never scaled. 
  77.          */  
  78.         tp->snd_wnd = ntohs(th->window);  
  79.         tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);  
  80.                 /* 对方没有窗口扩放,则设置相关变量*/  
  81.         if (!tp->rx_opt.wscale_ok) {  
  82.             tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0;  
  83.             tp->window_clamp = min(tp->window_clamp, 65535U);  
  84.         }  
  85.                 /* 时戳协商一致,以后每次发送TCP包都要设置时戳选项*/  
  86.         if (tp->rx_opt.saw_tstamp) {  
  87.             tp->rx_opt.tstamp_ok    = 1;  
  88.             tp->tcp_header_len =  
  89.                 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;  
  90.             tp->advmss       -= TCPOLEN_TSTAMP_ALIGNED;  
  91.             tcp_store_ts_recent(tp);  
  92.         } else {  
  93.             tp->tcp_header_len = sizeof(struct tcphdr);  
  94.         }  
  95.                 /* FACK 是在SACK基础上更好解决recovery算法 */  
  96.         if (tcp_is_sack(tp) && sysctl_tcp_fack)  
  97.             tcp_enable_fack(tp);  
  98.                 /* 为数据传输准备好MTU,MSS */  
  99.         tcp_mtup_init(sk);  
  100.         tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);  
  101.         tcp_initialize_rcv_mss(sk);  
  102.   
  103.         /* Remember, tcp_poll() does not lock socket! 
  104.          * Change state from SYN-SENT only after copied_seq 
  105.          * is initialized. */  
  106.         tp->copied_seq = tp->rcv_nxt;  
  107.         smp_mb();  
  108.         tcp_set_state(sk, TCP_ESTABLISHED);  
  109.   
  110.         security_inet_conn_established(sk, skb);  
  111.   
  112.         /* Make sure socket is routed, for correct metrics.  */  
  113.         icsk->icsk_af_ops->rebuild_header(sk);  
  114.   
  115.         tcp_init_metrics(sk);  
  116.   
  117.         tcp_init_congestion_control(sk);  
  118.   
  119.         /* Prevent spurious tcp_cwnd_restart() on first data 
  120.          * packet. 
  121.          */  
  122.         tp->lsndtime = tcp_time_stamp;  
  123.   
  124.         tcp_init_buffer_space(sk);  
  125.   
  126.         if (sock_flag(sk, SOCK_KEEPOPEN))  
  127.             inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp));  
  128.                 /* 如果没有窗口扩放选项,则为头部预测做准备*/  
  129.         if (!tp->rx_opt.snd_wscale)  
  130.             __tcp_fast_path_on(tp, tp->snd_wnd);  
  131.         else  
  132.             tp->pred_flags = 0;  
  133.   
  134.         if (!sock_flag(sk, SOCK_DEAD)) {  
  135.             sk->sk_state_change(sk);  
  136.             sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT);  
  137.         }  
  138.                 /* 握手第3步的ACK,如果有数据要发送,则随数据发出,否则马上发ACK*/  
  139.         if (sk->sk_write_pending ||  
  140.             icsk->icsk_accept_queue.rskq_defer_accept ||  
  141.             icsk->icsk_ack.pingpong) {  
  142.             /* Save one ACK. Data will be ready after 
  143.              * several ticks, if write_pending is set. 
  144.              * 
  145.              * It may be deleted, but with this feature tcpdumps 
  146.              * look so _wonderfully_ clever, that I was not able 
  147.              * to stand against the temptation 8)     --ANK 
  148.              */  
  149.             inet_csk_schedule_ack(sk);  
  150.             icsk->icsk_ack.lrcvtime = tcp_time_stamp;  
  151.             icsk->icsk_ack.ato    = TCP_ATO_MIN;  
  152.             tcp_incr_quickack(sk);  
  153.             tcp_enter_quickack_mode(sk);  
  154.             inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,  
  155.                           TCP_DELACK_MAX, TCP_RTO_MAX);  
  156.   
  157. discard:  
  158.             __kfree_skb(skb);  
  159.             return 0;  
  160.         } else {  
  161.             tcp_send_ack(sk);  
  162.         }  
  163.         return -1;  
  164.     }  
  165.   
  166.     /* No ACK in the segment */  
  167.   
  168.     if (th->rst) {  
  169.         /* rfc793: 
  170.          * "If the RST bit is set 
  171.          * 
  172.          *      Otherwise (no ACK) drop the segment and return." 
  173.          */  
  174.   
  175.         goto discard_and_undo;  
  176.     }  
  177.   
  178.     /* PAWS check. */  
  179.     if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp &&  
  180.         tcp_paws_check(&tp->rx_opt, 0))  
  181.         goto discard_and_undo;  
  182.         /* 同时打开,回复SYNACK报文*/  
  183.     if (th->syn) {  
  184.         /* We see SYN without ACK. It is attempt of 
  185.          * simultaneous connect with crossed SYNs. 
  186.          * Particularly, it can be connect to self. 
  187.          */  
  188.         tcp_set_state(sk, TCP_SYN_RECV);  
  189.   
  190.         if (tp->rx_opt.saw_tstamp) {  
  191.             tp->rx_opt.tstamp_ok = 1;  
  192.             tcp_store_ts_recent(tp);  
  193.             tp->tcp_header_len =  
  194.                 sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;  
  195.         } else {  
  196.             tp->tcp_header_len = sizeof(struct tcphdr);  
  197.         }  
  198.   
  199.         tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;  
  200.         tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;  
  201.   
  202.         /* RFC1323: The window in SYN & SYN/ACK segments is 
  203.          * never scaled. 
  204.          */  
  205.         tp->snd_wnd    = ntohs(th->window);  
  206.         tp->snd_wl1    = TCP_SKB_CB(skb)->seq;  
  207.         tp->max_window = tp->snd_wnd;  
  208.   
  209.         TCP_ECN_rcv_syn(tp, th);  
  210.   
  211.         tcp_mtup_init(sk);  
  212.         tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);  
  213.         tcp_initialize_rcv_mss(sk);  
  214.   
  215.         tcp_send_synack(sk);  
  216. #if 0  
  217.         /* Note, we could accept data and URG from this segment. 
  218.          * There are no obstacles to make this. 
  219.          * 
  220.          * However, if we ignore data in ACKless segments sometimes, 
  221.          * we have no reasons to accept it sometimes. 
  222.          * Also, seems the code doing it in step6 of tcp_rcv_state_process 
  223.          * is not flawless. So, discard packet for sanity. 
  224.          * Uncomment this return to process the data. 
  225.          */  
  226.         return -1;  
  227. #else  
  228.         goto discard;  
  229. #endif  
  230.     }  
  231.     /* "fifth, if neither of the SYN or RST bits is set then 
  232.      * drop the segment and return." 
  233.      */  
  234.   
  235. discard_and_undo:  
  236.     tcp_clear_options(&tp->rx_opt);  
  237.     tp->rx_opt.mss_clamp = saved_clamp;  
  238.     goto discard;  
  239.   
  240. reset_and_undo:  
  241.     tcp_clear_options(&tp->rx_opt);  
  242.     tp->rx_opt.mss_clamp = saved_clamp;  
  243.     return 1;  
  244. }  

 

接下来继续第3步,也就是上面的主动连接方发出的ACK到对方


原创粉丝点击