doc: net: Update the L2 documentation
The L2 documentation was describing functionality that has changed
recently. Now it should match the current reality.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
diff --git a/doc/reference/networking/net_l2.rst b/doc/reference/networking/net_l2.rst
index b3b96be..ba9984b 100644
--- a/doc/reference/networking/net_l2.rst
+++ b/doc/reference/networking/net_l2.rst
@@ -11,11 +11,10 @@
********
The L2 stack is designed to hide the whole networking link-layer part
-and the related device drivers from the higher IP stack. This is made
-through a unique object known as the "network interface object":
-:c:type:`struct net_if` declared in :file:`include/net/net_if.h`.
+and the related device drivers from the upper network stack. This is made
+through a :c:type:`struct net_if` declared in :file:`include/net/net_if.h`.
-The IP layer is unaware of implementation details beyond the net_if
+The upper layers are unaware of implementation details beyond the net_if
object and the generic API provided by the L2 layer in
:file:`include/net/net_l2.h` as :c:type:`struct net_l2`.
@@ -24,38 +23,40 @@
specific for that device, and optimized for working together.
Currently, there are L2 layers for Ethernet, IEEE 802.15.4 Soft-MAC,
-Bluetooth IPSP, and a dummy one, which is a generic layer example that
-can be used as a template for writing a new one.
+Bluetooth IPSP, CANBUS, OpenThread, WiFi and a dummy one, which is a generic
+layer example that can be used as a template for writing a new one.
L2 layer API
************
-In order to create an L2 layer, or even a driver for a specific L2
-layer, one needs to understand how the IP layer interacts with it and
-how the L2 layer is supposed to behave. The generic L2 API has 3
-functions:
+In order to create an L2 layer, or a driver for a specific L2 layer,
+one needs to understand how the L3 layer interacts with it and
+how the L2 layer is supposed to behave.
+See also :ref:`network stack architecture <ip_stack_architecture>` for
+more details. The generic L2 API has these functions:
-- recv: All device drivers, once they receive a packet which they put
- into a :c:type:`struct net_pkt`, will push this buffer to the IP
- core stack via :c:func:`net_recv_data()`. At this point, the IP core
+- ``recv()``: All device drivers, once they receive a packet which they put
+ into a :c:type:`struct net_pkt`, will push this buffer to the network
+ stack via :c:func:`net_recv_data()`. At this point, the network
stack does not know what to do with it. Instead, it passes the
- buffer along to the L2 stack's recv() function for handling. The L2
- stack does what it needs to do with the packet, for example, parsing
- the link layer header, or handling link-layer only packets. The
- recv() function will return NET_DROP in case of an erroneous packet,
+ buffer along to the L2 stack's ``recv()`` function for handling.
+ The L2 stack does what it needs to do with the packet, for example, parsing
+ the link layer header, or handling link-layer only packets. The ``recv()``
+ function will return NET_DROP in case of an erroneous packet,
NET_OK if the packet was fully consumed by the L2, or NET_CONTINUE
- if the IP stack should then handle it as an IP packet.
+ if the network stack should then handle it.
-- reserve: Prior to creating any network buffer content, the Zephyr
- core stack needs to know how much dedicated buffer space is needed
- for the L2 layer (for example, space for the link layer header). This
- reserve function returns the number of bytes needed.
+- ``send()``: Similar to receive function, the network stack will call this
+ function to actually send a network packet. All relevant link-layer content
+ will be generated and added by this function.
+ The ``send()`` function returns the number of bytes sent, or a negative
+ error code if there was a failure sending the network packet.
-- send: Similar to recv, the IP core stack will call this function to
- actually send a packet. All relevant link-layer content will be
- generated and added by this function. As for recv, send returns a
- verdict and can decide to drop the packet via NET_DROP if something
- wrong happened, or will return NET_OK.
+- ``enable()``: This function is used to enable/disable traffic over a network
+ interface. The function returns <0 if error and >=0 if no error.
+
+- ``get_flags()``: This function will return the capabilities of an L2 driver,
+ for example whether the L2 supports multicast or promiscuous mode.
Network Device drivers
**********************
@@ -68,85 +69,72 @@
- the driver_api pointer must point to a valid :c:type:`struct
net_if_api` pointer.
-- The network device driver must use ``NET_DEVICE_INIT_INSTANCE()``. This
- macro will call the DEVICE_AND_API_INIT() macro, and also
+- The network device driver must use ``NET_DEVICE_INIT_INSTANCE()``
+ or ``ETH_NET_DEVICE_INIT()`` for Ethernet devices. These
+ macros will call the ``DEVICE_AND_API_INIT()`` macro, and also
instantiate a unique :c:type:`struct net_if` related to the created
device driver instance.
Implementing a network device driver depends on the L2 stack it
-belongs to: Ethernet, IEEE 802.15.4, etc. In the next section, we will
-describe how a device driver should behave when receiving or sending a
-packet. The rest is really hardware dependent and thus does not need
-to be detailed here.
+belongs to: :ref:`Ethernet <ethernet_interface>`,
+:ref:`IEEE 802.15.4 <ieee802154_interface>`, etc.
+In the next section, we will describe how a device driver should behave when
+receiving or sending a network packet. The rest is hardware dependent
+and is not detailed here.
Ethernet device driver
======================
-On reception, it is up to the device driver to fill-in the buffer with
-as many data fragments as required. The buffer itself is a
+On reception, it is up to the device driver to fill-in the network packet with
+as many data buffers as required. The network packet itself is a
:c:type:`struct net_pkt` and should be allocated through
-:c:func:`net_pkt_get_reserve_rx(0)`. Then all fragments will be
-allocated through :c:func:`net_pkt_get_reserve_data(0)`. Of course
-the amount of required fragments depends on the size of the received
-packet and on the size of a fragment, which is given by
-:option:`CONFIG_NET_BUF_DATA_SIZE`.
+:c:func:`net_pkt_rx_alloc_with_buffer()`. Then all data buffers will be
+automatically allocated and filled by :c:func:`net_pkt_write()`.
-Note that it is not up to the device driver to decide on the
-link-layer space to be reserved in the buffer. Hence the 0 given as
-parameter here. The Ethernet L2 layer will update such information
-once the packet's Ethernet header has been successfully parsed.
+After all the network data has been received, the device driver needs to
+call :c:func:`net_recv_data()`. If that call fails, it will be up to the
+device driver to unreference the buffer via :c:func:`net_pkt_unref()`.
-In case :c:func:`net_recv_data()` call fails, it will be up to the
-device driver to unreference the buffer via
-:c:func:`net_pkt_unref()`.
-
-On sending, it is up to the device driver to send the buffer all at
-once, with all the fragments.
-
-In case of a fully successful packet transmission only, the device
-driver must unreference the buffer via :c:func:`net_pkt_unref()`.
+On sending, the device driver send function will be called, and it is up to
+the device driver to send the network packet all at once, with all the buffers.
Each Ethernet device driver will need, in the end, to call
-``NET_DEVICE_INIT_INSTANCE()`` like this:
+``ETH_NET_DEVICE_INIT()`` like this:
.. code-block:: c
- NET_DEVICE_INIT_INSTANCE(...,
- CONFIG_ETH_INIT_PRIORITY
- &the_valid_net_if_api_instance,
- ETHERNET_L2,
- NET_L2_GET_CTX_TYPE(ETHERNET_L2), 1500);
+ ETH_NET_DEVICE_INIT(..., CONFIG_ETH_INIT_PRIORITY,
+ &the_valid_net_if_api_instance, 1500);
IEEE 802.15.4 device driver
===========================
Device drivers for IEEE 802.15.4 L2 work basically the same as for
-Ethernet. What has been described above, especially for recv, applies
+Ethernet. What has been described above, especially for ``recv()``, applies
here as well. There are two specific differences however:
- It requires a dedicated device driver API: :c:type:`struct
ieee802154_radio_api`, which overloads :c:type:`struct
net_if_api`. This is because 802.15.4 L2 needs more from the device
- driver than just send and recv functions. This dedicated API is
+ driver than just ``send()`` and ``recv()`` functions. This dedicated API is
declared in :file:`include/net/ieee802154_radio.h`. Each and every IEEE
802.15.4 device driver must provide a valid pointer on such
relevantly filled-in API structure.
-- Sending a packet is slightly particular. IEEE 802.15.4 sends
+- Sending a packet is slightly different than in Ethernet. IEEE 802.15.4 sends
relatively small frames, 127 bytes all inclusive: frame header,
- payload and frame checksum. Buffer fragments are meant to fit such
+ payload and frame checksum. Buffers are meant to fit such
frame size limitation. But a buffer containing an IPv6/UDP packet
- might have more than one fragment. In the Ethernet device driver, it
- is up to the driver to handle all fragments. IEEE 802.15.4 drivers
- handle only one fragment at a time. This is why the :c:type:`struct
+ might have more than one fragment. IEEE 802.15.4 drivers
+ handle only one buffer at a time. This is why the :c:type:`struct
ieee802154_radio_api` requires a tx function pointer which differs
from the :c:type:`struct net_if_api` send function pointer.
Instead, the IEEE 802.15.4 L2, provides a generic
:c:func:`ieee802154_radio_send()` meant to be given as
:c:type:`struct net_if` send function. It turn, the implementation
of :c:func:`ieee802154_radio_send()` will ensure the same behavior:
- sending one fragment at a time through :c:type:`struct
- ieee802154_radio_api` tx function, and unreferencing the buffer
+ sending one buffer at a time through :c:type:`struct
+ ieee802154_radio_api` tx function, and unreferencing the network packet
only when all the transmission were successful.
Each IEEE 802.15.4 device driver, in the end, will need to call