Il existe un pilote de périphérique pour chaque type de NIC. De l'intérieur, Linux appellera TOUJOURS une routine standard de haut niveau: "netif_rx [net/core/dev.c]", qui contrôlera à quel protocole de niveau 3 le cadre appartient, et il appellera la bonne fonction de niveau 3 (ainsi nous utiliserons un pointeur vers la fonction pour déterminer laquelle est la bonne). (There exists a device driver for each kind of NIC. Inside it, Linux will ALWAYS call a standard high level routing: "netif_rx [net/core/dev.c]", which will controls what 3 level protocol the frame belong to, and it will call the right 3 level function (so we'll use a pointer to the function to determine which is right).
Nous allons voir maintenant un exemple de ce qui se produit quand nous envoyons un paquet TCP à Linux, à partir de l'appel ''netif_rx [net/core/dev.c] ''.
|netif_rx
|__skb_queue_tail
|qlen++
|* simple pointer insertion *
|cpu_raise_softirq
|softirq_active(cpu) |= (1 << NET_RX_SOFTIRQ) // met l'octet NET_RX_SOFTIRQ dans le vecteur BH
Fonctions:
Une fois que l'interaction d'IRQ est finie, nous devons suivre la prochaine partie de la vie du cadre et examiner ce que fait NET_RX_SOFTIRQ.
Nous appellerons ensuite ''net_rx_action [net/core/dev.c]'' selon "net_dev_init [net/core/dev.c]".
|net_rx_action
|skb = __skb_dequeue (the exact opposite of __skb_queue_tail)
|for (ptype = first_protocol; ptype < max_protocol; ptype++) // Determine
|if (skb->protocol == ptype) // what is the network protocol
|ptype->func -> ip_rcv // according to ''struct ip_packet_type [net/ipv4/ip_output.c]''
**** MAINTENANT NOUS SAVONS QUEL PAQUET EST IP ****
|ip_rcv
|NF_HOOK (ip_rcv_finish)
|ip_route_input // cherche dans la table de routage pour déterminer la fonction à appeler
|skb->dst->input -> ip_local_deliver // selon la précédente vérification de la table de routage, la destination est la machine locale
|ip_defrag // rassemble les fragments IP
|NF_HOOK (ip_local_deliver_finish)
|ipprot->handler -> tcp_v4_rcv // selon ''tcp_protocol [include/net/protocol.c]''
**** MAINTENANT NOUS SAVONS QUEL PAQUET EST TCP ****
|tcp_v4_rcv
|sk = __tcp_v4_lookup
|tcp_v4_do_rcv
|switch(sk->state)
*** Le paquet peut être envoyé à la tâche qui utilise une connexion (socket) relative ***
|case TCP_ESTABLISHED:
|tcp_rcv_established
|__skb_queue_tail // enfile le packet vers la connexion
|sk->data_ready -> sock_def_readable
|wake_up_interruptible
*** Le packet est toujours pris en main par le 3-way TCP handshake ***
|case TCP_LISTEN:
|tcp_v4_hnd_req
|tcp_v4_search_req
|tcp_check_req
|syn_recv_sock -> tcp_v4_syn_recv_sock
|__tcp_v4_lookup_established
|tcp_rcv_state_process
*** 3-Way TCP Handshake ***
|switch(sk->state)
|case TCP_LISTEN: // We received SYN
|conn_request -> tcp_v4_conn_request
|tcp_v4_send_synack // Send SYN + ACK
|tcp_v4_synq_add // set SYN state
|case TCP_SYN_SENT: // we received SYN + ACK
|tcp_rcv_synsent_state_process
tcp_set_state(TCP_ESTABLISHED)
|tcp_send_ack
|tcp_transmit_skb
|queue_xmit -> ip_queue_xmit
|ip_queue_xmit2
|skb->dst->output
|case TCP_SYN_RECV: // We received ACK
|if (ACK)
|tcp_set_state(TCP_ESTABLISHED)
Fonctions ci-dessous:
Description:
SERVEUR (ECOUTE) CLIENT (CONNECTING)
SYN
<-------------------
SYN + ACK
------------------->
ACK
<-------------------
3-Way TCP handshake