TCP connection Establishment Series-client receives Synack and sends ACK

Source: Internet
Author: User
Tags ack connection reset

Main content: The client receives the Synack, sends the ACK, completes the connection establishment.

Kernel version: 3.15.2

My blog: http://blog.csdn.net/zhangskd

Receiving entrance

Tcp_v4_rcv

|--> TCP_V4_DO_RCV

|-> tcp_rcv_state_process

|-> tcp_rcv_synsent_state_process

1. When the status is established, the processing is received with tcp_rcv_established ().

2. When the status is listen, it indicates that the sock is in a listening state and is used for passive open receive processing, including SYN and ACK.

3. When the status is not established or time_wait, use the tcp_rcv_state_process () process.

When the client actively establishes the connection, the status of the connection becomes syn_sent after the SYN segment is sent.

If you receive a synack segment at this point, the handler function is Tcp_rcv_state_process ().

int Tcp_v4_do_rcv (struct sock *sk, struct sk_buff *skb) {struct sock *rsk; #ifdef config_tcp_md5sig/* We really want     To reject the packet as early as possible if: * We ' re expecting a MD5 ' d packet and this is no MD5 TCP option.     * There is a MD5 option and we ' re not expecting one. */if (Tcp_v4_inbound_md5_hash (SK, SKB)) goto discard; #endif/* Receive processing with tcp_rcv_established () when the status is established *        /if (sk->sk_state = = tcp_established) {/* Fast path */struct dst_entry *DST = sk->sk_rx_dst;        Sock_rps_save_rxhash (SK, SKB);                if (DST) {if (Inet_sk (SK)->rx_dst_ifindex! = Skb->skb_iif | | Dst->ops->check (DST, 0) = = NULL) {                Dst_release (DST);            SK-&GT;SK_RX_DST = NULL;        }/* Process path when the connection was established */tcp_rcv_established (SK, SKB, TCP_HDR (SKB), Skb->len);    return 0; }/* Check message length, message checksum */if (Skb->len < Tcp_hdrlen (SKB) | | tcp_checksum_complete (SKB))       Goto Csum_err;         /* If the sock is in the listening state, the process of passive open, including receiving SYN or ACK */if (sk->sk_state = = Tcp_listen) {/* return value: * NULL, error        * Nsk = = SK, received SYN * NSK! = SK, received ACK */struct sock *nsk = Tcp_v4_hnd_req (SK, SKB);        if (! Nsk) goto Discard;            if (Nsk! = SK) {/* Receives ACK when */Sock_rps_save_rxhash (NSK, SKB);                if (Tcp_child_process (SK, NSK, SKB)) {/* Process the new sock */RSK = NSK;            Goto Reset;        } return 0;    }} else Sock_rps_save_rx (SK, SKB);        /* handles all states except established and time_wait, including the syn_sent status */if (tcp_rcv_state_process (SK, SKB, TCP_HDR (SKB), Skb->len)) {        RSK = SK;    Goto Reset; } return 0;reset:tcp_v4_send_reset (RSK, SKB);    /* Send passive RST package */DISCARD:KFREE_SKB (SKB);    Return 0;csum_err:tcp_inc_stats_bh (Sock_net (SK), tcp_mib_csumerrors);    TCP_INC_STATS_BH (Sock_net (SK), Tcp_mib_inerrs); goto Discard;}

The handler function when the connection state is not established or time_wait is tcp_rcv_state_process ().

/* This function implements the receiving procedure of RFC 793 for  * All states except established and time_wait. */in T tcp_rcv_state_process (struct sock *sk, struct sk_buff *skb, const struct TCPHDR *th, unsigned int len) {    struct tcp_s Ock *TP = Tcp_sk (SK);    struct Inet_connection_sock *icsk = INET_CSK (SK);    struct Request_sock *req;    int queued = 0;    bool acceptable;    U32 Synack_stamp;    Tp->rx_opt.saw_tstamp = 0;    Switch (sk->sk_state) {    ...    Case Tcp_syn_sent:/        * handle syn_sent state, mainly do:         * Judge the legality of Synack, update the connection information.         * Set the connection status to Tcp_established.         * Send Ack, may be sent immediately, may also delay sending.         *        /queued = tcp_rcv_synsent_state_process (sk, SKB, Th, len);        if (queued >= 0)            return queued;/* causes the calling function to send rst *                /Tcp_urg (SK, SKB, TH);/* To process emergency data */        * To send data and to check if expansion Send cache *        /Tcp_data_snd_check (SK);        return 0;    }    ...}

Syn_sent Status Processing

Tcp_rcv_synsent_state_process () is used for the processing of syn_sent state, and it is divided into two different scenarios.

(1) received the Synack

In general, you will receive the service-side synack, which is handled as follows:

Check whether the ACK_SEQ is legal.

If the timestamp option is used, check whether the echo timestamp is legitimate.

Check that the flag bit for TCP is legitimate.

If Synack is legal, update sock's various information.

Set the status of the connection to tcp_established and wake up the process of calling connect ().

Determine whether to send an ACK or delay the send immediately.

(2) receive the SYN

Before this side sends a SYN, and now receives a SYN, both sides initiate a connection request to the peer.

The process is as follows:

Set the connection status to Syn_recv.

Update the various sock information.

Constructs and sends Synack.

The receiver will also respond to the Synack, after which the processing process and the server-side receive ACK similar, can refer to the previous blog.

When the return value of tcp_rcv_synsent_state_process () is greater than 0 o'clock, it causes the upper calling function to send a passive rst.

Q: So in what case will the return value of this function be greater than 0?

A: An ACK segment is received, but the ack_seq sequence number is incorrect, or the echo timestamp is incorrect.

static int tcp_rcv_synsent_state_process (struct sock *sk, struct sk_buff *skb, const struct TCPHDR *th, unsigned int le    N) {struct Inet_connection_sock *icsk = INET_CSK (SK);    struct Tcp_sock *TP = Tcp_sk (SK);    struct Tcp_fastopen_cookie Foc = {. Len =-1};    int saved_clamp = tp->rx_opt.mss_clamp;    /* Full parsing of TCP options carried by SKB */tcp_parse_options (SKB, &tp->rx_opt, 0, &AMP;FOC); if (Tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) TP-&GT;RX_OPT.RCV_TSECR-= tp->tsoffset; /* Timestamp Offset */* If you carry an ACK flag, it is possible that synack */if (th->ack) {/* rfc793: * If the state is SY N-sent then first check the ACK bit * If the ACK bit is set * if the SEG. ACK <= ISS, or SEG. ACK > SND.        NXT, send * a reset (unless the RST bit is set, if so drop the segment * and return) "*/         /* Check Ack_seq:snd_una < ack_seq <= snd_nxt.    * If the SYN segment does not carry data, then the ACK_SEQ should be at this end of the ISN + 1.     */if (! After (TCP_SKB_CB (SKB)->ack_seq, Tp->snd_una) | |        After (TCP_SKB_CB (SKB)->ack_seq, tp->snd_nxt)) goto Reset_and_undo;         /* If the timestamp option is used, the echo timestamp must fall between the time of the first send SYN segment and the current time. */if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&!between (TP-&GT;RX_OPT.RCV            _TSECR, Tp->retrans_stamp, Tcp_time_stamp)) {NET_INC_STATS_BH (Sock_net (SK), linux_mib_pawsactiverejected);        Goto Reset_and_undo;         }/* Now ACK is acceptable.     * If the RST bit is set * If the ACK were acceptable then signal the user "error:connection reset", *         Drop the segment, enter CLOSED state, delete TCB, and return. "            */if (Th->rst) {/* If the RST flag bit is carried, the connection failed:) */Tcp_reset (SK);        Goto Discard;       }/* RFC793: * Fifth, if neither of the SYN or RST bits is set then drop the segment and return.  */* If neither RST nor SYN flag bit, discard this ack */if (! Th->syn) goto Discard_and_undo; /* RFC793: * If The SYN bit is on ... * was acceptable then ... * (Ousr syn has been acked), Chang E The connection state to established ... */* received a legitimate synack, the next to complete the establishment of the connection */* If the peer support Ecn,synack will only be set         The ECE flag is placed.         * Otherwise, the connection does not support ECN explicit congestion notification.        */tcp_ecn_rcv_synack (tp, TH);        /* Record the ACK sequence of the most recently updated Send window */TCP_INIT_WL (TP, TCP_SKB_CB (SKB)->seq);        /* Update the Send window to delete the confirmed SYN segment in the Send queue and take the time-delay sampling */tcp_ack (SK, SKB, Flag_slowpath); /* Ok. It ' s good. Set up sequence numbers and move to established. */tp->rcv_nxt = TCP_SKB_CB (SKB)->seq + 1; /* Update the receiving window to receive the next ordinal number */tp->rcv_wup = TCP_SKB_CB (SKB)->seq + 1;         /* Update the left end of the Receive window */* rfc1323:the window in SYN & syn/ack segments is never scaled. * Update the size of the peer receive window.         The window enlargement factor is not used when the handshake is three times. */Tp->snd_wnd = Ntohs (Th->window); /* If the connection does not support the window enlargement factor option */if (! Tp->rx_opt.wscale_ok) {Tp->rx_opt.snd_wscale = Tp->rx_opt.rcv_wsca            Le = 0;        Tp->window_clamp = min (Tp->window_clamp, 65535U);            }/* If the connection supports timestamp option */if (tp->rx_opt.saw_tstamp) {TP-&GT;RX_OPT.TSTAMP_OK = 1;            Tp->tcp_header_len = sizeof (struct TCPHDR) + tcpolen_tstamp_aligned;            TP-&GT;ADVMSS-= tcpolen_tstamp_aligned; Tcp_store_ts_recent (TP);        /* Record the timestamp of the peer as the next send Echo value */} else {tp->tcp_header_len = sizeof (struct TCPHDR);         }/* Use Sack to consider whether to use Fack */if (Tcp_is_sack (TP) && sysctl_tcp_fack) tcp_enable_fack (TP); Tcp_mtu_init (SK); /* MTU Initialization of TCP */TCP_SYNC_MSS (SK, Icsk->icsk_pmtu_cookie); /* Update MSS */TCP_INITIALIZE_RCV_MSS (SK);         /* Initialize the MSS value to be effectively sent to the end */* Remember, Tcp_poll () does not lock socket! * Change state from Syn-sent only after Copied_seq is INitialized. */tp->copied_seq = tp->rcv_nxt;        /* Update the left end of unread data */SMP_MB ();         /* Come here, the connection is successfully established, NEXT: * Set the status of the connection to tcp_established.         * Wake-up call to connect () process.        */Tcp_finish_connect (SK, SKB); /* Fast Open option to process */if ((Tp->syn_fastopen | | tp->syn_data) && tcp_rcv_fastopen_synack (SK,        SKB, &AMP;FOC)) return-1;         /* If one of the following conditions is true, the ACK will not be sent immediately with a delay acknowledgement: * There is currently data waiting to be sent.         * Use the tcp_defer_accept option.         * The delay confirmation flag is 1.            */if (sk->sk_write_pending | | icsk->icsk_accept_queue->rskq_defer_accept | | Icsk->icsk_ack.pingpong) {inet_csk_schedule_ack (SK);/* Set icsk_ack_sched flag bit, indicating that there is an ACK to send */icsk-& Gt;icsk_ack.lrcvtime = Tcp_time_stamp; /* Update the last time the datagram was received */Tcp_enter_quickack_mode (SK); /* Enter Fast confirmation mode, then a quick confirmation *//////* Activates the delay confirmation timer with a timeout of 200ms, which means up to 200ms/Inet_csk_reset_xmit_timer (SK, ICSK _time_dack, Tcp_delack_maX, Tcp_rto_max);d Iscard: __KFREE_SKB (SKB);        return 0;    } else {tcp_send_ack (SK);/* immediately sends an ACK, which is the last ACK of the three-time handshake */} return-1; }/* No ACK in the segment */* If the received segment does not have an ACK flag, but the RST flag is set, then directly discard the */if (Th->rst) {/* rfc793: *         If the RST bit is set and no ACK, drop the segment and return.    */goto Discard_and_undo; }/* PAWS check. Check if the timestamp is legal */if (tp->rx_opt.ts_recent_tstamp && tp->rx_opt.saw_tstamp && tcp_paws_reject (&    amp;tp->rx_opt, 0)) Goto Discard_and_undo; /* received the SYN segment, that is, open */if (Th->syn) {/* We see SYN without ACK. It is attempt of simultaneous connect * with crossed SYNs.         Particularly, it can be connect to self.          */* After the SYN is sent, the status is Syn_sent, and if the SYN is received at this time, the * status becomes SYN_RECV.        */Tcp_set_state (SK, TCP_SYN_RECV); if (tp->rx_opt.saw_tstamp) {TP-&GT;RX_OPT.TSTAMP_OK = 1;            Tcp_store_ts_recent (TP);        /* Record the timestamp of the peer as the next sent Echo value */Tp->tcp_header_len = sizeof (TCPHDR) + tcpolen_tstamp_aligned;        } else {tp->tcp_header_len = sizeof (struct TCPHDR); } TP-&GT;RCV_NXT = TCP_SKB_CB (SKB)->seq + 1; /* Update the receiving window to receive the next ordinal number */tp->rcv_wup = TCP_SKB_CB (SKB)->seq + 1;         /* Update the left end of the Receive window */* rfc1323:the window in SYN & syn/ack segments is never scaled. * Update the size of the peer receive window.         The window enlargement factor is not used when the handshake is three times.        */Tp->snd_wnd = Ntohs (Th->window);  TP-&GT;SND_WL1 = TCP_SKB_CB (SKB)->seq; /* Record the ACK ordinal of the most recently updated Send window */Tp->max_window = tp->snd_wnd;         /* The maximum advertised window for the peer currently seen */* If the Ecn,syn support is set to the ECE and CWR flags.         * Otherwise, the connection does not support ECN explicit congestion notification.        */Tcp_ecn_rcv_syn (tp, TH); Tcp_mtu_init (SK); /* MTU Initialization of TCP */TCP_SYNC_MSS (SK, Icsk->icsk_pmtu_cookie); /* Update MSS */TCP_INITIALIZE_RCV_MSS (SK); /* Initialize the MSS value to be sent efficiently////construct and send Synack */Tcp_send_synacK (SK);    Goto Discard;    }discard_and_undo:tcp_clear_options (&tp->rx_opt);    Tp->rx_opt.mss_clamp = Saved_clamp;    Goto discard;reset_and_undo:tcp_clear_options (&tp->rx_opt);    Tp->rx_opt.mss_clamp = Saved_clamp; return 1;}

When open at the same time, in the Syn_sent state, after receiving the SYN segment, the status becomes Syn_recv, and then the Synack is sent.

After you receive the legal Synack, you can complete the connection setup.

/* Send a crossed syn-ack during socket establishment. * Warning:this routine must only is called when we had already * sent a SYN packet that crossed the incoming SYN that CA Used this * routine to get called. If This assumption fails then the initial Rcv_wnd * and Rcv_wscale values won't is correct.    */int Tcp_send_synack (struct sock *sk) {struct Sk_buff *skb; SKB = Tcp_write_queue_head (SK); /* The first segment of the send queue, that is, the SYN segment */if (SKB = = NULL | |! (TCP_SKB_CB (SKB)->tcp_flags & Tcphdr_syn))        {pr_debug ("%s:wrong queue state\n", __func__);    Return-efault; } if (! (TCP_SKB_CB (SKB)->tcp_flags & Tcphdr_ack))         {/* If the SKB is cloned and has multiple users, you cannot modify this SKB directly. * Clone a private nskb at this time, replacing the previous one.         Then you can modify it arbitrarily. */if (skb_cloned (SKB)) {struct Sk_buff *nskb = skb_copy (SKB, gfp_atomic);/* Clone one copy */if (n            SKB = = NULL) Return-enomem; Tcp_unlink_write_queue (SKB, SK); /* Remove SKB from the Send queue */Skb_header_relEase (NSKB); /* Increase the reference count of the SKB load section */__tcp_add_write_queue_head (SK, NSKB); /* Put NSKB into the head of the Send queue */SK_WMEM_FREE_SKB (SK, SKB); /* Update Memory Usage */sk->sk_wmem_queued + = nskb->truesize; /* Update the total size of the Send queue */Sk_mem_charge (SK, nskb->truesize); /* Update the pre-allocated but unused memory size */SKB = NSKB;        /* The next use is exclusive NSKB */} TCP_SKB_CB (SKB)->tcp_flags |= tcphdr_ack; Tcp_ecn_send_synack (Tcp_sk (SK), SKB);    /* Set ECN flag bit */} TCP_SKB_CB (SKB)->when = Tcp_time_stamp; Return TCP_TRANSMIT_SKB (SK, SKB, 1, gfp_atomic); /* Send this synack segment */} static inline void Sk_wmem_free_skb (struct sock *sk, struct Sk_buff *skb) {/* Write queue has been sh    Runk recently */Sock_set_flag (SK, Sock_queue_shrunk); sk->sk_wmem_queued-= skb->truesize; /* Update the total size of the Send queue */Sk_mem_uncharge (SK, skb->truesize); /* Update the pre-allocated but unused memory size */__KFREE_SKB (SKB);}

Wake-up user process

Tcp_finish_connect () is used to complete the establishment of the connection, mainly to do the following things:

1. Place the status of the connection from Syn_sent to established.

2. Initialize the TCP-related variables according to the route cache.

3. Get the default congestion control algorithm.

4. Adjust the size of the send cache and the receive cache.

5. Activate the keepalive timer if the so_keepalive option is used.

6. Wake up the process on this socket waiting queue (that is, the process that called connect).

If an asynchronous notification is used, the Send Sigio notification process on the asynchronous notification queue is writable.

void Tcp_finish_connect (struct sock *sk, struct sk_buff *skb) {struct Tcp_sock *tp = Tcp_sk (SK);    struct Inet_connection_sock *icsk = INET_CSK (SK);    /* Connection status changed from Syn_sent to established */Tcp_set_state (SK, tcp_established);        if (SKB! = NULL) {icsk->icsk_af_ops->sk_rx_dst_set (SK, SKB);    Security_inet_conn_established (SK, SKB);    }/* Make sure socket are routed, for correct metrics */Icsk->icsk_af_ops->rebuild_header (SK);    /* Initialize TCP related variables */tcp_init_metrics (SK) According to the route cache;    /* Get the default TCP congestion control algorithm */Tcp_init_congestion_control (SK); /* Prevent spurious Tcp_cwnd_restart () on first data packet. */tp->lsndtime = Tcp_time_stamp;    /* The time of the recent contract */* Adjust the Send cache and receive cache size */tcp_init_buffer_space (SK); /* If the so_keepalive option is used, activate the keepalive timer */if (Sock_flag (SK, Sock_keepopen)) Inet_csk_reset_keepalive_timer (SK, KeepAlive    _time_when (TP)); /* If the on-side window enlargement factor is 0 */if (! Tp->rx_opt.snd_wscale) __tcp_fast_path_on (TP, Tp->snd_wnd); /* SettingsFirst Prediction field */Else Tp->pred_flags = 0;         if (! Sock_flag (SK, Sock_dead)) {/* point to Sock_def_wakeup, Wake Call to connect () process */Sk->sk_state_change (SK);    /* If asynchronous notifications are used, send Sigio notification process writable */Sk_wake_async (SK, Sock_wake_io, poll_out); }}

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

TCP connection Establishment Series-client receives Synack and sends ACK

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.