Linux2.6 kernel protocol stack series-TCP protocol 2. Receive, linux2.6 -- tcp
1. queuing mechanism
When receiving incoming TCP packets, there are three Queues:
● Queue to be processed
● Pre-queuing queue
● Receiving queue
The receiving queue contains the processed TCP data segment. That is, all the protocol headers are removed and the data is being copied to the user application. The receiving queue contains all the data segments received in order. The TCP data segments in the other two queues need further processing.
TCP packets are first processed by tcp_v4_rcv. This function determines whether to process packets or queue in the waiting queue and pre-queue.
/* Transmission layer message processing entry */int tcp_v4_rcv (struct sk_buff * skb ){... /* first obtain a socket rotation lock. When entering this routine, disable the lower half function because the routine is interrupted from NET SoftIRQ. */Bh_lock_sock (sk);/* lock the set interface in Soft Interrupt */ret = 0;/* If the process does not have access to the transfer control block, then, perform a normal reception * // * and check whether the socket is in use. When someone is using this socket, (sk)-> sk_lock.owner is 1. When reading, writing, and modifying a socket, the socket will be in use. */If (! Sock_owned_by_user (sk) {/* Call tcp_prequeue to send the TCP packet to the pre-queuing queue. */If (! Tcp_prequeue (sk, skb)/* process the data segment directly if TCP cannot be queued. */Ret = tcp_v4_do_rcv (sk, skb);} else/* Add the message to the backup queue and process the message when the user process unlocks the control block */sk_add_backlog (sk, skb ); bh_unlock_sock (sk );...}
2. tcp_rcv_established () Processing
Here we will not describe all the processing details. We will only describe the processing and queuing mechanism. First, we discuss the possibility of directly copying data to the user buffer. If not, remove the TCP header and send the data segment to the receiving queue.
/* When the connection is established normally, process the received TCP packet */int tcp_rcv_established (struct sock * sk, struct sk_buff * skb, struct tcphdr * th, unsigned len) {struct tcp_sock * tp = tcp_sk (sk );...} else {/* data load available */int eaten = 0; /* determine whether the receiving segment can be directly copied to the user space * // * Whether the serial number of the receiving segment is equal to the serial number before the segment that has not been copied from the kernel space to the user space, that is, the receiving queue should be empty * // * the length of user data in the TCP segment is smaller than the remaining available amount in the user space cache */if (tp-> ucopy. task = current & tp-> copied_seq = tp-> rcv_nxt & len-tcp_header_len <= tp-> ucop Y. len & sock_owned_by_user (sk) {/* the lock is held by the current process */_ set_current_state (TASK_RUNNING);/* copy the SKB data to the user buffer */if (! Round (sk, skb, tcp_header_len) {if (tcp_header_len = (sizeof (struct tcphdr) + round) & tp-> rcv_nxt = tp-> rcv_wup) /* update timestamp */tcp_store_ts_recent (tp); tcp_rcv_rtt_measure_ts (tp, skb);/* update round-trip time */_ skb_pull (skb, tcp_header_len ); /* The next expected segment number * // * update tp-> rcv_nxt to the end serial number of the processed packet. */Tp-> rcv_nxt = TCP_SKB_CB (skb)-> end_seq; NET_INC_STATS_BH (linux_mib_tcphitstouser); eaten = 1 ;}} if (! Eaten ){... /* move the pointer and skip the TCP Header, that is, remove the TCP Header */_ skb_pull (skb, tcp_header_len);/* Add the data packet to the receiving queue for caching, wait for the process to actively read */_ skb_queue_tail (& sk-> sk_receive_queue, skb);/* set the owner of skb to the current port, update the total number of received cache and pre-allocated cache length */sk_stream_set_owner_r (skb, sk);/* update rcv_nxt to the end serial number of the segment */tp-> rcv_nxt = TCP_SKB_CB (skb) -> end_seq ;}... return 0 ;}
3.
Too many contents to be continued