Macro wlan_frame_writer::write_frame

write_frame!() { /* proc-macro */ }
Expand description

Allocates a buffer in a new fdf::Arena and writes a frame into the buffer.

This happens in three steps:

  1. Compute the frame’s length.
  2. Allocate a buffer an fdf::Arena.
  3. Write the frame into the buffer.

§Headers

Headers must derive zerocopy’s various traits and be declared as packed & C-compatible. Headers are declared through a qualified path to a type followed by an expression evaluating to a reference of the same type. For example:

headers: {
    mac::EthernetIIHdr: &mac::EthernetIIHdr {
        da: dst_addr,
        sa: src_addr,
        ether_type: llc_frame.hdr.protocol_id,
    },
},

§Body

An arbitrary body can be written to the end of the buffer’s header section. The body’s type must be a slice of a compatible type.

§IEs

§Supported IEs

  • ssid: a byte slice
  • supported_rates: a byte slice
  • dsss_param_set: wlan_common::ie::DsssParamSet
  • extended_supported_rates: a byte slice OR {} If {} is used the rates supplied in the supported_rates IE will be continued in this one if they exceed the maximum amount of allowed supported rates. Note: extended_supported_rates cannot be used without also declaring supported_rates first. extended_supported_rates may not directly follow the supported_rates IE.
  • tim: wlan_common::ie::TimView
  • ht_caps: wlan_common::ie::HtCapabilities
  • vht_caps: wlan_common::ie::VhtCapabilities
  • rsne: wlan_common::ie::rsn::rsne::Rsne
  • bss_max_idle_period: wlan_common::ie::BssMaxIdlePeriod
  • wsc: wlan_common::ie::Wsc
  • wpa1: wlan_common::ie::Wpa1

§IE values

IE values can be any expression that evaluates to the corresponding IE type. For example the following expressions are valid:

ssid: vec![4u8; 12],
ssid: SSID_CONSTANT,
ssid: b"foobar",
ssid: self.generate_ssid(),
ssid: local_var,
ssid: match x { 0 => b"foo", _ => b"bar" },
ssid: if x { b"foo" } else { b"bar" },

§Optional IEs

IEs may be optional (see examples below). Optional IEs are declared through an ? token. Value expressions in optional IEs must evaluate to a value of type Option<V> with V being a compatible value type. If the value is declared through an if-statement and NO else branch was defined, the then-branch’s value must be of type V and will automatically be wrapped with Some(_) if the condition was met. If the condition was not met, None will be used. If an else-brach was defined both branches must return an Option<V> value.

§Emit IE offset

One can emit the offset at which a particular IE is written at.

let mut offset = 0;
let buffer = write_frame!({
    ...
    ies: {
        ssid: ssid,
        supported_rates: &rates,
        offset @ extended_supported_rates: {/* continue rates */},
    },
    ...
});

§Payload

An arbitrary payload can be written to the end of the buffer. The payload’s type must be a slice of a compatible type.

§Return type

The macro returns a Result<ArenaStaticBuffer<[u8]>, Error>.

§Constraints

The macro early returns with an error if the writing to the buffer failed, thus, the caller must carry a return type of Result<(), Error>. This macro is heavily dependent on the wlan_common crates and assumes the caller to depend on those.

§Examples

let buffer = write_frame!({
    headers: {
        mac::MgmtHdr: &mac::MgmtHdr {
            frame_ctrl: mac::FrameControl(0)
                .with_frame_type(mac::FrameType::MGMT)
                .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
            duration: 0,
            addr1: mac::BCAST_ADDR,
            addr2: self.iface_mac,
            addr3: mac::BCAST_ADDR,
            seq_ctrl: mac::SequenceControl(0)
                .with_seq_num(self.ctx.seq_mgr.next_sns1(&mac::BCAST_ADDR) as u16),
        },
    },
    ies: {
        ssid: ssid,
        supported_rates: &rates,
        offset @ extended_supported_rates: {/* continue rates */},
        ht_cap?: if band_info.ht_supported {
            band_info.ht_caps.into()
        },
        vht_cap?: if band_info.vht_supported {
            band_info.vht_caps.into()
        }
    },
    payload: vec![42u8; 5],
});