tcp_data_queue作用为数据段的接收处理,其中分为多种情况:
(1) 无数据,释放skb,返回;
(2) 预期接收的数据段,a. 进行0窗口判断;b. 进程上下文,复制数据到用户空间;c. 不满足b或者b未完整拷贝此skb的数据段,则加入到接收队列;d. 更新下一个期望接收的序号;e. 若有fin标记,则处理fin;f. 乱序队列不为空,则处理乱序;g. 快速路径的检查和设置;h. 唤醒用户空间进程读取数据;
(3) 重传的数据段,进入快速ack模式,释放该skb;
(4) 窗口以外的数据段,进入快速ack模式,释放该skb;
(5) 数据段重叠,在进行0窗口判断之后,进行(2)中的加入接收队列,以及>=d的流程;
(6) 乱序的数据段,调用tcp_data_queue_ofo进行乱序数据段的接收处理;
1 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) 2 { 3 struct tcp_sock *tp = tcp_sk(sk); 4 bool fragstolen = false; 5 int eaten = -1; 6 7 /* 无数据 */ 8 if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { 9 __kfree_skb(skb); 10 return; 11 } 12 13 /* 删除路由缓存 */ 14 skb_dst_drop(skb); 15 16 /* 去掉tcp首部 */ 17 __skb_pull(skb, tcp_hdr(skb)->doff * 4); 18 19 tcp_ecn_accept_cwr(tp, skb); 20 21 tp->rx_opt.dsack = 0; 22 23 /* Queue data for delivery to the user. 24 * Packets in sequence go to the receive queue. 25 * Out of sequence packets to the out_of_order_queue. 26 */ 27 /* 预期接收的数据段 */ 28 if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { 29 /* 窗口为0,不能接收数据 */ 30 if (tcp_receive_window(tp) == 0) 31 goto out_of_window; 32 33 /* Ok. In sequence. In window. */ 34 /* 进程上下文 */ 35 36 /* 当前进程读取数据 */ 37 if (tp->ucopy.task == current && 38 /* 用户空间读取序号与接收序号一致&& 需要读取的数据不为0 */ 39 tp->copied_seq == tp->rcv_nxt && tp->ucopy.len && 40 /* 被用户空间锁定&& 无紧急数据 */ 41 sock_owned_by_user(sk) && !tp->urg_data) { 42 43 /* 带读取长度和数据段长度的较小值 */ 44 int chunk = min_t(unsigned int, skb->len, 45 tp->ucopy.len); 46 /* 设置running状态 */ 47 __set_current_state(TASK_RUNNING); 48 49 /* 拷贝数据 */ 50 if (!skb_copy_datagram_msg(skb, 0, tp->ucopy.msg, chunk)) { 51 tp->ucopy.len -= chunk; 52 tp->copied_seq += chunk; 53 /* 完整读取了该数据段 */ 54 eaten = (chunk == skb->len); 55 56 /* 调整接收缓存和窗口 */ 57 tcp_rcv_space_adjust(sk); 58 } 59 } 60 61 /* 未拷贝到用户空间或者未拷贝完整数据段 */ 62 if (eaten <= 0) { 63 queue_and_out: 64 /* 没有拷贝到用户空间,对内存进行检查 */ 65 if (eaten < 0) { 66 if (skb_queue_len(&sk->sk_receive_queue) == 0) 67 sk_forced_mem_schedule(sk, skb->truesize); 68 else if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) 69 goto drop; 70 } 71 72 /* 添加到接收队列 */ 73 eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); 74 } 75 76 /* 更新下一个期望接收的序号*/ 77 tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); 78 /* 有数据 */ 79 if (skb->len) 80 tcp_event_data_recv(sk, skb); 81 82 /* 标记有fin,则处理 */ 83 if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) 84 tcp_fin(sk); 85 86 /* 乱序队列有数据,则处理 */ 87 if (!RB_EMPTY_ROOT(&tp->out_of_order_queue)) { 88 89 /* 将乱序队列中的数据段转移到接收队列 */ 90 tcp_ofo_queue(sk); 91 92 /* RFC2581. 4.2. SHOULD send immediate ACK, when 93 * gap in queue is filled. 94 */ 95 /* 乱序数据段处理完毕,需要立即发送ack */ 96 if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) 97 inet_csk(sk)->icsk_ack.pingpong = 0; 98 } 99 100 if (tp->rx_opt.num_sacks) 101 tcp_sack_remove(tp); 102 103 /* 快路检查 */ 104 tcp_fast_path_check(sk); 105 106 /* 向用户空间拷贝了数据,则释放skb */ 107 if (eaten > 0) 108 kfree_skb_partial(skb, fragstolen); 109 110 /* 不在销毁状态,则唤醒进程读取数据 */ 111 if (!sock_flag(sk, SOCK_DEAD)) 112 sk->sk_data_ready(sk); 113 return; 114 } 115 116 /* 重传 */ 117 if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { 118 /* A retransmit, 2nd most common case. Force an immediate ack. */ 119 NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); 120 tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); 121 122 out_of_window: 123 /* 进入快速ack模式 */ 124 tcp_enter_quickack_mode(sk); 125 126 /* 调度ack */ 127 inet_csk_schedule_ack(sk); 128 drop: 129 /* 释放skb */ 130 tcp_drop(sk, skb); 131 return; 132 } 133 134 /* Out of window. F.e. zero window probe. */ 135 /* 窗口以外的数据,比如零窗口探测报文段 */ 136 if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) 137 goto out_of_window; 138 139 /* 进入快速ack模式 */ 140 tcp_enter_quickack_mode(sk); 141 142 /* 数据段重叠 */ 143 if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { 144 /* Partial packet, seq < rcv_next < end_seq */ 145 SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X ", 146 tp->rcv_nxt, TCP_SKB_CB(skb)->seq, 147 TCP_SKB_CB(skb)->end_seq); 148 149 tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); 150 151 /* If window is closed, drop tail of packet. But after 152 * remembering D-SACK for its head made in previous line. 153 */ 154 /* 窗口为0,不能接收 */ 155 if (!tcp_receive_window(tp)) 156 goto out_of_window; 157 goto queue_and_out; 158 } 159 160 /* 接收乱序数据段 */ 161 tcp_data_queue_ofo(sk, skb); 162 }