blob: 0645fbc8cc5848671e37647f23e9c54ecc1ebaf9 [file]
***********
USB Network
***********
Role: device only. TinyUSB can present an Ethernet-style interface using
CDC-ECM, RNDIS, or CDC-NCM. The application connects Ethernet frames to a
network stack such as lwIP.
Choose one driver
=================
``CFG_TUD_ECM_RNDIS`` and ``CFG_TUD_NCM`` are mutually exclusive.
* The ECM/RNDIS driver can expose separate configurations so Windows selects
RNDIS and macOS selects ECM; Linux can use either.
* NCM aggregates Ethernet datagrams into Network Transfer Blocks and is the
preferred starting point for current, higher-throughput designs. Windows
binding may require the Microsoft OS 2.0 descriptors shown by the example.
Use the matching descriptor macro: ``TUD_CDC_ECM_DESCRIPTOR``,
``TUD_RNDIS_DESCRIPTOR``, or ``TUD_CDC_NCM_DESCRIPTOR``. Provide a unique
48-bit ``tud_network_mac_address`` and return the same address as a 12-digit
hexadecimal USB string descriptor where the class descriptor references it.
The host uses this address for its end of the link, so give the device's own
network stack a different MAC; the example toggles its least significant bit.
Configuration options
=====================
.. list-table::
:header-rows: 1
:widths: 42 16 42
* - Option
- Default
- What it controls
* - ``CFG_TUD_ECM_RNDIS`` / ``CFG_TUD_NCM``
- ``0``
- Selects one network class implementation. Enabling both is a build
error.
* - ``CFG_TUD_NET_MTU``
- ``1514`` bytes
- Maximum Ethernet frame including its 14-byte Ethernet header.
* - ``CFG_TUD_NCM_OUT_NTB_MAX_SIZE``
- ``3200`` bytes
- Largest host-to-device NTB received. At least 2048 bytes (see
`NCM sizing`_).
* - ``CFG_TUD_NCM_IN_NTB_MAX_SIZE``
- ``3200`` bytes
- Largest device-to-host NTB assembled for transmission. At least 2048
bytes (see `NCM sizing`_).
* - ``CFG_TUD_NCM_OUT_NTB_N`` / ``CFG_TUD_NCM_IN_NTB_N``
- ``1`` each
- Number of receive/transmit NTB buffers. Increasing these can reduce
stalls at a proportional RAM cost; benchmark before changing them.
* - ``CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB``
- ``8``
- Maximum Ethernet frames TinyUSB aggregates into a transmit NTB.
* - ``CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB``
- ``6``
- Maximum frames the device tells the host to place in one receive NTB.
* - ``CFG_TUD_NCM_DEFAULT_LINK_UP``
- Undefined (link up)
- Initial NCM link state returned by the default
``tud_network_default_link_state_cb()``.
Frame flow
==========
For host-to-device frames, TinyUSB calls
``tud_network_recv_cb(src, size)``. Return ``true`` once the frame is accepted,
then call ``tud_network_recv_renew()`` to receive the next one. ECM/RNDIS keeps
``src`` valid until that call, but NCM may reuse the storage as soon as the
callback returns, so copy the frame inside the callback. On ``false``,
ECM/RNDIS drops the frame and renews reception itself; NCM keeps the frame and
offers it again on the next ``tud_network_recv_renew()``, which the application
must call.
For device-to-host frames:
1. Call ``tud_network_can_xmit(size)``.
2. If it returns true, call ``tud_network_xmit(ref, arg)`` once.
3. TinyUSB calls ``tud_network_xmit_cb(dst, ref, arg)``; copy the complete
Ethernet frame into ``dst`` and return its length.
The drivers do not lock their state: call ``tud_network_recv_renew()``,
``tud_network_can_xmit()`` and ``tud_network_xmit()`` from the task that runs
``tud_task()``.
Use ``tud_network_link_state()`` to notify the host when the logical or physical
link changes. A mounted USB device is not necessarily a link-up network
interface.
.. list-table::
:header-rows: 1
:widths: 40 60
* - API or callback
- What it does
* - ``tud_network_recv_cb()``
- Offers one received Ethernet frame. Return ``true`` once it is
accepted; see above for how long ``src`` stays valid.
* - ``tud_network_recv_renew()``
- Lets the driver deliver the next frame (re-arms reception, or offers the
next NCM datagram).
* - ``tud_network_can_xmit()`` / ``tud_network_xmit()``
- Checks whether one frame of ``size`` bytes can be queued now, then
queues it. Call ``xmit`` once after each successful check.
* - ``tud_network_xmit_cb()``
- Copies the complete frame into TinyUSB's destination and returns its
actual byte length.
* - ``tud_network_init_cb()``
- Not called by either driver.
* - ``tud_network_set_packet_filter_cb()``
- Reports ECM and NCM host filter bits so the application can adjust
multicast or promiscuous delivery.
* - ``tud_network_default_link_state_cb()`` /
``tud_network_link_state()``
- Supplies the initial NCM link state and later sends link up/down changes
to the host (ECM and NCM only; ignored in RNDIS mode).
NCM sizing
==========
Keep ``CFG_TUD_NCM_IN_NTB_MAX_SIZE`` and ``CFG_TUD_NCM_OUT_NTB_MAX_SIZE`` at
2048 bytes or more: the class requires the host to select an IN NTB size of at
least 2048 bytes and no more than the device's maximum, and Linux expects an OUT
NTB size of at least 2048 bytes. NCM buffer sizes have a direct RAM/throughput
tradeoff. Begin with one IN and one OUT NTB, then measure before increasing
the NTB sizes or their ``*_NTB_N`` counts. Keep descriptor capabilities and
runtime responses consistent with the enabled NCM features.
The :doc:`../../examples/device/net_lwip_webserver` example includes NCM and
ECM/RNDIS descriptor sets, lwIP integration, DHCP, DNS, link-state changes, and
host setup notes.
Specifications used: *CDC Ethernet Control Model*, Revision 1.2, and *CDC
Network Control Model*, Revision 1.0 (Errata 1). RNDIS is a vendor protocol,
not a USB-IF CDC subclass.