Calling graph for Transmission and Reception

It may be worth clarifying further the flow of control in the transmit and receive cases, where the hardware driver does use interrupts and so DSRs to tell the “foreground” when something asynchronous has occurred.

Transmission

  1. Some foreground task such as the application, SNMP “daemon”, DHCP management thread or whatever, calls into network stack to send a packet, or the stack decides to send a packet in response to incoming traffic such as a “ping” or ARP request.

  2. The driver calls the HRDWR_can_send() function in the hardware driver.

  3. HRDWR_can_send() returns the number of available "slots" in which it can store a pending transmit packet. If it cannot send at this time, the packet is queued outside the hardware driver for later; in this case, the hardware is already busy transmitting, so expect an interrupt as described below for completion of the packet currently outgoing.

  4. If it can send right now, HRDWR_send() is called. HRDWR_send() copies the data into special hardware buffers, or instructs the hardware to “send that.” It also remembers the key that is associated with this tx request.

  5. These calls return … time passes …

  6. Asynchronously, the hardware makes an interrupt to say “transmit is done.” The ISR quietens the interrupt source in the hardware and requests that the associated DSR be run.

  7. The DSR calls (or is) the eth_drv_dsr() function in the generic driver.

  8. eth_drv_dsr() in the generic driver awakens the “Network Delivery Thread” which calls the deliver function HRDWR_deliver() in the driver.

  9. The deliver function realizes that a transmit request has completed, and calls the callback tx-done function (sc->funs->eth_drv->tx_done)() with the same key that it remembered for this tx.

  10. The callback tx-done function uses the key to find the resources associated with this transmit request; thus the stack knows that the transmit has completed and its resources can be freed.

  11. The callback tx-done function also enquires whether HRDWR_can_send() now says “yes, we can send” and if so, dequeues a further transmit request which may have been queued as described above. If so, then HRDWR_send() copies the data into the hardware buffers, or instructs the hardware to "send that" and remembers the new key, as above. These calls then all return to the “Network Delivery Thread” which then sleeps, awaiting the next asynchronous event.

  12. All done …

Receive

  1. Asynchronously, the hardware makes an interrupt to say “there is ready data in a receive buffer.” The ISR quietens the interrupt source in the hardware and requests that the associated DSR be run.

  2. The DSR calls (or is) the eth_drv_dsr() function in the generic driver.

  3. eth_drv_dsr() in the generic driver awakens the “Network Delivery Thread” which calls the deliver function HRDWR_deliver() in the driver.

  4. The deliver function realizes that there is data ready and calls the callback receive function (sc->funs->eth_drv->recv)() to tell it how many bytes to prepare for.

  5. The callback receive function allocates memory within the stack (eg. MBUFs in BSD/Unix style stacks) and prepares a set of scatter-gather buffers that can accommodate the packet.

  6. It then calls back into the hardware driver routine HRDWR_recv(). HRDWR_recv() must copy the data from the hardware's buffers into the scatter-gather buffers provided, and return.

  7. The network stack now has the data in-hand, and does with it what it will. This might include recursive calls to transmit a response packet. When this all is done, these calls return, and the “Network Delivery Thread” sleeps once more, awaiting the next asynchronous event.