First, find out the important data structure
Two global variables: struct socket * socket [nr_socket]; struct proto_ops * pops [nr_protocol];
BSD Socket Layer
Struct socket * sock/struct proto_ops * Ops
======================================
Inet layer struct proto_ops inet_proto_ops = {inet_creat, inet_read,...} serves as the ops operation function of the socket layer
Struct sock * sk/struct proto * Protocol
======================================
TCP/UDP/ICMP Layer
Struct proto tcp_prot = {tcp_read, tcp_write,..., ip_queue_transmit} is used as the operation function of sock protocol. Bind is initialized during sock_create ().
Strcut proto udp_prot
======================================
IP/arp Layer
Struct inet_protocol inet_protocol_base ={& tcp_protocol, & udp_protocol, & icmp_protocol} is bound to inet_protocol_base during initialization
======================================
Dev Layer
Struct packet_type ptype_base ={& ip_packet, & arp_packet}
Initialization Process sock_init ()-> ddi_init ()-> inet_proto_init ()-> socket_register ()
Receive data packets
When a data packet arrives at the NIC asynchronously, the NIC checks whether the packet is sent to the local Nic. If not, the NIC is discarded. If yes, the NIC interrupt information is sent. The CPU executes the NIC drive interrupt program ei_interrrupt () reading the NIC register status and other work, call ei_receive () to read data from the NIC data register and encapsulate the data into a struct sk_buff structure, and then call netrx_if () insert the SKB data packet to the SKB queue named backlog, skb_queue_tail (SKB), mark the lower half of the interrupt, and the kernel executes the program inet_bh () of the lower half of the interrupt when appropriate ().
In inet_bh (), read the dequeue_skb (backlog) of the backlog queue cyclically and call Dev-> type_transmit (SKB) to obtain the packet type 0x800 (ip_packet ), 0x806 (arp_packet), call struct packet_type ptype_base [type] func () based on packet type to process the corresponding data packets. take IP packek as an example, call ip_recv (SKB) for processing, and call address_check (). If the des IP address in the data packet is not the IP address sent to the local machine, go to ip_forward () to process data forwarding; otherwise, determine whether the data packet has been processed by IP fragment; If yes, reorganize the ip_defragment () data packet; otherwise, determine the protocol type (TCP, UDP, ICMP), respectively calling the corresponding protocol handler stru CT inet_protocol inet_proto_base [type]-> handler (). For TCP, tcp_recv (SKB) is used. Locate struct sock * Sk in tcp_array [] based on the port number in the TCP header, perform TCP status Processing Based on the sk status. If it is already established, call tcp_data () to insert the SKB to the sk-> rqueue queue, wait for the upper layer to call read/Recv/recvfrom to read from the rqueue of the receiving queue.
The call sequence is ei_interrupt ()-> ei_receive ()-> netif_rx ()-> inet_bh ()-> packet_type_base [type]-> func () (ip_recv) -> inet_proto_base [type]-> handler () (tcp_recv)-> tcp_data ()
Packet transmission
Call sock_write/sock_send at the socket layer by using the write ()/send () or other systems to adjust the operation function of struct proto_ops of struct socket to inet_write/inet_send at the inet layer, then, use the struct proto operation function in struct sock. For TCP, tcp_write () is used to construct the SKB. Call ip_build_header () to construct the IP header, and then construct the TCP header, call tcp_send_skb (SKB) to perform TCP segment processing based on the size of the MSS. Call queue_transmit in struct proto, that is, ip_queue_transmit (SKB) check the size of the data packet and MTU to determine whether to perform sharding. If yes, go to ip_fragment (SKB); otherwise, find route_table. Determine the MAC address of the next hop and construct Dev-> build_header to generate the Ethernet header. Then call dev_queue_transmit (SKB) and call Dev-> hard_start_xmit to send data to the ei_start_xmit () in the device driver, if the sending fails, insert the SKB to Dev-> buff [3] and wait for dev_transmit ()-> dev_queue_transmit () to be sent in inet_bh.
Call the sequential write ()/send ()-> sock_write ()/sock_send ()-> inet_write ()/inet_send ()-> tcp_write ()-> tcp_send_skb () -> ip_queue_transmit ()-> dev_queue_transmit ()-> ei_start_xmit ()
TCP/IP protocol data sending and receiving process