| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /// Generic Network Device interface. |
| /// |
| /// The definitions herein provide the API surface to expose a hardware device as a network device |
| /// interface to the system through the FIDL protocol [`fuchsia.hardware.network/Device`]. A network |
| /// device interface is the data-plane contract that allows the networking stack to send and receive |
| /// frames on a physical or virtual network. A device exposes this capability by implementing the |
| /// `NetworkDeviceImpl` protocol, which allows a middleware implementation to bind to it and offer |
| /// the FIDL protocol to applications. |
| /// |
| /// The API contract is based on three key concepts: |
| /// - Frame Types |
| /// - Receive and Transmit buffers |
| /// - Memory layout |
| /// |
| /// Frame Types are the defined contract that is exposed to applications, which convey the data type |
| /// contained in a tx or rx buffer. The supported frame types are defined in |
| /// [`fuchsia.hardware.network/FrameType`]. Upon initialization, the middleware implementation will |
| /// fetch the supported frame types from the device through the `GetInfo` call. |
| /// |
| /// Receive and Transmit buffers are buffers that are headed to different directions: a receive |
| /// buffer is a piece of data that is received from the network, and makes its way to the |
| /// application layer. A transmit buffer travels in the opposite direction: it originates in the |
| /// application layer and makes its way out into the network. The device implementation receives |
| /// buffers from the [`NetworkDeviceIfc`], which is offered by the middleware implementation. |
| /// |
| /// A receive buffer flows from [`NetworkDeviceIfc`] into [`NetworkDeviceImpl`] through the |
| /// [`NetworkDeviceImpl.QueueRxSpace`] method, which gives access to receive buffers. The diagram |
| /// below illustrates the mechanism: |
| /// ```text |
| /// ++++++++++++++++++++++++++++ +++++++++++++++++++++++ |
| /// | (1) | => RxSpaceBuffer => | (2) | |
| /// | NetworkDeviceIfc | | NetworkDeviceImpl | |
| /// | (4) | <= RxBuffer <= | (3) | <= Network data |
| /// ++++++++++++++++++++++++++++ +++++++++++++++++++++++ |
| /// ``` |
| /// |
| /// - (1) `NetworkDeviceIfc` pushes available rx buffer space to `NetworkDeviceImpl` through |
| /// [`NetworkDeviceImpl.QueueRxSpace`]. |
| /// - (2) `NetworkDeviceImpl` retains the available space buffers until network data comes in. |
| /// - (3) `NetworkDeviceImpl` receives data from the network, stores it in one of its available |
| /// [`RxSpaceBuffers`], making it a [`NetworkDeviceImpl.RxBuffer`]. |
| /// - (4) `NetworkDeviceImpl` sends the fulfilled `RxBuffer` to `NetworkDeviceIfc` through |
| /// [`NetworkDeviceIfc.CompleteRx`], which, in turn, sends that data over to applications. |
| /// |
| /// A receive buffer flows from `NetworkDeviceIfc` into `NetworkDeviceImpl` through the |
| /// [`NetworkDeviceImpl.QueueTx`] method, and it's returned to [`NetworkDeviceIfc`] as a |
| /// [`TxResult`]. The diagram below illustrates the mechanism: |
| /// |
| /// ```text |
| /// ++++++++++++++++++++++++++++ +++++++++++++++++++++++ |
| /// | (1) | => TxBuffer => | (2) | |
| /// | NetworkDeviceIfc | | NetworkDeviceImpl | |
| /// | (4) | <= TxResult <= | (3) | => Network data |
| /// ++++++++++++++++++++++++++++ +++++++++++++++++++++++ |
| /// ``` |
| /// |
| /// - (1) `NetworkDeviceIfc` receives a transmit buffer from applications filled with data intended |
| /// to be delivered to the network. |
| /// - (2) `NetworkDeviceIfc` pushes the buffer into `NetworkDeviceImpl` through the |
| /// [`NetworkDeviceImpl.QueueTx`] call. |
| /// - (3) `NetworkDeviceImpl` sends the data contained in the buffer out into the network. |
| /// - (4) When the data is successfully transmitted, `NetworkDeviceImpl` marks the transmission as |
| /// complete referencing the buffer's identifier to [`NetworkDeviceIfc.CompleteTx`]. |
| library fuchsia.hardware.network.device; |
| |
| using zx; |
| using fuchsia.hardware.network.mac; |
| |
| /// Disables automatic snooping for the device. |
| /// |
| /// The generic NetworkDevice layer typically automatically copies all tx traffic to any snooping |
| /// clients. Devices may turn off that behavior by setting the `FEATURE_NO_AUTO_SNOOP` flag. |
| /// |
| /// Devices that disable auto-snooping SHOULD use the [`NetworkDeviceIfc.Snoop`] interface method to |
| /// expose any tx frames they receive. |
| const FEATURE_NO_AUTO_SNOOP uint32 = 0x01; |
| |
| /// Maximum number of disjoint parts a buffer may have. |
| // NOTE: the number 4 should cover the most common use case for split buffers: 1 contiguous buffer |
| // for header, 1 contiguous buffer for data, 0 or 1 contiguous buffer for trailer. Rounded up to |
| // nearest power of two. |
| const MAX_BUFFER_PARTS uint32 = 4; |
| |
| /// The maximum number of concurrent shared VMOs that may exist. |
| // NOTE: The expected number of VMOs in use is going to be between 1 and 3 with common client usage. |
| // This value is chosen to be larger than that to account for possible transitions between clients |
| // (there may be an overlap of one client shutting of a data session as one comes online) and also |
| // not limit too harshly the number of clients. |
| const MAX_VMOS uint8 = 32; |
| |
| /// The maximum number of ports a device can have at once. |
| // NOTE: Chosen arbitrarily to allow for static memory allocation for port information. Expectation |
| // is that devices are not going to have more than 4 ports in typical use cases. |
| const MAX_PORTS uint8 = 32; |
| |
| /// VMO identifier. |
| /// |
| /// VMO identifiers are always in the range [0, [`MAX_VMOS`]). |
| /// |
| /// VMO identifiers are reported to devices through [`NetworkDeviceImpl.PrepareVmo`]. |
| alias vmo_id = uint8; |
| |
| /// Buffer identifier. |
| /// |
| /// Rx space buffers and tx buffers are identified by these when exchanged between interface and |
| /// implementation. |
| alias buffer_id = uint32; |
| |
| /// Port identifier. |
| /// |
| /// Port identifiers are always in the range [0, [`MAX_PORTS`]). |
| alias port_id = uint8; |
| |
| /// A contiguous memory region in a VMO. |
| /// |
| /// Note that a `BufferRegion` is only contiguous in terms of the VMO it references, it does not |
| /// necessarily translate into contiguous physical memory. |
| type BufferRegion = struct { |
| /// VMO backing this region. |
| vmo vmo_id; |
| /// Offset, in bytes, of data chunk in VMO. |
| offset uint64; |
| /// Length, in bytes, of data chunk in VMO. |
| length uint64; |
| }; |
| |
| /// No extra frame metadata, [`FrameInfo.info_type`] must be |
| /// [`fuchsia.hardware.network/InfoType.NO_INFO`]. |
| type NoInfo = struct { |
| // TODO(brunodalbo) remove this dummy field once banjo supports it. Currently banjo uses empty |
| // structs to allow forward-declaration from FIDL. |
| nothing uint8; |
| }; |
| |
| /// Extra frame sidecar metadata stored in [`BufferMetadata`]. |
| type FrameInfo = strict union { |
| /// No extra frame metadata. |
| 1: no_info NoInfo; |
| }; |
| |
| /// Metadata associated with a [`TxBuffer`] or an [`RxBuffer`]. |
| type BufferMetadata = struct { |
| /// Destination or source port identifier for this buffer. |
| port port_id; |
| /// Extra frame metadata information. The type of the |
| /// [`FrameInfo`] union is defined by the value in `info_type`. |
| info FrameInfo; |
| /// Type of data in `info`, as defined in [`fuchsia.hardware.network/InfoType`]. |
| info_type uint32; |
| /// Frame tx or rx flags, as defined in [`fuchsia.hardware.network/RxFlags`], |
| /// [`fuchsia.hardware.network/TxFlags`], and [`fuchsia.hardware.network/TxReturnFlags`]. |
| flags uint32; |
| /// Type of frame contained in this buffer, as defined in |
| /// [`fuchsia.hardware.network/FrameType`]. |
| frame_type uint8; |
| }; |
| |
| /// A transmit buffer containing a single frame. |
| type TxBuffer = struct { |
| /// Unique buffer identifier. |
| id buffer_id; |
| /// Regions of VMO holding frame data. |
| data vector<BufferRegion>:MAX_BUFFER_PARTS; |
| /// Metadata associated with this buffer. |
| meta BufferMetadata; |
| /// Length of header bytes in the data contained in this buffer. Will always be either 0 or the |
| /// requested [`DeviceInfo.tx_head_length`] value. The head bytes are always at the beginning of |
| /// the buffer. |
| head_length uint16; |
| /// Length of tail bytes in the data contained in this buffer. Will always be either 0 or the |
| /// requested [`DeviceInfo.tx_tail_length`] value. The tail bytes are always at the end of the |
| /// buffer. |
| tail_length uint16; |
| }; |
| |
| /// A buffer with allocated space to receive frames in. An `RxSpaceBuffer` must always be returned |
| /// as an [`RxBufferPart`] within an [`RxBuffer`]. |
| type RxSpaceBuffer = struct { |
| /// Unique buffer identifier. |
| id buffer_id; |
| /// VMO region where buffer space is located. |
| region BufferRegion; |
| }; |
| |
| /// A single contiguous part of an [`RxBuffer`], created from an [`RxSpaceBuffer`]. |
| type RxBufferPart = struct { |
| /// The buffer identifier informed in the [`RxSpaceBuffer`] that originated this `RxBuffer`. |
| id buffer_id; |
| /// Offset in bytes from [`RxSpaceBuffer`]'s start where inbound data begins. |
| /// |
| /// This is a relative offset within the region defined by the originating space, not an |
| /// absolute offset in the space's VMO. |
| offset uint32; |
| /// The total length in bytes written in the [`RxSpaceBuffer`] referenced by `id`, excluding any |
| /// `offset` bytes. |
| length uint32; |
| }; |
| |
| /// A buffer containing a single frame received by the device. |
| type RxBuffer = struct { |
| /// Metadata associated with buffer. |
| meta BufferMetadata; |
| /// Fulfilled rx buffer space comprising this frame. |
| /// |
| /// Must have at least one part. |
| data vector<RxBufferPart>:MAX_BUFFER_PARTS; |
| }; |
| |
| /// The result of a tx operation, reported to [`NetworkDeviceIfc`] through |
| /// [`NetworkDeviceIfc.CompleteTx`]. |
| type TxResult = struct { |
| /// The buffer identifier informed in the [`TxBuffer`] that originated this `TxResult`. |
| id buffer_id; |
| /// The result status to report. |
| /// |
| /// Error results map to their equivalents in [`fuchsia.hardware.network/TxReturnFlags`]. |
| /// |
| /// - `ZX_OK` if the frame was sent successfully. |
| /// - `ZX_ERR_NOT_SUPPORTED` if any of the frame's flags are not supported. |
| /// - `ZX_ERR_NO_RESOURCES` if the transmit failed to allocate space in its output queue for the |
| /// frame. |
| /// - `ZX_ERR_UNAVAILABLE` if the device is offline (or went offline before getting a |
| /// confirmation that the frame was sent) or stopped. |
| /// - `ZX_ERR_INTERNAL` or any other unlisted errors will be reported as a generic |
| /// [`fuchsia.hardware.network/TxReturnFlags.TX_RET_ERROR`]. |
| status zx.status; |
| }; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-interface") |
| protocol NetworkPort { |
| /// Gets information about the port. |
| /// |
| /// Port information must not change over the port's lifetime. |
| /// |
| /// - response `info` port information. |
| GetInfo() -> (struct { |
| info PortInfo; |
| }); |
| /// Gets operational status of the port. |
| /// |
| /// Changes to operational status must be reported via [`NetworkDeviceIfc.StatusChanged`] |
| /// |
| /// - response `status` snapshot of port's operational status. |
| GetStatus() -> (struct { |
| status PortStatus; |
| }); |
| /// Notifies the port that there are sessions interested in it. |
| /// |
| /// An active port has sessions attached to it. Implementations may employ power saving or other |
| /// strategies on disabled ports. Implementations that do employ such strategies: |
| /// - should not report inbound frames for inactive ports; |
| /// - must return errors for outbound frames destined to inactive ports. |
| /// |
| /// All ports are inactive on creation. |
| /// |
| /// + request `active` `true` if port has sessions attached to it, `false` otherwise. |
| SetActive(struct { |
| active bool; |
| }); |
| /// Gets an interface to the MAC addressing layer of the port. |
| /// |
| /// Ports that do not support MAC addressing must return an empty interface. That means the |
| /// generated-banjo bindings `ctx` and `ops` fields must both be null. |
| /// |
| /// - response `mac_ifc` mac addressing handle. |
| // TODO(https://fxbug.dev/67196): Make this an optional interface return once this is FIDL. |
| GetMac() -> (resource struct { |
| mac_ifc client_end:fuchsia.hardware.network.mac.MacAddr; |
| }); |
| /// Notifies this port has been removed from the interface. |
| /// |
| /// Resources associated with the port must only be freed upon receiving the `Removed` call. |
| Removed(); |
| }; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-interface") |
| protocol NetworkDeviceIfc { |
| /// Notifies the interface of status changes on port with `id`. |
| /// |
| /// Port status changes must always be notified through `StatusChanged`. The interface will not |
| /// poll ports for status via [`NetworkPort.GetStatus`]. |
| /// |
| /// + request `id` port identifier. |
| /// + request `new_status` new port's status. |
| PortStatusChanged(struct { |
| id port_id; |
| new_status PortStatus; |
| }); |
| /// Instantiates a new port with `id`. |
| /// |
| /// `id` must not be currently in use by any other ports. `id`s may be reused once the provided |
| /// port is destroyed by [`NetworkPort.Removed`]. |
| /// |
| /// Port identifiers do not need to be stable across instantiations or reboots. Port identifiers |
| /// don't need to be allocated in any specific order as long as [`MAX_PORTS`] is not exceeded. |
| /// |
| /// + request `id` new port identifier. |
| /// + request `port` handle to network port implementation. |
| AddPort(resource struct { |
| id port_id; |
| port client_end:NetworkPort; |
| }); |
| /// Destroys port with `id`. |
| /// |
| /// NOTE: Resources associated with the port must not be freed until [`NetworkPort.Removed`] is |
| /// called. |
| /// |
| /// + request `id` removed port identifier. |
| RemovePort(struct { |
| id port_id; |
| }); |
| /// Notifies interface of incoming rx data, contained in [`RxBuffer`]. |
| /// |
| /// Callers should attempt to batch as many buffers as possible in a single call. Number of |
| /// buffers in a single call must be limited to the [`DeviceInfo.rx_depth`] reported by the |
| /// `NetworkDeviceImpl` that is returning the buffers. |
| /// |
| /// Buffers with zero length are considered "unfulfilled". They're not reported to any sessions |
| /// and the buffer space comprising them may be reused. Devices should return any outstanding |
| /// buffer space as unfulfilled on stop. See [`NetworkDeviceImpl.Stop`]. |
| /// |
| /// By calling `CompleteRx` the caller relinquishes ownership of all buffers that are being |
| /// marked as complete. |
| /// |
| /// + request `rx` buffers containing incoming data. |
| CompleteRx(struct { |
| rx vector<RxBuffer>:MAX; |
| }); |
| /// Notifies interface of complete transmit buffers. |
| /// |
| /// Callers should attempt to batch as many buffers as possible in a single call. |
| /// |
| /// Number of buffers in a single call must be limited to the [`DeviceInfo.tx_depth`] reported |
| /// by the `NetworkDeviceImpl` that is returning the buffers. |
| /// |
| /// By calling `CompleteTx` the caller relinquishes ownership of all buffers that are being |
| /// returned. |
| /// |
| /// + request `tx` transmit results. |
| CompleteTx(struct { |
| tx vector<TxResult>:MAX; |
| }); |
| /// Notifies interface of a snooped tx frame. |
| /// |
| /// Typically used by implementations that have the [`FEATURE_NO_AUTO_SNOOP`] bit set in |
| /// [`DeviceInfo.device_features`]. Implementations that generate transmit traffic internally |
| /// should use `Snoop` regardless of `FEATURE_NO_AUTO_SNOOP` being set. |
| /// |
| /// Snooped frames are *ALWAYS* outbound frames that are being fed back into the interface for |
| /// traffic snooping. Device implementations need to call [`NetworkDeviceIfc.Snoop`] ONLY if |
| /// [`NetworkDeviceImpl.SetSnoop`] was set to `true` by the interface, otherwise any buffers in |
| /// `Snoop` will be ignored. |
| /// |
| /// + request `rx` snooped transmit frames to be looped back as incoming data. |
| Snoop(struct { |
| rx vector<RxBuffer>:MAX; |
| }); |
| }; |
| |
| /// Supported tx frame types. |
| // NOTE(brunodalbo): TxSupport has exactly the same structure as |
| // `fuchsia.hardware.network.FrameTypeSupport`, but importing FIDL types into banjo is not yet |
| // supported. |
| type TxSupport = struct { |
| /// The frame type this support entry refers to. |
| type uint8; |
| /// The frame type-specific features supported. |
| features uint32; |
| /// The flags supported for the given frame type. |
| supported_flags uint32; |
| }; |
| |
| /// Static port information. |
| type PortInfo = struct { |
| /// Port class, as defined in [`fuchsia.hardware.network/PortClass`]. |
| port_class uint8; |
| /// Supported rx frame types, as defined by [`fuchsia.hardware.network/FrameType`]. |
| rx_types vector<uint8>:MAX; |
| /// Supported tx frame types. |
| tx_types vector<TxSupport>:MAX; |
| }; |
| |
| /// Static device information. |
| /// `DeviceInfo` must not change for the entire lifetime of a device. |
| type DeviceInfo = struct { |
| /// Device features |
| device_features uint32; |
| /// Maximum depth of tx frames in device's outgoing queue. |
| tx_depth uint16; |
| /// Maximum number of rx frames in a device's incoming queue. |
| rx_depth uint16; |
| /// Rx depth threshold at which the device should be fed new rx buffers. |
| /// |
| /// New buffer notifications from [`NetworkDeviceIfc`] may be skipped while the number of rx |
| /// buffers held by the implementation is larger than `rx_threshold`. It is invalid to provide a |
| /// value larger than `rx_depth`. `rx_threshold = rx_depth` is functionally equivalent to |
| /// `rx_threshold = rx_depth - 1`. |
| /// |
| /// A large value (close to `rx_depth`) may cause considerable CPU thrash for small rx |
| /// completion transaction sizes, while a small value may cause the implementation to be starved |
| /// of buffers. The typical choice of value is `rx_depth / 2`. |
| rx_threshold uint16; |
| /// Maximum virtual discontiguous buffer parts accepted by the device. |
| /// |
| /// Devices that can't perform scatter-gather operations must set `max_buffer_parts` to 1. |
| /// |
| /// Must be in the range [1, `MAX_BUFFER_PARTS`]. |
| max_buffer_parts uint8; |
| /// Maximum total length of buffers. May be set to zero for no maximum. |
| /// |
| /// Devices that do not support scatter-gather DMA may set this to a value smaller than a |
| /// page size to guarantee compatibility. |
| /// |
| /// Can't be larger than `MAX_PHYSICAL_PARTS` pages. |
| max_buffer_length uint32; |
| /// Alignment requirement for buffers relative to the start of VMOs. |
| /// |
| /// Must be greater than zero. |
| buffer_alignment uint32; |
| /// The minimum rx buffer length for correct operation, in bytes. |
| min_rx_buffer_length uint32; |
| /// The minimum tx buffer length for correct operation, in bytes. |
| /// |
| /// This length accounts only for the buffer's body, and should not account for `tx_head_length` |
| /// or `tx_tail_length`. |
| min_tx_buffer_length uint32; |
| /// Number of bytes requested as header bytes on tx buffers. |
| /// |
| /// If set to zero, tx buffers will never contain header space. Otherwise, tx buffers will start |
| /// at the beginning of the header space, and the header region will be informed. |
| tx_head_length uint16; |
| /// Number of bytes requested as tail bytes on tx buffers. |
| /// |
| /// If set to zero, tx buffers will never contain tail space. Otherwise, tx buffers will end at |
| /// the end of the tail space, and the tail region will be informed. |
| tx_tail_length uint16; |
| /// Available Rx acceleration flags for this device, as defined in |
| /// [`fuchsia.hardware.network/RxAcceleration`]. |
| /// |
| /// `rx_accel` maps the `RX_ACCEL_*` flags in the frame descriptors with semantic acceleration |
| /// features described by `RxAcceleration`. Position `n` of `rx_accel` conveys the meaning of |
| /// the `RX_ACCEL_n` flag. |
| rx_accel vector<uint8>:MAX; |
| /// Available tx acceleration flags for this device, as defined in |
| /// [`fuchsia.hardware.network/TxAcceleration`]. |
| /// |
| /// `tx_accel` maps the `TX_ACCEL_*` flags in the frame descriptors with semantic acceleration |
| /// features described by `TxAcceleration`. Position `n` of `tx_accel` conveys the meaning of |
| /// the `TX_ACCEL_n` flag. |
| tx_accel vector<uint8>:MAX; |
| }; |
| |
| /// Dynamic port information. |
| /// |
| /// `PortStatus` reflects the operational status of a port, changes to status are reported through |
| /// [`NetworkDeviceIfc.StatusChanged`]. |
| type PortStatus = struct { |
| /// Port's maximum transmission unit, in bytes. |
| mtu uint32; |
| /// Port status flags. |
| /// |
| /// Status flags, as defined in [`fuchsia.hardware.network/Status`]. |
| flags uint32; |
| }; |
| |
| @transport("Banjo") |
| @banjo_layout("ddk-protocol") |
| protocol NetworkDeviceImpl { |
| /// Initializes the network device. |
| /// |
| /// `Init` is only called once during the lifetime of the device to register `iface` as the |
| /// callback target for the Network Device implementation. |
| /// |
| /// Upon initialization, the device is expected to be in the "Stopped" state, the `Start` method |
| /// will be called once the data path needs to be opened. |
| /// |
| /// + request `iface` handle to the device interface. |
| /// - response `s` initialization status. A value other than `ZX_OK` will cause the device |
| /// to unbind. |
| Init(resource struct { |
| iface client_end:NetworkDeviceIfc; |
| }) -> (struct { |
| s zx.status; |
| }); |
| /// Starts the device's data path. |
| /// |
| /// `start` signals to the device implementation that it should bring up its data path and be |
| /// ready to receive tx frames and `iface` will start accepting rx frames. |
| /// |
| /// The device is only considered started once `Start` returns. Until then, the contract |
| /// guarantees that no other data-path calls will be made to the device (`QueueTx`, |
| /// `RxAvailable`, `Stop`), implementers can safely assume or assert that this contract is |
| /// upheld. |
| @async |
| Start() -> (); |
| /// Stops the network device. |
| /// |
| /// The device implementation must return all outstanding Tx and Rx buffers upon receiving this |
| /// call. Any new buffers received in the stopped state must be returned with an appropriate |
| /// error (tx) or unfulfilled (rx). See [`NetworkDeviceIfc.CompleteTx`] and |
| /// [`NetworkDeviceIfc.CompleteRx`] for details. |
| /// |
| /// The device implementation may perform any power saving measures after observing stop. |
| @async |
| Stop() -> (); |
| /// Gets information about the device. |
| /// |
| /// Device information must not change over the course of the lifetime of the device. |
| /// |
| /// - response `info` device information. |
| GetInfo() -> (struct { |
| info DeviceInfo; |
| }); |
| /// Enqueues a list of buffers for transmission on the network device. |
| /// |
| /// The driver takes ownership of the buffer and must complete the tx transaction by using |
| /// [`NetworkDeviceIfc.CompleteTx`] operations once it is done |
| /// with each buffer in `buffers`. |
| /// |
| /// The total number of outstanding tx buffers given to a device will never exceed the reported |
| /// [`DeviceInfo.tx_depth`] value. Which also means that no more |
| /// than `tx_depth` buffers are going to be informed at once in a single call to `QueueTx`. |
| /// |
| /// Buffers enqueued while the device in is the stopped state must be returned with an |
| /// appropriate error. See [`TxResult.status`] for specific |
| /// error codes. |
| /// |
| /// + request `buffers` tx buffers to enqueue for sending. |
| QueueTx(struct { |
| buffers vector<TxBuffer>:MAX; |
| }); |
| /// Enqueues a list of rx buffer space on the network device. |
| /// |
| /// The driver takes ownership of the buffer and must complete the transaction (once network |
| /// data arrives) using [`NetworkDeviceIfc.CompleteRx`]. |
| /// |
| /// The total number of outstanding rx buffers given to a device will never exceed the reported |
| /// [`DeviceInfo.rx_depth`] value. Which also means that no more |
| /// than `rx_depth` buffers are going to be informed at once in a single call to `QueueRxSpace`. |
| /// |
| /// Buffers enqueued while the device in is the stopped state must be returned with a zero |
| /// length. |
| /// |
| /// + request `buffers` rx space buffers to be filled with network data when it arrives. |
| QueueRxSpace(struct { |
| buffers vector<RxSpaceBuffer>:MAX; |
| }); |
| /// Informs device that a new VMO is being used to store frame data. |
| /// |
| /// Implementers must store the VMO handle referenced by `id` until |
| /// [`NetworkDeviceImpl.ReleaseVmo`] is called with the same `id`. |
| /// |
| /// + request `id` identifier used to reference this VMO. |
| /// + request `vmo` VMO where frame data will be stored. |
| PrepareVmo(resource struct { |
| id vmo_id; |
| vmo zx.handle:VMO; |
| }); |
| /// Device may dispose of all references to the VMO referenced by `id`. |
| /// |
| /// No more buffers will be sent with this `id`. |
| /// |
| /// `ReleaseVmo` is guaranteed to only be called when the implementation holds no buffers that |
| /// reference that `id`. |
| /// |
| /// + request `id` VMO identifier. |
| ReleaseVmo(struct { |
| id vmo_id; |
| }); |
| /// Informs the device that it should start or stop reporting snooped transmit frames through |
| /// [`NetworkDeviceIfc.Snoop`]. |
| /// |
| /// + request `snoop` if `true` device should start reporting snooping frames. If `false` device |
| /// should stop reporting snooped frames. Upon initialization, device assumes `snop` is `false`. |
| SetSnoop(struct { |
| snoop bool; |
| }); |
| }; |