TCP被動打開 之 第二次握手-發送SYN+ACK


假定客戶端執行主動打開,發送syn包到服務器,服務器執行完該包的第一次握手操作后,調用af_ops->send_synack向客戶端發送syn+ack包,該回調實際調用tcp_v4_send_synack函數;

 1 int tcp_conn_request(struct request_sock_ops *rsk_ops,
 2              const struct tcp_request_sock_ops *af_ops,
 3              struct sock *sk, struct sk_buff *skb)
 4 {
 5         /* 第一次握手的服務器處理 */
 6  
 7         /* 發送syn+ack */
 8         af_ops->send_synack(sk, dst, &fl, req, &foc,
 9                     !want_cookie ? TCP_SYNACK_NORMAL :
10                            TCP_SYNACK_COOKIE);
11     return 0;
12 }

 

tcp_v4_send_synack完成路由查找,構造syn+ack包,構造ip包,然后發送出去;

 1 /*
 2  *    Send a SYN-ACK after having received a SYN.
 3  *    This still operates on a request_sock only, not on a big
 4  *    socket.
 5  */
 6 static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
 7                   struct flowi *fl,
 8                   struct request_sock *req,
 9                   struct tcp_fastopen_cookie *foc,
10                   enum tcp_synack_type synack_type)
11 {
12     const struct inet_request_sock *ireq = inet_rsk(req);
13     struct flowi4 fl4;
14     int err = -1;
15     struct sk_buff *skb;
16 
17     /* First, grab a route. */
18     /* 路由為空則查路由 */
19     if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
20         return -1;
21 
22     /* 構造syn+ack包 */
23     skb = tcp_make_synack(sk, dst, req, foc, synack_type);
24 
25     if (skb) {
26         /* 生成校驗碼 */
27         __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
28 
29         /* 構造ip包並發送 */
30         err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,
31                         ireq->ir_rmt_addr,
32                         ireq->opt);
33 
34         /* 返回錯誤是否為本地阻塞判斷 */
35         err = net_xmit_eval(err);
36     }
37 
38     return err;
39 }

 

tcp_make_synack函數完成skb分配,tcp首部的構造;

  1 struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
  2                 struct request_sock *req,
  3                 struct tcp_fastopen_cookie *foc,
  4                 enum tcp_synack_type synack_type)
  5 {
  6     struct inet_request_sock *ireq = inet_rsk(req);
  7     const struct tcp_sock *tp = tcp_sk(sk);
  8     struct tcp_md5sig_key *md5 = NULL;
  9     struct tcp_out_options opts;
 10     struct sk_buff *skb;
 11     int tcp_header_size;
 12     struct tcphdr *th;
 13     int mss;
 14 
 15     /* 分配skb */
 16     skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC);
 17     if (unlikely(!skb)) {
 18         dst_release(dst);
 19         return NULL;
 20     }
 21     /* Reserve space for headers. */
 22     /* 保留頭部空間 */
 23     skb_reserve(skb, MAX_TCP_HEADER);
 24 
 25     switch (synack_type) {
 26     case TCP_SYNACK_NORMAL:
 27         /* skb關聯控制塊 */
 28         skb_set_owner_w(skb, req_to_sk(req));
 29         break;
 30     case TCP_SYNACK_COOKIE:
 31         /* Under synflood, we do not attach skb to a socket,
 32          * to avoid false sharing.
 33          */
 34         break;
 35     case TCP_SYNACK_FASTOPEN:
 36         /* sk is a const pointer, because we want to express multiple
 37          * cpu might call us concurrently.
 38          * sk->sk_wmem_alloc in an atomic, we can promote to rw.
 39          */
 40         skb_set_owner_w(skb, (struct sock *)sk);
 41         break;
 42     }
 43 
 44     /* 設置路由緩存 */
 45     skb_dst_set(skb, dst);
 46 
 47     /* mss取從路由表中查詢的mss與user_mss之間的較小值 */
 48     mss = tcp_mss_clamp(tp, dst_metric_advmss(dst));
 49 
 50     memset(&opts, 0, sizeof(opts));
 51 #ifdef CONFIG_SYN_COOKIES
 52     if (unlikely(req->cookie_ts))
 53         skb->skb_mstamp.stamp_jiffies = cookie_init_timestamp(req);
 54     else
 55 #endif
 56 
 57     /* 獲取時間戳 */
 58     skb_mstamp_get(&skb->skb_mstamp);
 59 
 60 #ifdef CONFIG_TCP_MD5SIG
 61     rcu_read_lock();
 62     md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req));
 63 #endif
 64 
 65     /* 設置hash */
 66     skb_set_hash(skb, tcp_rsk(req)->txhash, PKT_HASH_TYPE_L4);
 67     /* 設置tcp選項 */
 68     tcp_header_size = tcp_synack_options(req, mss, skb, &opts, md5, foc) +
 69               sizeof(*th);
 70 
 71     /* 構造填充tcp頭 */
 72     skb_push(skb, tcp_header_size);
 73     skb_reset_transport_header(skb);
 74 
 75     th = (struct tcphdr *)skb->data;
 76     memset(th, 0, sizeof(struct tcphdr));
 77     /* 設置syn+ack標記 */
 78     th->syn = 1;
 79     th->ack = 1;
 80     tcp_ecn_make_synack(req, th);
 81     /* 設置源目的端口 */
 82     th->source = htons(ireq->ir_num);
 83     th->dest = ireq->ir_rmt_port;
 84     /* Setting of flags are superfluous here for callers (and ECE is
 85      * not even correctly set)
 86      */
 87 
 88     /* 初始化無數據的skb,標志為syn+ack */
 89     tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
 90                  TCPHDR_SYN | TCPHDR_ACK);
 91 
 92     /* 設置序號和確認序號 */
 93     th->seq = htonl(TCP_SKB_CB(skb)->seq);
 94     /* XXX data is queued and acked as is. No buffer/window check */
 95     th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
 96 
 97     /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
 98     /* 設置窗口 */
 99     th->window = htons(min(req->rsk_rcv_wnd, 65535U));
100 
101     /* 寫入選項 */
102     tcp_options_write((__be32 *)(th + 1), NULL, &opts);
103 
104     /* 設置首部長度 */
105     th->doff = (tcp_header_size >> 2);
106     __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
107 
108 #ifdef CONFIG_TCP_MD5SIG
109     /* Okay, we have all we need - do the md5 hash if needed */
110     if (md5)
111         tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
112                            md5, req_to_sk(req), skb);
113     rcu_read_unlock();
114 #endif
115 
116     /* Do not fool tcpdump (if any), clean our debris */
117     skb->tstamp = 0;
118     return skb;
119 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM